https://gcc.gnu.org/g:ae66d06710d3cb9eaebdf36c717456f8f85687d8
commit r17-5442-gae66d06710d3cb9eaebdf36c717456f8f85687d8 Author: Arthur Cohen <[email protected]> Date: Mon Sep 28 20:04:52 2026 +0200 gccrs: intrinsics: Add impl for fadd_fast, fsub_fast, fmul_fast, fdiv_fast and frem_fast Add an implementation for the aforementioned intrinsics. Note that this is a simple implementation and does not actually implement fast mode for these operations, but instead simply performs the operation. As far as I can tell, it is not possible to turn on fast mode in GCC for just one operation instead of the whole program. gcc/rust/ChangeLog: * backend/rust-compile-intrinsic.cc: Reformat the table and add entries for f<op>_fast intrinsics. * backend/rust-intrinsic-handlers.cc (fop_fast): New handler for f<op>_fast intrinsics. * backend/rust-intrinsic-handlers.h (fop_fast): New declaration. * typecheck/rust-hir-type-check-intrinsic.cc: Add typecheck info for f<op>_fast intrinsics. * util/rust-intrinsic-values.h: New intrinsics. gcc/testsuite/ChangeLog: * rust/compile/fop_fast_intrinsics.rs: New test. Diff: --- gcc/rust/backend/rust-compile-intrinsic.cc | 120 +++++++++++---------- gcc/rust/backend/rust-intrinsic-handlers.cc | 56 ++++++++++ gcc/rust/backend/rust-intrinsic-handlers.h | 5 + .../typecheck/rust-hir-type-check-intrinsic.cc | 14 +++ gcc/rust/util/rust-intrinsic-values.h | 6 ++ gcc/testsuite/rust/compile/fop_fast_intrinsics.rs | 27 +++++ 6 files changed, 173 insertions(+), 55 deletions(-) diff --git a/gcc/rust/backend/rust-compile-intrinsic.cc b/gcc/rust/backend/rust-compile-intrinsic.cc index 872b53e701a8..c16db442f3cc 100644 --- a/gcc/rust/backend/rust-compile-intrinsic.cc +++ b/gcc/rust/backend/rust-compile-intrinsic.cc @@ -28,61 +28,71 @@ namespace Compile { using IValue = Values::Intrinsics; static const std::map<std::string, handlers::HandlerBuilder> generic_intrinsics - = {{IValue::OFFSET, handlers::offset}, - {IValue::ARITH_OFFSET, handlers::arith_offset_handler}, - {IValue::WRITE_BYTES, handlers::write_bytes_handler}, - {IValue::ASSERT_ZERO_VALID, handlers::assert_zero_valid_handler}, - {IValue::SIZE_OF, handlers::sizeof_handler}, - {IValue::SIZE_OF_VAL, handlers::size_of_val_handler}, - {IValue::MIN_ALIGN_OF, handlers::min_align_of_handler}, - {IValue::MIN_ALIGN_OF_VAL, handlers::min_align_of_val_handler}, - {IValue::TRANSMUTE, handlers::transmute}, - {IValue::ROTATE_LEFT, handlers::rotate_left}, - {IValue::ROTATE_RIGHT, handlers::rotate_right}, - {IValue::WRAPPING_ADD, handlers::wrapping_op (PLUS_EXPR)}, - {IValue::WRAPPING_SUB, handlers::wrapping_op (MINUS_EXPR)}, - {IValue::WRAPPING_MUL, handlers::wrapping_op (MULT_EXPR)}, - {IValue::ADD_WITH_OVERFLOW, handlers::op_with_overflow (PLUS_EXPR)}, - {IValue::SUB_WITH_OVERFLOW, handlers::op_with_overflow (MINUS_EXPR)}, - {IValue::MUL_WITH_OVERFLOW, handlers::op_with_overflow (MULT_EXPR)}, - {IValue::COPY, handlers::copy (true)}, - {IValue::COPY_NONOVERLAPPING, handlers::copy (false)}, - {IValue::PREFETCH_READ_DATA, handlers::prefetch_read_data}, - {IValue::PREFETCH_WRITE_DATA, handlers::prefetch_write_data}, - {IValue::ATOMIC_STORE, handlers::atomic_store (__ATOMIC_SEQ_CST)}, - {IValue::ATOMIC_STORE_SEQCST, handlers::atomic_store (__ATOMIC_SEQ_CST)}, - {IValue::ATOMIC_STORE_REL, handlers::atomic_store (__ATOMIC_RELEASE)}, - {IValue::ATOMIC_STORE_RELEASE, handlers::atomic_store (__ATOMIC_RELEASE)}, - {IValue::ATOMIC_STORE_RELAXED, handlers::atomic_store (__ATOMIC_RELAXED)}, - {IValue::ATOMIC_STORE_UNORDERED, - handlers::atomic_store (__ATOMIC_RELAXED)}, - {IValue::ATOMIC_LOAD, handlers::atomic_load (__ATOMIC_SEQ_CST)}, - {IValue::ATOMIC_LOAD_SEQCST, handlers::atomic_load (__ATOMIC_SEQ_CST)}, - {IValue::ATOMIC_LOAD_ACQ, handlers::atomic_load (__ATOMIC_ACQUIRE)}, - {IValue::ATOMIC_LOAD_ACQUIRE, handlers::atomic_load (__ATOMIC_ACQUIRE)}, - {IValue::ATOMIC_LOAD_RELAXED, handlers::atomic_load (__ATOMIC_RELAXED)}, - {IValue::ATOMIC_LOAD_UNORDERED, handlers::atomic_load (__ATOMIC_RELAXED)}, - {IValue::UNCHECKED_ADD, handlers::unchecked_op (PLUS_EXPR)}, - {IValue::UNCHECKED_SUB, handlers::unchecked_op (MINUS_EXPR)}, - {IValue::UNCHECKED_MUL, handlers::unchecked_op (MULT_EXPR)}, - {IValue::UNCHECKED_DIV, handlers::unchecked_op (TRUNC_DIV_EXPR)}, - {IValue::UNCHECKED_REM, handlers::unchecked_op (TRUNC_MOD_EXPR)}, - {IValue::UNCHECKED_SHL, handlers::unchecked_op (LSHIFT_EXPR)}, - {IValue::UNCHECKED_SHR, handlers::unchecked_op (RSHIFT_EXPR)}, - {IValue::UNINIT, handlers::uninit}, - {IValue::MOVE_VAL_INIT, handlers::move_val_init}, - {IValue::LIKELY, handlers::expect (true)}, - {IValue::UNLIKELY, handlers::expect (false)}, - {IValue::ASSUME, handlers::assume}, - {IValue::TRY, handlers::try_handler (false)}, - {IValue::CATCH_UNWIND, handlers::try_handler (true)}, - {IValue::DISCRIMINANT_VALUE, handlers::discriminant_value}, - {IValue::VARIANT_COUNT, handlers::variant_count}, - {IValue::BSWAP, handlers::bswap_handler}, - {IValue::CTLZ, handlers::ctlz_handler}, - {IValue::CTLZ_NONZERO, handlers::ctlz_nonzero_handler}, - {IValue::CTTZ, handlers::cttz_handler}, - {IValue::CTTZ_NONZERO, handlers::cttz_nonzero_handler}}; + = { + {IValue::OFFSET, handlers::offset}, + {IValue::ARITH_OFFSET, handlers::arith_offset_handler}, + {IValue::WRITE_BYTES, handlers::write_bytes_handler}, + {IValue::ASSERT_ZERO_VALID, handlers::assert_zero_valid_handler}, + {IValue::SIZE_OF, handlers::sizeof_handler}, + {IValue::SIZE_OF_VAL, handlers::size_of_val_handler}, + {IValue::MIN_ALIGN_OF, handlers::min_align_of_handler}, + {IValue::MIN_ALIGN_OF_VAL, handlers::min_align_of_val_handler}, + {IValue::TRANSMUTE, handlers::transmute}, + {IValue::ROTATE_LEFT, handlers::rotate_left}, + {IValue::ROTATE_RIGHT, handlers::rotate_right}, + {IValue::WRAPPING_ADD, handlers::wrapping_op (PLUS_EXPR)}, + {IValue::WRAPPING_SUB, handlers::wrapping_op (MINUS_EXPR)}, + {IValue::WRAPPING_MUL, handlers::wrapping_op (MULT_EXPR)}, + {IValue::ADD_WITH_OVERFLOW, handlers::op_with_overflow (PLUS_EXPR)}, + {IValue::SUB_WITH_OVERFLOW, handlers::op_with_overflow (MINUS_EXPR)}, + {IValue::MUL_WITH_OVERFLOW, handlers::op_with_overflow (MULT_EXPR)}, + {IValue::COPY, handlers::copy (true)}, + {IValue::COPY_NONOVERLAPPING, handlers::copy (false)}, + {IValue::PREFETCH_READ_DATA, handlers::prefetch_read_data}, + {IValue::PREFETCH_WRITE_DATA, handlers::prefetch_write_data}, + {IValue::ATOMIC_STORE, handlers::atomic_store (__ATOMIC_SEQ_CST)}, + {IValue::ATOMIC_STORE_SEQCST, handlers::atomic_store (__ATOMIC_SEQ_CST)}, + {IValue::ATOMIC_STORE_REL, handlers::atomic_store (__ATOMIC_RELEASE)}, + {IValue::ATOMIC_STORE_RELEASE, handlers::atomic_store (__ATOMIC_RELEASE)}, + {IValue::ATOMIC_STORE_RELAXED, handlers::atomic_store (__ATOMIC_RELAXED)}, + {IValue::ATOMIC_STORE_UNORDERED, handlers::atomic_store (__ATOMIC_RELAXED)}, + {IValue::ATOMIC_LOAD, handlers::atomic_load (__ATOMIC_SEQ_CST)}, + {IValue::ATOMIC_LOAD_SEQCST, handlers::atomic_load (__ATOMIC_SEQ_CST)}, + {IValue::ATOMIC_LOAD_ACQ, handlers::atomic_load (__ATOMIC_ACQUIRE)}, + {IValue::ATOMIC_LOAD_ACQUIRE, handlers::atomic_load (__ATOMIC_ACQUIRE)}, + {IValue::ATOMIC_LOAD_RELAXED, handlers::atomic_load (__ATOMIC_RELAXED)}, + {IValue::ATOMIC_LOAD_UNORDERED, handlers::atomic_load (__ATOMIC_RELAXED)}, + {IValue::UNCHECKED_ADD, handlers::unchecked_op (PLUS_EXPR)}, + {IValue::UNCHECKED_SUB, handlers::unchecked_op (MINUS_EXPR)}, + {IValue::UNCHECKED_MUL, handlers::unchecked_op (MULT_EXPR)}, + {IValue::UNCHECKED_DIV, handlers::unchecked_op (TRUNC_DIV_EXPR)}, + {IValue::UNCHECKED_REM, handlers::unchecked_op (TRUNC_MOD_EXPR)}, + {IValue::UNCHECKED_SHL, handlers::unchecked_op (LSHIFT_EXPR)}, + {IValue::UNCHECKED_SHR, handlers::unchecked_op (RSHIFT_EXPR)}, + {IValue::UNINIT, handlers::uninit}, + {IValue::MOVE_VAL_INIT, handlers::move_val_init}, + {IValue::LIKELY, handlers::expect (true)}, + {IValue::UNLIKELY, handlers::expect (false)}, + {IValue::ASSUME, handlers::assume}, + {IValue::TRY, handlers::try_handler (false)}, + {IValue::CATCH_UNWIND, handlers::try_handler (true)}, + {IValue::DISCRIMINANT_VALUE, handlers::discriminant_value}, + {IValue::VARIANT_COUNT, handlers::variant_count}, + {IValue::BSWAP, handlers::bswap_handler}, + {IValue::CTLZ, handlers::ctlz_handler}, + {IValue::CTLZ_NONZERO, handlers::ctlz_nonzero_handler}, + {IValue::CTTZ, handlers::cttz_handler}, + {IValue::CTTZ_NONZERO, handlers::cttz_nonzero_handler}, + {IValue::FADD_FAST, handlers::fop_fast (ArithmeticOrLogicalOperator::ADD)}, + {IValue::FSUB_FAST, + handlers::fop_fast (ArithmeticOrLogicalOperator::SUBTRACT)}, + {IValue::FMUL_FAST, + handlers::fop_fast (ArithmeticOrLogicalOperator::MULTIPLY)}, + {IValue::FDIV_FAST, + handlers::fop_fast (ArithmeticOrLogicalOperator::DIVIDE)}, + {IValue::FREM_FAST, + handlers::fop_fast (ArithmeticOrLogicalOperator::MODULUS)}, +}; Intrinsics::Intrinsics (Context *ctx) : ctx (ctx) {} diff --git a/gcc/rust/backend/rust-intrinsic-handlers.cc b/gcc/rust/backend/rust-intrinsic-handlers.cc index d68e872af43e..2d8dad76379b 100644 --- a/gcc/rust/backend/rust-intrinsic-handlers.cc +++ b/gcc/rust/backend/rust-intrinsic-handlers.cc @@ -26,6 +26,7 @@ #include "rust-constexpr.h" #include "rust-session-manager.h" #include "rust-tree.h" +#include "rust-tyty.h" #include "tree-core.h" #include "rust-gcc.h" #include "fold-const.h" @@ -1036,6 +1037,53 @@ cttz_handler (Context *ctx, TyTy::FnType *fntype, bool nonzero) return fndecl; } +static tree +fop_fast (Context *ctx, TyTy::FnType *fntype, location_t locus, + ArithmeticOrLogicalOperator op) +{ + // fast float ops intrinsics have two parameters + rust_assert (fntype->get_params ().size () == 2); + + // and one generic parameter + rust_assert (fntype->get_num_substitutions () == 1); + + tree lookup = NULL_TREE; + if (check_for_cached_intrinsic (ctx, fntype, &lookup)) + return lookup; + + auto fndecl = compile_intrinsic_function (ctx, fntype); + + // setup the params + std::vector<Bvariable *> param_vars; + compile_fn_params (ctx, fntype, fndecl, ¶m_vars); + + auto &lhs_param = param_vars.at (0); + auto &rhs_param = param_vars.at (1); + rust_assert (param_vars.size () == 2); + + if (!Backend::function_set_parameters (fndecl, param_vars)) + return error_mark_node; + + enter_intrinsic_block (ctx, fndecl); + + // BUILTIN rotate FN BODY BEGIN + tree lhs = Backend::var_expression (lhs_param, UNDEF_LOCATION); + tree rhs = Backend::var_expression (rhs_param, UNDEF_LOCATION); + + tree result_expr + = Backend::arithmetic_or_logical_expression (op, lhs, rhs, locus); + + auto return_statement + = Backend::return_statement (fndecl, result_expr, UNDEF_LOCATION); + + ctx->add_statement (return_statement); + // BUILTIN rotate FN BODY END + + finalize_intrinsic_block (ctx, fndecl); + + return fndecl; +} + } // namespace inner const HandlerBuilder @@ -1046,6 +1094,14 @@ op_with_overflow (tree_code op) }; } +HandlerBuilder +fop_fast (ArithmeticOrLogicalOperator op) +{ + return [op] (Context *ctx, TyTy::FnType *fntype, location_t locus) { + return inner::fop_fast (ctx, fntype, locus, op); + }; +} + tree rotate_left (Context *ctx, TyTy::FnType *fntype, location_t) { diff --git a/gcc/rust/backend/rust-intrinsic-handlers.h b/gcc/rust/backend/rust-intrinsic-handlers.h index 712d422e5148..6161b7fa2c43 100644 --- a/gcc/rust/backend/rust-intrinsic-handlers.h +++ b/gcc/rust/backend/rust-intrinsic-handlers.h @@ -107,6 +107,11 @@ tree arith_offset_handler (Context *ctx, TyTy::FnType *fntype, tree assert_zero_valid_handler (Context *ctx, TyTy::FnType *fntype, location_t expr_locus); +/** + * For fadd_fast, fsub_fast, fmul_fast, fdiv_fast and frem_fast + */ +HandlerBuilder fop_fast (ArithmeticOrLogicalOperator op); + } // namespace handlers } // namespace Compile diff --git a/gcc/rust/typecheck/rust-hir-type-check-intrinsic.cc b/gcc/rust/typecheck/rust-hir-type-check-intrinsic.cc index a0a0479639eb..716df7880557 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-intrinsic.cc +++ b/gcc/rust/typecheck/rust-hir-type-check-intrinsic.cc @@ -313,6 +313,20 @@ const std::unordered_map<std::string, IntrinsicRules> {1, {IRT::MutPtrFirstGeneric, IRT::U8, IRT::Usize}, IRT::Unit}}, // pub fn assert_zero_valid<T>(); {IValue::ASSERT_ZERO_VALID, {1, {}, IRT::Unit}}, + + // pub fn fadd_fast<T>(a: T, b: T) -> T + // same for fsub_fast, fmul_fast, fdiv_fast and frem_fast + {IValue::FADD_FAST, + {1, {IRT::FirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}}, + {IValue::FSUB_FAST, + {1, {IRT::FirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}}, + {IValue::FMUL_FAST, + {1, {IRT::FirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}}, + {IValue::FDIV_FAST, + {1, {IRT::FirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}}, + {IValue::FREM_FAST, + {1, {IRT::FirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}}, + }; IntrinsicCheckResult diff --git a/gcc/rust/util/rust-intrinsic-values.h b/gcc/rust/util/rust-intrinsic-values.h index 43df60fd5a2d..9223e20abedc 100644 --- a/gcc/rust/util/rust-intrinsic-values.h +++ b/gcc/rust/util/rust-intrinsic-values.h @@ -175,6 +175,12 @@ public: static constexpr auto &ARITH_OFFSET = "arith_offset"; static constexpr auto &WRITE_BYTES = "write_bytes"; static constexpr auto &ASSERT_ZERO_VALID = "assert_zero_valid"; + + static constexpr auto &FADD_FAST = "fadd_fast"; + static constexpr auto &FSUB_FAST = "fsub_fast"; + static constexpr auto &FMUL_FAST = "fmul_fast"; + static constexpr auto &FDIV_FAST = "fdiv_fast"; + static constexpr auto &FREM_FAST = "frem_fast"; }; } // namespace Values } // namespace Rust diff --git a/gcc/testsuite/rust/compile/fop_fast_intrinsics.rs b/gcc/testsuite/rust/compile/fop_fast_intrinsics.rs new file mode 100644 index 000000000000..4d798a6da0ac --- /dev/null +++ b/gcc/testsuite/rust/compile/fop_fast_intrinsics.rs @@ -0,0 +1,27 @@ +#![feature(no_core)] +#![feature(intrinsics)] +#![feature(lang_items)] +#![no_core] + +#[lang = "sized"] +trait Sized {} + +extern "rust-intrinsic" { + fn fadd_fast<T>(a: T, b: T) -> T; + fn fsub_fast<T>(a: T, b: T) -> T; + fn fmul_fast<T>(a: T, b: T) -> T; + fn fdiv_fast<T>(a: T, b: T) -> T; + fn frem_fast<T>(a: T, b: T) -> T; +} + +fn main() { + unsafe { + fadd_fast(4.07, 2.9); + fsub_fast(4.07, 2.9); + fmul_fast(4.07, 2.9); + fdiv_fast(4.07, 2.9); + + frem_fast(4.07f32, 2.9f32); + frem_fast(4.07f64, 2.9f64); + } +}
