[gccrs COMMIT] gccrs: Implement some platform-intrinsic simd function support
gerris.rs@gmail.com
gerris.rs@gmail.com
Mon Sep 14 16:46:15 GMT 2026
From: Yap Zhi Heng <yapzhhg@gmail.com>
Generated 007t.gimple code from compiling platform_intrinsics.rs:
_1 = x == y;
_eq = VEC_COND_EXPR <_1, { -1, -1 }, { 0, 0 }>;
_2 = x != y;
_ne = VEC_COND_EXPR <_2, { -1, -1 }, { 0, 0 }>;
_3 = x < y;
_lt = VEC_COND_EXPR <_3, { -1, -1 }, { 0, 0 }>;
_4 = x <= y;
_le = VEC_COND_EXPR <_4, { -1, -1 }, { 0, 0 }>;
_5 = x > y;
_gt = VEC_COND_EXPR <_5, { -1, -1 }, { 0, 0 }>;
_6 = x >= y;
_ge = VEC_COND_EXPR <_6, { -1, -1 }, { 0, 0 }>;
_add = x + y;
_sub = x - y;
_mul = x * y;
_div = x / y;
_shl = x << y;
_shr = x >> y;
_and = x & y;
_or = x | y;
_xor = x ^ y;
gcc/rust/ChangeLog:
* Make-lang.in: Compile the new rust-compile-platform-intrinsic files.
* backend/rust-compile-base.cc (HIRCompileBase::setup_abi_options): Make the
PLATFORM_INTRINSIC case use the `cdecl` ABI.
* backend/rust-compile-platform-intrinsic.cc: New file to handle compilation of
'platform-intrinsic' extern functions.
* backend/rust-compile-platform-intrinsic.h: Header file for the formentioned file.
* backend/rust-compile-expr.cc (CompileExpr::visit (HIR::CallExpr)): Add new
conditions to compile platform-intrinsic extern functions.
* typecheck/rust-hir-type-check-base.cc (TypeCheckBase::resolve_generic_params):
Check 'platform-intrinsic' extern functions for const parameters.
* typecheck/rust-hir-type-check-expr.cc (TypeCheckExpr::visit (HIR::TupleIndexExpr)):
Fix resolved tuple expression not destructuring.
Signed-off-by: Yap Zhi Heng <yapzhhg@gmail.com>
---
This change was merged into the gccrs repository and is posted here for
upstream visibility and potential drive-by review, as requested by GCC
release managers.
Each commit email contains a link to its details on github from where you can
find the Pull-Request and associated discussions.
Commit on github: https://github.com/Rust-GCC/gccrs/commit/92f85fbebd72e5e1dac0ea9ceea8f4ef3dac6584
The commit has NOT been mentioned in any issue.
The commit has been mentioned in the following pull-request(s):
- https://github.com/Rust-GCC/gccrs/pull/4891
gcc/rust/Make-lang.in | 1 +
gcc/rust/backend/rust-compile-base.cc | 1 +
gcc/rust/backend/rust-compile-expr.cc | 25 ++++
.../rust-compile-platform-intrinsic.cc | 117 ++++++++++++++++++
.../backend/rust-compile-platform-intrinsic.h | 51 ++++++++
.../typecheck/rust-hir-type-check-base.cc | 6 +-
.../typecheck/rust-hir-type-check-expr.cc | 3 +-
.../rust/compile/platform_intrinsics.rs | 117 ++++++++++++++++++
8 files changed, 318 insertions(+), 3 deletions(-)
create mode 100644 gcc/rust/backend/rust-compile-platform-intrinsic.cc
create mode 100644 gcc/rust/backend/rust-compile-platform-intrinsic.h
create mode 100644 gcc/testsuite/rust/compile/platform_intrinsics.rs
diff --git a/gcc/rust/Make-lang.in b/gcc/rust/Make-lang.in
index e4e570452..552de0153 100644
--- a/gcc/rust/Make-lang.in
+++ b/gcc/rust/Make-lang.in
@@ -229,6 +229,7 @@ GRS_OBJS = \
rust/rust-compile-type.o \
rust/rust-compile-block.o \
rust/rust-compile-struct-field-expr.o \
+ rust/rust-compile-platform-intrinsic.o \
rust/rust-constexpr.o \
rust/rust-compile-base.o \
rust/rust-compile-drop-builder.o \
diff --git a/gcc/rust/backend/rust-compile-base.cc b/gcc/rust/backend/rust-compile-base.cc
index d4161a96f..65ec002fc 100644
--- a/gcc/rust/backend/rust-compile-base.cc
+++ b/gcc/rust/backend/rust-compile-base.cc
@@ -509,6 +509,7 @@ HIRCompileBase::setup_abi_options (tree fndecl, ABI abi)
{
case Rust::ABI::RUST:
case Rust::ABI::INTRINSIC:
+ case Rust::ABI::PLATFORM_INTRINSIC:
case Rust::ABI::C:
case Rust::ABI::CDECL:
// `decl_attributes` function (not the macro) has the side-effect of
diff --git a/gcc/rust/backend/rust-compile-expr.cc b/gcc/rust/backend/rust-compile-expr.cc
index 6480e946b..815f53cb0 100644
--- a/gcc/rust/backend/rust-compile-expr.cc
+++ b/gcc/rust/backend/rust-compile-expr.cc
@@ -28,6 +28,7 @@
#include "rust-compile-block.h"
#include "rust-compile-drop.h"
#include "rust-compile-implitem.h"
+#include "rust-compile-platform-intrinsic.h"
#include "rust-constexpr.h"
#include "rust-compile-type.h"
#include "rust-finalized-name-resolution-context.h"
@@ -1696,6 +1697,23 @@ CompileExpr::visit (HIR::CallExpr &expr)
return true;
};
+ // special check for platform-intrinsic functions
+ TyTy::FnType *platform_intrinsic = nullptr;
+ if (tyty->get_kind () == TyTy::TypeKind::FNDEF)
+ {
+ auto *fn_ty = static_cast<TyTy::FnType *> (tyty);
+ if (fn_ty->get_abi () == ABI::PLATFORM_INTRINSIC)
+ platform_intrinsic = fn_ty;
+ }
+
+ if (ctx->const_context_p () && platform_intrinsic != nullptr)
+ {
+ rust_sorry_at (
+ expr.get_locus (),
+ "platform intrinsic calls in consts are not supported yet");
+ return;
+ }
+
auto fn_address = CompileExpr::Compile (expr.get_fnexpr (), ctx);
if (ctx->const_context_p ())
{
@@ -1776,6 +1794,13 @@ CompileExpr::visit (HIR::CallExpr &expr)
args.push_back (rvalue);
}
+ if (platform_intrinsic != nullptr)
+ {
+ translated = PlatformIntrinsic::compile_call (ctx, platform_intrinsic,
+ args, expr.get_locus ());
+ return;
+ }
+
// must be a regular call to a function
translated
= Backend::call_expression (fn_address, args, nullptr, expr.get_locus ());
diff --git a/gcc/rust/backend/rust-compile-platform-intrinsic.cc b/gcc/rust/backend/rust-compile-platform-intrinsic.cc
new file mode 100644
index 000000000..3580143de
--- /dev/null
+++ b/gcc/rust/backend/rust-compile-platform-intrinsic.cc
@@ -0,0 +1,117 @@
+// Copyright (C) 2026 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "rust-system.h"
+#include "rust-compile-context.h"
+#include "rust-compile-type.h"
+#include "rust-tyty.h"
+#include "rust-abi.h"
+#include "rust-tree.h"
+#include "tree.h"
+#include "fold-const.h"
+#include "rust-compile-platform-intrinsic.h"
+
+namespace Rust {
+namespace Compile {
+
+const std::map<std::string, PlatformIntrinsic::PlatformIntrinsicMapping>
+ PlatformIntrinsic::platform_intrinsics = {
+ {"simd_add", {OpKind::BINARY, PLUS_EXPR}},
+ {"simd_sub", {OpKind::BINARY, MINUS_EXPR}},
+ {"simd_mul", {OpKind::BINARY, MULT_EXPR}},
+ {"simd_div",
+ {OpKind::BINARY,
+ TRUNC_DIV_EXPR}}, // uses RDIV_EXPR if operands are real type
+ {"simd_shl", {OpKind::BINARY, LSHIFT_EXPR}},
+ {"simd_shr", {OpKind::BINARY, RSHIFT_EXPR}},
+ {"simd_and", {OpKind::BINARY, BIT_AND_EXPR}},
+ {"simd_or", {OpKind::BINARY, BIT_IOR_EXPR}},
+ {"simd_xor", {OpKind::BINARY, BIT_XOR_EXPR}},
+ {"simd_eq", {OpKind::COMPARISON, EQ_EXPR}},
+ {"simd_ne", {OpKind::COMPARISON, NE_EXPR}},
+ {"simd_lt", {OpKind::COMPARISON, LT_EXPR}},
+ {"simd_le", {OpKind::COMPARISON, LE_EXPR}},
+ {"simd_gt", {OpKind::COMPARISON, GT_EXPR}},
+ {"simd_ge", {OpKind::COMPARISON, GE_EXPR}},
+};
+
+tree
+compile_comparison_op (const TyTy::FnType *fntype,
+ const std::vector<tree> &arguments, location_t locus,
+ const tree &result_type, const tree_code op_code)
+{
+ tree input_type = TREE_TYPE (arguments[0]);
+ tree predicate_type = truth_type_for (input_type);
+
+ tree predicate = fold_build2_loc (locus, op_code, predicate_type,
+ arguments[0], arguments[1]);
+ return fold_build3_loc (locus, VEC_COND_EXPR, result_type, predicate,
+ build_minus_one_cst (result_type),
+ build_zero_cst (result_type));
+}
+
+tree
+compile_binary_op (const TyTy::FnType *fntype,
+ const std::vector<tree> &arguments, location_t locus,
+ const tree &result_type, const tree_code op_code)
+{
+ tree_code final_op_code = op_code;
+
+ // idk any more elegant way to do this
+ if (final_op_code == TRUNC_DIV_EXPR
+ && TREE_CODE (TREE_TYPE (result_type)) == REAL_TYPE)
+ final_op_code = RDIV_EXPR;
+
+ return fold_build2_loc (locus, final_op_code, result_type, arguments[0],
+ arguments[1]);
+}
+
+tree
+PlatformIntrinsic::compile_call (Context *ctx, TyTy::FnType *fntype,
+ const std::vector<tree> &arguments,
+ location_t locus)
+{
+ rust_assert (fntype != nullptr);
+ rust_assert (fntype->get_abi () == ABI::PLATFORM_INTRINSIC);
+ auto *result_ty = fntype->get_return_type ()->destructure ();
+ tree result_type = TyTyResolveCompile::compile (ctx, result_ty);
+
+ auto it = platform_intrinsics.find (fntype->get_identifier ());
+ if (it == platform_intrinsics.end ())
+ {
+ // TODO add an error here
+ return error_mark_node;
+ }
+
+ const auto &mapping = it->second;
+
+ switch (mapping.kind)
+ {
+ case OpKind::BINARY:
+ return compile_binary_op (fntype, arguments, locus, result_type,
+ mapping.code);
+ case OpKind::COMPARISON:
+ return compile_comparison_op (fntype, arguments, locus, result_type,
+ mapping.code);
+ default:
+ return error_mark_node;
+ }
+}
+
+} // namespace Compile
+} // namespace Rust
diff --git a/gcc/rust/backend/rust-compile-platform-intrinsic.h b/gcc/rust/backend/rust-compile-platform-intrinsic.h
new file mode 100644
index 000000000..c568a627e
--- /dev/null
+++ b/gcc/rust/backend/rust-compile-platform-intrinsic.h
@@ -0,0 +1,51 @@
+// Copyright (C) 2026 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef RUST_COMPILE_PLATFORM_INTRINSIC_H
+#define RUST_COMPILE_PLATFORM_INTRINSIC_H
+
+namespace Rust {
+namespace Compile {
+
+class PlatformIntrinsic
+{
+public:
+ static tree compile_call (Context *ctx, TyTy::FnType *fntype,
+ const std::vector<tree> &arguments,
+ location_t locus);
+
+private:
+ enum class OpKind
+ {
+ BINARY,
+ COMPARISON,
+ };
+
+ struct PlatformIntrinsicMapping
+ {
+ OpKind kind;
+ tree_code code;
+ };
+ static const std::map<std::string, PlatformIntrinsicMapping>
+ platform_intrinsics;
+};
+
+} // namespace Compile
+} // namespace Rust
+
+#endif // RUST_COMPILE_PLATFORM_INTRINSIC_H
diff --git a/gcc/rust/typecheck/rust-hir-type-check-base.cc b/gcc/rust/typecheck/rust-hir-type-check-base.cc
index faa6d5ea9..c9e392039 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-base.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-base.cc
@@ -669,7 +669,8 @@ TypeCheckBase::resolve_generic_params (
case HIR::GenericParam::GenericKind::CONST:
{
- if (is_foreign && abi != Rust::ABI::INTRINSIC)
+ if (is_foreign && abi != Rust::ABI::INTRINSIC
+ && abi != Rust::ABI::PLATFORM_INTRINSIC)
{
rust_error_at (generic_param->get_locus (), ErrorCode::E0044,
"foreign items may not have const parameters");
@@ -747,7 +748,8 @@ TypeCheckBase::resolve_generic_params (
case HIR::GenericParam::GenericKind::TYPE:
{
- if (is_foreign && abi != Rust::ABI::INTRINSIC)
+ if (is_foreign && abi != Rust::ABI::INTRINSIC
+ && abi != Rust::ABI::PLATFORM_INTRINSIC)
{
rust_error_at (generic_param->get_locus (), ErrorCode::E0044,
"foreign items may not have type parameters");
diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.cc b/gcc/rust/typecheck/rust-hir-type-check-expr.cc
index fdc17fe44..b2e10c622 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-expr.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-expr.cc
@@ -86,7 +86,8 @@ TypeCheckExpr::ResolveOpOverload (LangItem::Kind lang_item_type,
void
TypeCheckExpr::visit (HIR::TupleIndexExpr &expr)
{
- auto resolved = TypeCheckExpr::Resolve (expr.get_tuple_expr ());
+ auto resolved
+ = TypeCheckExpr::Resolve (expr.get_tuple_expr ())->destructure ();
if (resolved->get_kind () == TyTy::TypeKind::ERROR)
{
rust_error_at (expr.get_tuple_expr ().get_locus (),
diff --git a/gcc/testsuite/rust/compile/platform_intrinsics.rs b/gcc/testsuite/rust/compile/platform_intrinsics.rs
new file mode 100644
index 000000000..c93df7c4a
--- /dev/null
+++ b/gcc/testsuite/rust/compile/platform_intrinsics.rs
@@ -0,0 +1,117 @@
+// { dg-do compile { target { { i?86-*-* x86_64-*-* } && ia32 } } }
+// { dg-options "-mrdrnd -mrdseed -fdump-tree-gimple" }
+#![feature(no_core, abi_unadjusted, repr_simd, lang_items)]
+#![no_core]
+
+#[lang = "sized"]
+pub trait Sized {}
+
+#[repr(simd)]
+pub struct __m128i(i64, i64);
+
+extern "platform-intrinsic" {
+ //pub fn simd_select_bitmask
+ pub fn simd_eq<T, U>(x: T, y: T) -> U;
+ pub fn simd_ne<T, U>(x: T, y: T) -> U;
+ pub fn simd_lt<T, U>(x: T, y: T) -> U;
+ pub fn simd_le<T, U>(x: T, y: T) -> U;
+ pub fn simd_gt<T, U>(x: T, y: T) -> U;
+ pub fn simd_ge<T, U>(x: T, y: T) -> U;
+
+ // #[rustc_args_required_const(2)]
+ // pub fn simd_shuffle2<T, U>(x: T, y: T, idx: [u32; 2]) -> U;
+ // #[rustc_args_required_const(2)]
+ // pub fn simd_shuffle4<T, U>(x: T, y: T, idx: [u32; 4]) -> U;
+ // #[rustc_args_required_const(2)]
+ // pub fn simd_shuffle8<T, U>(x: T, y: T, idx: [u32; 8]) -> U;
+ // #[rustc_args_required_const(2)]
+ // pub fn simd_shuffle16<T, U>(x: T, y: T, idx: [u32; 16]) -> U;
+ // #[rustc_args_required_const(2)]
+ // pub fn simd_shuffle32<T, U>(x: T, y: T, idx: [u32; 32]) -> U;
+ // #[rustc_args_required_const(2)]
+ // pub fn simd_shuffle64<T, U>(x: T, y: T, idx: [u32; 64]) -> U;
+ // #[rustc_args_required_const(2)]
+ // pub fn simd_shuffle128<T, U>(x: T, y: T, idx: [u32; 128]) -> U;
+
+ // #[rustc_const_unstable(feature = "const_simd_insert", issue = "none")]
+ // pub fn simd_insert<T, U>(x: T, idx: u32, val: U) -> T;
+ // #[rustc_const_unstable(feature = "const_simd_extract", issue = "none")]
+ // pub fn simd_extract<T, U>(x: T, idx: u32) -> U;
+ // //pub fn simd_select
+ // pub fn simd_bitmask<T, U>(x: T) -> U;
+
+ // pub fn simd_cast<T, U>(x: T) -> U;
+
+ pub fn simd_add<T>(x: T, y: T) -> T;
+ pub fn simd_sub<T>(x: T, y: T) -> T;
+ pub fn simd_mul<T>(x: T, y: T) -> T;
+ pub fn simd_div<T>(x: T, y: T) -> T;
+ pub fn simd_shl<T>(x: T, y: T) -> T;
+ pub fn simd_shr<T>(x: T, y: T) -> T;
+ pub fn simd_and<T>(x: T, y: T) -> T;
+ pub fn simd_or<T>(x: T, y: T) -> T;
+ pub fn simd_xor<T>(x: T, y: T) -> T;
+
+ // pub fn simd_saturating_add<T>(x: T, y: T) -> T;
+ // pub fn simd_saturating_sub<T>(x: T, y: T) -> T;
+
+ // pub fn simd_gather<T, U, V>(values: T, pointers: U, mask: V) -> T;
+ // pub fn simd_scatter<T, U, V>(values: T, pointers: U, mask: V);
+
+ // pub fn simd_reduce_add_unordered<T, U>(x: T) -> U;
+ // pub fn simd_reduce_mul_unordered<T, U>(x: T) -> U;
+ // pub fn simd_reduce_add_ordered<T, U>(x: T, acc: U) -> U;
+ // pub fn simd_reduce_mul_ordered<T, U>(x: T, acc: U) -> U;
+ // pub fn simd_reduce_min<T, U>(x: T) -> U;
+ // pub fn simd_reduce_max<T, U>(x: T) -> U;
+ // pub fn simd_reduce_min_nanless<T, U>(x: T) -> U;
+ // pub fn simd_reduce_max_nanless<T, U>(x: T) -> U;
+ // pub fn simd_reduce_and<T, U>(x: T) -> U;
+ // pub fn simd_reduce_or<T, U>(x: T) -> U;
+ // pub fn simd_reduce_xor<T, U>(x: T) -> U;
+ // pub fn simd_reduce_all<T>(x: T) -> bool;
+ // pub fn simd_reduce_any<T>(x: T) -> bool;
+
+ // pub fn simd_select<M, T>(m: M, a: T, b: T) -> T;
+ // pub fn simd_select_bitmask<M, T>(m: M, a: T, b: T) -> T;
+
+ // pub fn simd_fmin<T>(a: T, b: T) -> T;
+ // pub fn simd_fmax<T>(a: T, b: T) -> T;
+
+ // pub fn simd_fsqrt<T>(a: T) -> T;
+ // pub fn simd_fsin<T>(a: T) -> T;
+ // pub fn simd_fcos<T>(a: T) -> T;
+ // pub fn simd_fabs<T>(a: T) -> T;
+ // pub fn simd_floor<T>(a: T) -> T;
+ // pub fn simd_ceil<T>(a: T) -> T;
+ // pub fn simd_fexp<T>(a: T) -> T;
+ // pub fn simd_fexp2<T>(a: T) -> T;
+ // pub fn simd_flog10<T>(a: T) -> T;
+ // pub fn simd_flog2<T>(a: T) -> T;
+ // pub fn simd_flog<T>(a: T) -> T;
+ // //pub fn simd_fpowi
+ // //pub fn simd_fpow
+ // pub fn simd_fma<T>(a: T, b: T, c: T) -> T;
+}
+
+fn main(){
+ let x: __m128i = __m128i(0, 2);
+ let y: __m128i = __m128i(2, 2);
+ unsafe {
+ let _eq = simd_eq::<__m128i, __m128i>(x, y);
+ let _ne = simd_ne::<__m128i, __m128i>(x, y);
+ let _lt = simd_lt::<__m128i, __m128i>(x, y);
+ let _le = simd_le::<__m128i, __m128i>(x, y);
+ let _gt = simd_gt::<__m128i, __m128i>(x, y);
+ let _ge = simd_ge::<__m128i, __m128i>(x, y);
+ let _add = simd_add(x, y);
+ let _sub = simd_sub(x, y);
+ let _mul = simd_mul(x, y);
+ let _div = simd_div(x, y);
+ let _shl = simd_shl(x, y);
+ let _shr = simd_shr(x, y);
+ let _and = simd_and(x, y);
+ let _or = simd_or(x, y);
+ let _xor = simd_xor(x, y);
+ };
+}
base-commit: a107b3c08762eda82ad6f1ffdf595ff4b01c3152
--
2.55.0
More information about the Gcc-rust
mailing list