[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