https://gcc.gnu.org/g:fffe5e21229c9cefc072f911ae7aa1e12fe001c1
commit r17-4360-gfffe5e21229c9cefc072f911ae7aa1e12fe001c1 Author: Yap Zhi Heng <[email protected]> Date: Mon Sep 14 20:17:50 2026 +0800 gccrs: Implement some platform-intrinsic simd function support 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 <[email protected]> Diff: --- gcc/rust/Make-lang.in | 1 + gcc/rust/backend/rust-compile-base.cc | 1 + gcc/rust/backend/rust-compile-expr.cc | 25 +++++ .../backend/rust-compile-platform-intrinsic.cc | 117 +++++++++++++++++++++ gcc/rust/backend/rust-compile-platform-intrinsic.h | 51 +++++++++ gcc/rust/typecheck/rust-hir-type-check-base.cc | 6 +- gcc/rust/typecheck/rust-hir-type-check-expr.cc | 3 +- gcc/testsuite/rust/compile/platform_intrinsics.rs | 117 +++++++++++++++++++++ 8 files changed, 318 insertions(+), 3 deletions(-) diff --git a/gcc/rust/Make-lang.in b/gcc/rust/Make-lang.in index e4e5704528cf..552de0153d66 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 d4161a96f1f2..65ec002fca46 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 6480e946b155..815f53cb0878 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 000000000000..3580143de355 --- /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 000000000000..c568a627e8dd --- /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 faa6d5ea98ee..c9e392039a3c 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 fdc17fe44e25..b2e10c6225bd 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 000000000000..c93df7c4a20b --- /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); + }; +}
