From: Arthur Cohen <[email protected]>

And open Rust-GCC/gccrs#4949 as this means our regular casts from float to int 
are
invalid and missing some extra checks.

gcc/rust/ChangeLog:

        * backend/rust-compile-intrinsic.cc: Declare the new intrinsic.
        * backend/rust-intrinsic-handlers.cc (float_to_int_unchecked): New 
handler.
        * backend/rust-intrinsic-handlers.h (float_to_int_unchecked): Declare 
it.
        * typecheck/rust-hir-type-check-intrinsic.cc: Add the intrinsic to the 
typecheck
        info.
        * util/rust-intrinsic-values.h: New value for float_to_int_unchecked.

gcc/testsuite/ChangeLog:

        * rust/execute/torture/float_to_int_unchecked.rs: New test.
---
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/0b70380e60d04b0f47e3657dcbe68899aafe1663

The commit has been mentioned in the following issue(s):
 - Rust-GCC/gccrs#4949: https://github.com/Rust-GCC/gccrs/issues/4949

The commit has been mentioned in the following pull-request(s):
 - https://github.com/Rust-GCC/gccrs/pull/4970

 gcc/rust/backend/rust-compile-intrinsic.cc    |  1 +
 gcc/rust/backend/rust-intrinsic-handlers.cc   | 44 +++++++++++++++++++
 gcc/rust/backend/rust-intrinsic-handlers.h    |  3 ++
 .../rust-hir-type-check-intrinsic.cc          |  5 +++
 gcc/rust/util/rust-intrinsic-values.h         |  2 +
 .../execute/torture/float_to_int_unchecked.rs | 22 ++++++++++
 6 files changed, 77 insertions(+)
 create mode 100644 gcc/testsuite/rust/execute/torture/float_to_int_unchecked.rs

diff --git a/gcc/rust/backend/rust-compile-intrinsic.cc 
b/gcc/rust/backend/rust-compile-intrinsic.cc
index c16db442f..0202f493c 100644
--- a/gcc/rust/backend/rust-compile-intrinsic.cc
+++ b/gcc/rust/backend/rust-compile-intrinsic.cc
@@ -92,6 +92,7 @@ static const std::map<std::string, handlers::HandlerBuilder> 
generic_intrinsics
      handlers::fop_fast (ArithmeticOrLogicalOperator::DIVIDE)},
     {IValue::FREM_FAST,
      handlers::fop_fast (ArithmeticOrLogicalOperator::MODULUS)},
+    {IValue::FLOAT_TO_INT_UNCHECKED, handlers::float_to_int_unchecked},
 };
 
 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 2d8dad763..c07609891 100644
--- a/gcc/rust/backend/rust-intrinsic-handlers.cc
+++ b/gcc/rust/backend/rust-intrinsic-handlers.cc
@@ -2316,6 +2316,50 @@ assert_zero_valid_handler (Context *ctx, TyTy::FnType 
*fntype, location_t)
   return fndecl;
 }
 
+tree
+float_to_int_unchecked (Context *ctx, TyTy::FnType *fntype, location_t loc)
+{
+  rust_assert (fntype->get_params ().size () == 1);
+  rust_assert (fntype->get_num_substitutions () == 2);
+
+  tree lookup = NULL_TREE;
+  if (check_for_cached_intrinsic (ctx, fntype, &lookup))
+    return lookup;
+
+  auto fndecl = compile_intrinsic_function (ctx, fntype);
+
+  auto &dst_param = fntype->get_substs ().at (1);
+  const auto dst_ty = dst_param.get_param_ty ();
+  auto int_ty_resolved = dst_ty->resolve ();
+
+  auto int_ty = TyTyResolveCompile::compile (ctx, int_ty_resolved);
+
+  // setup the params
+  std::vector<Bvariable *> param_vars;
+  compile_fn_params (ctx, fntype, fndecl, &param_vars);
+
+  rust_assert (param_vars.size () == 1);
+
+  auto &float_param = param_vars.at (0);
+
+  if (!Backend::function_set_parameters (fndecl, param_vars))
+    return error_mark_node;
+
+  enter_intrinsic_block (ctx, fndecl);
+
+  tree float_value = Backend::var_expression (float_param, UNDEF_LOCATION);
+
+  auto convert_expr = Backend::convert_expression (int_ty, float_value, loc);
+
+  auto return_statement = Backend::return_statement (fndecl, convert_expr, 
loc);
+
+  ctx->add_statement (return_statement);
+
+  finalize_intrinsic_block (ctx, fndecl);
+
+  return fndecl;
+}
+
 } // namespace handlers
 } // namespace Compile
 } // namespace Rust
diff --git a/gcc/rust/backend/rust-intrinsic-handlers.h 
b/gcc/rust/backend/rust-intrinsic-handlers.h
index 6161b7fa2..bc668a7f1 100644
--- a/gcc/rust/backend/rust-intrinsic-handlers.h
+++ b/gcc/rust/backend/rust-intrinsic-handlers.h
@@ -112,6 +112,9 @@ tree assert_zero_valid_handler (Context *ctx, TyTy::FnType 
*fntype,
  */
 HandlerBuilder fop_fast (ArithmeticOrLogicalOperator op);
 
+tree float_to_int_unchecked (Context *ctx, TyTy::FnType *fntype,
+                            location_t loc);
+
 } // 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 716df7880..1498a09c4 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-intrinsic.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-intrinsic.cc
@@ -327,6 +327,11 @@ const std::unordered_map<std::string, IntrinsicRules>
     {IValue::FREM_FAST,
      {1, {IRT::FirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
 
+    // fn float_to_int_unchecked<Float, Int>(x: Float) -> Int
+    //     where Float: FloatPrimitive, Int: Copy
+    {IValue::FLOAT_TO_INT_UNCHECKED,
+     {2, {IRT::FirstGeneric}, IRT::SecondGeneric}},
+
 };
 
 IntrinsicCheckResult
diff --git a/gcc/rust/util/rust-intrinsic-values.h 
b/gcc/rust/util/rust-intrinsic-values.h
index 9223e20ab..0da1f0c3a 100644
--- a/gcc/rust/util/rust-intrinsic-values.h
+++ b/gcc/rust/util/rust-intrinsic-values.h
@@ -181,6 +181,8 @@ public:
   static constexpr auto &FMUL_FAST = "fmul_fast";
   static constexpr auto &FDIV_FAST = "fdiv_fast";
   static constexpr auto &FREM_FAST = "frem_fast";
+
+  static constexpr auto &FLOAT_TO_INT_UNCHECKED = "float_to_int_unchecked";
 };
 } // namespace Values
 } // namespace Rust
diff --git a/gcc/testsuite/rust/execute/torture/float_to_int_unchecked.rs 
b/gcc/testsuite/rust/execute/torture/float_to_int_unchecked.rs
new file mode 100644
index 000000000..4f342c291
--- /dev/null
+++ b/gcc/testsuite/rust/execute/torture/float_to_int_unchecked.rs
@@ -0,0 +1,22 @@
+#![feature(no_core)]
+#![feature(intrinsics)]
+#![feature(lang_items)]
+#![no_core]
+
+#[lang = "sized"]
+trait Sized {}
+
+extern "rust-intrinsic" {
+    fn float_to_int_unchecked<Float, Int>(value: Float) -> Int;
+}
+
+fn main() -> i32 {
+    let a = 15.07;
+
+    let b = a as i32;
+    let c: i32 = unsafe { float_to_int_unchecked(a) };
+
+    // NOTE: This is only valid for certain floating point values as f32 -> 
i32 conversions
+    // are different for invalid values when using the cast and when using the 
unchecked intrinsic
+    b - c
+}

base-commit: a02e9a643d591708a5de6d506ef75f3405a91a0e
-- 
2.55.0

Reply via email to