From: Arthur Cohen <[email protected]>

gcc/rust/ChangeLog:

        * backend/rust-compile-intrinsic.cc: Register new handler.
        * backend/rust-intrinsic-handlers.cc (ptr_offset_from): New function.
        * backend/rust-intrinsic-handlers.h (ptr_offset_from): Likewise.
        * typecheck/rust-hir-type-check-intrinsic.cc: Register new entry for
        ptr_offset_from.
        * util/rust-intrinsic-values.h: Likewise.

gcc/testsuite/ChangeLog:

        * rust/execute/torture/ptr_offset_from.rs: New test.

Tested on x86_64-pc-linux-gnu.

---
 gcc/rust/backend/rust-compile-intrinsic.cc    |  1 +
 gcc/rust/backend/rust-intrinsic-handlers.cc   | 40 +++++++++++++++++++
 gcc/rust/backend/rust-intrinsic-handlers.h    |  2 +
 .../rust-hir-type-check-intrinsic.cc          |  4 ++
 gcc/rust/util/rust-intrinsic-values.h         |  2 +
 .../rust/execute/torture/ptr_offset_from.rs   | 30 ++++++++++++++
 6 files changed, 79 insertions(+)
 create mode 100644 gcc/testsuite/rust/execute/torture/ptr_offset_from.rs

diff --git a/gcc/rust/backend/rust-compile-intrinsic.cc 
b/gcc/rust/backend/rust-compile-intrinsic.cc
index 862d9a3adb7..8b98d35416d 100644
--- a/gcc/rust/backend/rust-compile-intrinsic.cc
+++ b/gcc/rust/backend/rust-compile-intrinsic.cc
@@ -234,6 +234,7 @@ static const std::map<std::string, Intrinsic::CompileFn> 
intrinsics = {
   {IValue::ASSERT_ZERO_VALID, handlers::type_assert (TyAssert::ZeroValid)},
   {IValue::ASSERT_INHABITED, handlers::type_assert (TyAssert::Inhabited)},
   {IValue::ASSERT_UNINIT_VALID, handlers::type_assert (TyAssert::UninitValid)},
+  {IValue::PTR_OFFSET_FROM, handlers::ptr_offset_from},
 };
 
 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 74d278d3388..d4ef4a9c728 100644
--- a/gcc/rust/backend/rust-intrinsic-handlers.cc
+++ b/gcc/rust/backend/rust-intrinsic-handlers.cc
@@ -27,6 +27,7 @@
 #include "rust-diagnostics.h"
 #include "rust-location.h"
 #include "rust-constexpr.h"
+#include "rust-operators.h"
 #include "rust-session-manager.h"
 #include "rust-tree.h"
 #include "rust-tyty.h"
@@ -2215,6 +2216,45 @@ breakpoint (IntrinsicCtx &ctx)
   TREE_SIDE_EFFECTS (ctx.fn) = 1;
 }
 
+void
+ptr_offset_from (IntrinsicCtx &ctx)
+{
+  // Per offset_from's documentation
+  // https://doc.rust-lang.org/std/primitive.pointer.html#method.offset_from
+  //
+  // This calculates the distance between two pointers in terms of units of `T`
+  // - the distance in bytes divided by `size_of::<T>()`
+
+  auto &param_mapping = ctx.fntype.get_substs ().at (0);
+  auto param_tyty = param_mapping.get_param_ty ();
+  auto resolved_tyty = param_tyty->resolve ();
+  tree ty = TyTyResolveCompile::compile (ctx.inner (), resolved_tyty);
+
+  auto pointee_size_unsigned = TYPE_SIZE_UNIT (ty);
+  auto pointee_size
+    = Backend::convert_expression (signed_size_type_node, 
pointee_size_unsigned,
+                                  ctx.loc);
+
+  auto addr = Backend::var_expression (ctx.param_vars[0], ctx.loc);
+  auto base = Backend::var_expression (ctx.param_vars[1], ctx.loc);
+
+  // Convert the pointers to integers
+  auto addr_int
+    = Backend::convert_expression (signed_size_type_node, addr, ctx.loc);
+  auto base_int
+    = Backend::convert_expression (signed_size_type_node, base, ctx.loc);
+
+  auto byte_diff = Backend::arithmetic_or_logical_expression (
+    ArithmeticOrLogicalOperator::SUBTRACT, addr_int, base_int, ctx.loc);
+
+  auto result = build2_loc (ctx.loc, EXACT_DIV_EXPR, signed_size_type_node,
+                           byte_diff, pointee_size);
+
+  auto return_stmt = Backend::return_statement (ctx.fn, result, ctx.loc);
+
+  ctx.add_statement (return_stmt);
+}
+
 } // 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 b57485d130c..7e5691041b5 100644
--- a/gcc/rust/backend/rust-intrinsic-handlers.h
+++ b/gcc/rust/backend/rust-intrinsic-handlers.h
@@ -221,6 +221,8 @@ Intrinsic::CompileFn type_assert (TyAssert assert);
 
 void breakpoint (IntrinsicCtx &ctx);
 
+void ptr_offset_from (IntrinsicCtx &ctx);
+
 } // 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 afa633c3852..3139bf5d45b 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-intrinsic.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-intrinsic.cc
@@ -537,6 +537,10 @@ const std::unordered_map<std::string, IntrinsicRules>
     // fn nontemporal_store<T>(ptr: *mut T, value: T)
     {IValue::NONTEMPORAL_STORE,
      {1, {IRT::MutPtrFirstGeneric, IRT::FirstGeneric}, IRT::Unit}},
+
+    // fn ptr_offset_from<T>(ptr: *const T, base: *const T) -> isize;
+    {IValue::PTR_OFFSET_FROM,
+     {1, {IRT::ConstPtrFirstGeneric, IRT::ConstPtrFirstGeneric}, IRT::Isize}},
 };
 
 IntrinsicCheckResult
diff --git a/gcc/rust/util/rust-intrinsic-values.h 
b/gcc/rust/util/rust-intrinsic-values.h
index 1bd5d16527c..f8067a62a46 100644
--- a/gcc/rust/util/rust-intrinsic-values.h
+++ b/gcc/rust/util/rust-intrinsic-values.h
@@ -286,6 +286,8 @@ public:
   static constexpr auto &EXACT_DIV = "exact_div";
 
   static constexpr auto &NONTEMPORAL_STORE = "nontemporal_store";
+
+  static constexpr auto &PTR_OFFSET_FROM = "ptr_offset_from";
 };
 } // namespace Values
 } // namespace Rust
diff --git a/gcc/testsuite/rust/execute/torture/ptr_offset_from.rs 
b/gcc/testsuite/rust/execute/torture/ptr_offset_from.rs
new file mode 100644
index 00000000000..d884cc8ff23
--- /dev/null
+++ b/gcc/testsuite/rust/execute/torture/ptr_offset_from.rs
@@ -0,0 +1,30 @@
+#![feature(no_core)]
+#![feature(intrinsics)]
+#![feature(lang_items)]
+#![no_core]
+
+#[lang = "sized"]
+trait Sized {}
+
+extern "rust-intrinsic" {
+    fn ptr_offset_from<T>(ptr: *const T, base: *const T) -> isize;
+    fn size_of<T>() -> usize;
+}
+
+fn main() -> i32 {
+    let value = 0;
+
+    let first = &value as *const i32;
+
+    // Crimes? A lil bit of crimes?
+    let last = first as usize;
+
+    let last = last + 8 * size_of::<i32>();
+
+    let first = first as *const i32;
+    let last = last as *const i32;
+
+    let offset = unsafe { ptr_offset_from(last, first) };
+
+    offset as i32 - 8
+}
-- 
2.55.0

Reply via email to