[gccrs COMMIT 2/4] gccrs: Initial implementation of LLVM builtin to GCC adapter

gerris.rs@gmail.com gerris.rs@gmail.com
Mon Aug 31 13:08:28 GMT 2026


From: Yap Zhi Heng <yapzhhg@gmail.com>

Only works for rdseed, rdrand, addcarry and subborrow for now. Compiled 006t.original output
from compiling llvm_builtins.rs:

```
struct (u16, i32) x86_rdrand16_step ()
{
  u16 RUSTTMP.0;
  i32 RUSTTMP.1;

  RUSTTMP.1 = __builtin_ia32_rdrand16_step (&RUSTTMP.0);
  return {.__0=RUSTTMP.0, .__1=RUSTTMP.1};
}

struct (u32, i32) x86_rdrand32_step ()
{
  u32 RUSTTMP.2;
  i32 RUSTTMP.3;

  RUSTTMP.3 = __builtin_ia32_rdrand32_step (&RUSTTMP.2);
  return {.__0=RUSTTMP.2, .__1=RUSTTMP.3};
}

struct (u64, i32) x86_rdrand64_step ()
{
  u64 RUSTTMP.4;
  i32 RUSTTMP.5;

  RUSTTMP.5 = __builtin_ia32_rdrand64_step ((unsigned long *) &RUSTTMP.4);
  return {.__0=RUSTTMP.4, .__1=RUSTTMP.5};
}

struct (u16, i32) x86_rdseed16_step ()
{
  u16 RUSTTMP.6;
  i32 RUSTTMP.7;

  RUSTTMP.7 = __builtin_ia32_rdseed_hi_step (&RUSTTMP.6);
  return {.__0=RUSTTMP.6, .__1=RUSTTMP.7};
}

struct (u32, i32) x86_rdseed32_step ()
{
  u32 RUSTTMP.8;
  i32 RUSTTMP.9;

  RUSTTMP.9 = __builtin_ia32_rdseed_si_step (&RUSTTMP.8);
  return {.__0=RUSTTMP.8, .__1=RUSTTMP.9};
}

struct (u64, i32) x86_rdseed64_step ()
{
  u64 RUSTTMP.10;
  i32 RUSTTMP.11;

  RUSTTMP.11 = __builtin_ia32_rdseed_di_step ((unsigned long *) &RUSTTMP.10);
  return {.__0=RUSTTMP.10, .__1=RUSTTMP.11};
}

struct (u8, u32) llvm_addcarry_u32 (const u8 a, const u32 b, const u32 c)
{
  u32 RUSTTMP.12;
  u8 RUSTTMP.13;

  RUSTTMP.13 = (u8) __builtin_ia32_addcarryx_u32 ((unsigned char) a, (u32) b, (u32) c, &RUSTTMP.12);
  return {.__0=RUSTTMP.13, .__1=RUSTTMP.12};
}

struct (u8, u32) llvm_subborrow_u32 (const u8 a, const u32 b, const u32 c)
{
  u32 RUSTTMP.14;
  u8 RUSTTMP.15;

  RUSTTMP.15 = (u8) __builtin_ia32_sbb_u32 ((unsigned char) a, (u32) b, (u32) c, &RUSTTMP.14);
  return {.__0=RUSTTMP.15, .__1=RUSTTMP.14};
}

struct (u8, u64) llvm_addcarry_u64 (const u8 a, const u64 b, const u64 c)
{
  u64 RUSTTMP.16;
  u8 RUSTTMP.17;

  RUSTTMP.17 = (u8) __builtin_ia32_addcarryx_u64 ((unsigned char) a, (unsigned long) b, (unsigned long) c, (unsigned long *) &RUSTTMP.16);
  return {.__0=RUSTTMP.17, .__1=RUSTTMP.16};
}

struct (u8, u64) llvm_subborrow_u64 (const u8 a, const u64 b, const u64 c)
{
  u64 RUSTTMP.18;
  u8 RUSTTMP.19;

  RUSTTMP.19 = (u8) __builtin_ia32_sbb_u64 ((unsigned char) a, (unsigned long) b, (unsigned long) c, (unsigned long *) &RUSTTMP.18);
  return {.__0=RUSTTMP.19, .__1=RUSTTMP.18};
}
```

gcc/rust/ChangeLog:

	* backend/rust-builtins.h (LlvmBuiltinMappingResult): New enum.
	(LlvmBuiltinAdapter): New enum.
	(LlvmBuiltinMapping): New enum.
	(BuiltinsContext::map_llvm_to_gcc_builtin): New function for LLVM built-in mapping.
	(BuiltinsContext::register_builtin): New function for registering built-ins.
	(BuiltinsContext::register_llvm_to_gcc_builtin): New function.
	(BuiltinsContext::llvm_to_gcc_builtin): New map to translate function names.
	* backend/rust-builtins.cc (BuiltinsContext::map_llvm_to_gcc_builtin): Implementation.
	(BuiltinsContext::register_llvm_to_gcc_builtin): Implementation.
	(BuiltinsContext::register_builtin): Implementation.
	(BuiltinsContext::setup): Call register_llvm_to_gcc_builtin during setup.
	* rust-lang.cc (grs_langhook_builtin_function): Register GCC built-in functions.
	* backend/rust-compile-extern.h (CompileExternItem::OutputTupleOrder): New enum to denote
	the tuple field order of the LLVM built-in's return type.
	(CompileExternItem::compile_x86_output_pointer_adapter): New function to adapt LLVM's
	rdseed, rdrand, addcarry, subborrow function signatures to GCC's equivalents.
	(CompileExternItem::visit (HIR::ExternalFunctionItem)): Handle UNADJUSTED ABI case by
	properly resolving LLVM intrinsic function names.

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/61db02df381b61b57a8862b676eb59a493ea3780

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/4809

 gcc/rust/backend/rust-builtins.cc           |  71 +++++++
 gcc/rust/backend/rust-builtins.h            |  28 +++
 gcc/rust/backend/rust-compile-extern.h      | 213 ++++++++++++++++++++
 gcc/rust/rust-lang.cc                       |   6 +-
 gcc/testsuite/rust/compile/llvm_builtins.rs |  50 +++++
 5 files changed, 366 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/rust/compile/llvm_builtins.rs

diff --git a/gcc/rust/backend/rust-builtins.cc b/gcc/rust/backend/rust-builtins.cc
index e685a4d1e..0d08cdf3d 100644
--- a/gcc/rust/backend/rust-builtins.cc
+++ b/gcc/rust/backend/rust-builtins.cc
@@ -48,6 +48,25 @@ BuiltinsContext::lookup_simple_builtin (const std::string &name, tree *builtin)
   return lookup_gcc_builtin (*to_search, builtin);
 }
 
+LlvmBuiltinMappingResult
+BuiltinsContext::map_llvm_to_gcc_builtin (const std::string &name,
+					  tree *resolved,
+					  LlvmBuiltinAdapter *adapter)
+{
+  rust_assert (resolved != nullptr);
+
+  auto mapping = llvm_to_gcc_builtin.find (name);
+  if (mapping == llvm_to_gcc_builtin.end ())
+    return LlvmBuiltinMappingResult::NOT_MAPPED;
+
+  *resolved = NULL_TREE;
+  if (!lookup_gcc_builtin (mapping->second.gcc_name, resolved))
+    return LlvmBuiltinMappingResult::TARGET_UNAVAILABLE;
+
+  *adapter = mapping->second.adapter;
+  return LlvmBuiltinMappingResult::RESOLVED;
+}
+
 BuiltinsContext::BuiltinsContext () : setup_state (SetupState::UNINITIALIZED) {}
 
 /**
@@ -359,6 +378,57 @@ BuiltinsContext::register_rust_mappings ()
   };
 }
 
+void
+BuiltinsContext::register_llvm_to_gcc_builtin ()
+{
+  llvm_to_gcc_builtin = {
+    {"llvm.x86.rdrand.16",
+     {"__builtin_ia32_rdrand16_step",
+      LlvmBuiltinAdapter::OUTPUT_POINTER_VALUE_STATUS}},
+    {"llvm.x86.rdrand.32",
+     {"__builtin_ia32_rdrand32_step",
+      LlvmBuiltinAdapter::OUTPUT_POINTER_VALUE_STATUS}},
+    {"llvm.x86.rdrand.64",
+     {"__builtin_ia32_rdrand64_step",
+      LlvmBuiltinAdapter::OUTPUT_POINTER_VALUE_STATUS}},
+    {"llvm.x86.rdseed.16",
+     {"__builtin_ia32_rdseed_hi_step",
+      LlvmBuiltinAdapter::OUTPUT_POINTER_VALUE_STATUS}},
+    {"llvm.x86.rdseed.32",
+     {"__builtin_ia32_rdseed_si_step",
+      LlvmBuiltinAdapter::OUTPUT_POINTER_VALUE_STATUS}},
+    {"llvm.x86.rdseed.64",
+     {"__builtin_ia32_rdseed_di_step",
+      LlvmBuiltinAdapter::OUTPUT_POINTER_VALUE_STATUS}},
+
+    {"llvm.x86.addcarry.32",
+     {"__builtin_ia32_addcarryx_u32",
+      LlvmBuiltinAdapter::OUTPUT_POINTER_STATUS_VALUE}},
+    {"llvm.x86.addcarryx.u32",
+     {"__builtin_ia32_addcarryx_u32", LlvmBuiltinAdapter::FORWARD_ARGUMENTS}},
+    {"llvm.x86.subborrow.32",
+     {"__builtin_ia32_sbb_u32",
+      LlvmBuiltinAdapter::OUTPUT_POINTER_STATUS_VALUE}},
+    {"llvm.x86.addcarry.64",
+     {"__builtin_ia32_addcarryx_u64",
+      LlvmBuiltinAdapter::OUTPUT_POINTER_STATUS_VALUE}},
+    {"llvm.x86.addcarryx.u64",
+     {"__builtin_ia32_addcarryx_u64", LlvmBuiltinAdapter::FORWARD_ARGUMENTS}},
+    {"llvm.x86.subborrow.64",
+     {"__builtin_ia32_sbb_u64",
+      LlvmBuiltinAdapter::OUTPUT_POINTER_STATUS_VALUE}}};
+}
+
+void
+BuiltinsContext::register_builtin (tree decl)
+{
+  rust_assert (TREE_CODE (decl) == FUNCTION_DECL);
+  rust_assert (DECL_NAME (decl));
+
+  const char *name = IDENTIFIER_POINTER (DECL_NAME (decl));
+  builtin_functions.insert ({std::string (name), decl});
+}
+
 void
 BuiltinsContext::setup ()
 {
@@ -372,6 +442,7 @@ BuiltinsContext::setup ()
   targetm.init_builtins ();
 
   register_rust_mappings ();
+  register_llvm_to_gcc_builtin ();
 
   setup_state = SetupState::READY;
 }
diff --git a/gcc/rust/backend/rust-builtins.h b/gcc/rust/backend/rust-builtins.h
index 7819a7c03..e2c7f9816 100644
--- a/gcc/rust/backend/rust-builtins.h
+++ b/gcc/rust/backend/rust-builtins.h
@@ -79,6 +79,26 @@ namespace Compile {
 // };
 // Some(cx.get_intrinsic(&llvm_name))
 
+enum class LlvmBuiltinMappingResult
+{
+  NOT_MAPPED,
+  TARGET_UNAVAILABLE,
+  RESOLVED,
+};
+
+enum class LlvmBuiltinAdapter
+{
+  OUTPUT_POINTER_VALUE_STATUS,
+  OUTPUT_POINTER_STATUS_VALUE,
+  FORWARD_ARGUMENTS,
+};
+
+struct LlvmBuiltinMapping
+{
+  std::string gcc_name;
+  LlvmBuiltinAdapter adapter;
+};
+
 class BuiltinsContext
 {
 public:
@@ -86,6 +106,12 @@ public:
 
   bool lookup_simple_builtin (const std::string &name, tree *builtin);
 
+  LlvmBuiltinMappingResult
+  map_llvm_to_gcc_builtin (const std::string &name, tree *resolved,
+			   LlvmBuiltinAdapter *adapter);
+
+  void register_builtin (tree decl);
+
 private:
   enum Type
   {
@@ -199,6 +225,7 @@ private:
   void define_builtins ();
 
   void register_rust_mappings ();
+  void register_llvm_to_gcc_builtin ();
 
   BuiltinsContext ();
 
@@ -213,6 +240,7 @@ private:
   // A mapping of the GCC built-ins exposed to GCC Rust.
   std::map<std::string, tree> builtin_functions;
   std::map<std::string, std::string> rust_intrinsic_to_gcc_builtin;
+  std::map<std::string, LlvmBuiltinMapping> llvm_to_gcc_builtin;
 };
 
 } // namespace Compile
diff --git a/gcc/rust/backend/rust-compile-extern.h b/gcc/rust/backend/rust-compile-extern.h
index 4eabf0ddb..f9aecef5b 100644
--- a/gcc/rust/backend/rust-compile-extern.h
+++ b/gcc/rust/backend/rust-compile-extern.h
@@ -26,6 +26,9 @@
 #include "rust-hir-full-decls.h"
 #include "rust-attributes.h"
 #include "rust-attribute-values.h"
+#include "rust-builtins.h"
+#include "rust-compile-fnparam.h"
+#include "fold-const.h"
 
 namespace Rust {
 namespace Compile {
@@ -127,6 +130,68 @@ public:
     std::string ir_symbol_name = function.get_item_name ().as_string ();
     GGC::Ident asm_name = get_link_name (function);
 
+    if (fntype->get_abi () == ABI::UNADJUSTED)
+      {
+	tree resolved;
+	LlvmBuiltinAdapter adapter;
+	auto mapping_res = BuiltinsContext::get ().map_llvm_to_gcc_builtin (
+	  asm_name.as_string (), &resolved, &adapter);
+
+	switch (mapping_res)
+	  {
+	  case LlvmBuiltinMappingResult::NOT_MAPPED:
+	    rust_error_at (function.get_locus (),
+			   "LLVM intrinsic %qs is not supported at the moment",
+			   asm_name.c_str ());
+	    reference = error_mark_node;
+	    return;
+	  case LlvmBuiltinMappingResult::TARGET_UNAVAILABLE:
+	    rust_error_at (
+	      function.get_locus (),
+	      "LLVM intrinsic %qs is not available for this target",
+	      asm_name.c_str ());
+	    reference = error_mark_node;
+	    return;
+	  case LlvmBuiltinMappingResult::RESOLVED:
+	    break;
+	  }
+
+	tree adapter_tree = error_mark_node;
+
+	switch (adapter)
+	  {
+	  case LlvmBuiltinAdapter::OUTPUT_POINTER_VALUE_STATUS:
+	    adapter_tree = compile_x86_output_pointer_adapter (
+	      ctx, fntype, resolved, OutputTupleOrder::VALUE_STATUS,
+	      function.get_locus ());
+	    break;
+	  case LlvmBuiltinAdapter::OUTPUT_POINTER_STATUS_VALUE:
+	    adapter_tree = compile_x86_output_pointer_adapter (
+	      ctx, fntype, resolved, OutputTupleOrder::STATUS_VALUE,
+	      function.get_locus ());
+	    break;
+	  case LlvmBuiltinAdapter::FORWARD_ARGUMENTS:
+	    // TODO placeholder
+	    adapter_tree = compile_x86_output_pointer_adapter (
+	      ctx, fntype, resolved, OutputTupleOrder::STATUS_VALUE,
+	      function.get_locus ());
+	    break;
+	  }
+
+	if (adapter_tree == error_mark_node)
+	  {
+	    rust_error_at (function.get_locus (),
+			   "Invalid signature for LLVM intrinsic %qs",
+			   asm_name.c_str ());
+	    reference = error_mark_node;
+	    return;
+	  }
+
+	ctx->insert_function_decl (fntype, adapter_tree);
+	reference = address_expression (adapter_tree, ref_locus);
+	return;
+      }
+
     const unsigned int flags = Backend::function_is_declaration;
     tree fndecl = Backend::function (compiled_fn_type, ir_symbol_name, asm_name,
 				     flags, function.get_locus ());
@@ -144,6 +209,12 @@ public:
   }
 
 private:
+  enum class OutputTupleOrder
+  {
+    VALUE_STATUS,
+    STATUS_VALUE,
+  };
+
   CompileExternItem (Context *ctx, TyTy::BaseType *concrete,
 		     location_t ref_locus)
     : HIRCompileBase (ctx), concrete (concrete), reference (error_mark_node),
@@ -180,6 +251,148 @@ private:
     return obj.get_item_name ();
   }
 
+  /**
+   * Compiles a wrapper that wraps around GCC built-ins for compatibility
+   * with LLVM built-ins function signatures returning a tuple with value +
+   * status.
+   *
+   * @param ctx
+   * @param fntype the LLVM built-in function type
+   * @param gcc_builtin the GCC built-in function
+   * @param order whether the LLVM built-in returns (value, status) or (status,
+   * value)
+   * @param locus
+   * @return tree
+   */
+  static tree compile_x86_output_pointer_adapter (Context *ctx,
+						  TyTy::FnType *fntype,
+						  tree gcc_builtin,
+						  OutputTupleOrder order,
+						  location_t locus)
+  {
+    // expect to be a 2-field tuple return type
+    TyTy::TupleType *tuple
+      = fntype->get_return_type ()->try_as<TyTy::TupleType> ();
+
+    if (tuple == nullptr || tuple->num_fields () != 2)
+      // TODO probably add error here
+      return error_mark_node;
+
+    tree compiled_fn_type = TyTyResolveCompile::compile (ctx, fntype);
+
+    const auto &path = fntype->get_ident ().path;
+    std::string ir_name = path.get () + fntype->subst_as_string ();
+    std::string asm_name = ctx->mangle_item (fntype, path);
+
+    // start building the wrapper function
+    tree fndecl
+      = Backend::function (compiled_fn_type, ir_name, asm_name, 0, locus);
+
+    TREE_PUBLIC (fndecl) = 0;
+    DECL_ARTIFICIAL (fndecl) = 1;
+    DECL_EXTERNAL (fndecl) = 0;
+    DECL_DECLARED_INLINE_P (fndecl) = 1;
+
+    // compile params for the rust wrapper
+    std::vector<Bvariable *> param_vars;
+    param_vars.reserve (fntype->get_params ().size ());
+    for (auto &param : fntype->get_params ())
+      {
+	auto &pattern = param.get_pattern ();
+	tree type = TyTyResolveCompile::compile (ctx, param.get_type ());
+	Bvariable *variable
+	  = CompileFnParam::compile (ctx, fndecl, pattern, type,
+				     pattern.get_locus ());
+	param_vars.emplace_back (variable);
+      }
+
+    if (!Backend::function_set_parameters (fndecl, param_vars))
+      return error_mark_node;
+
+    // forward the rust params, convert each into the corresponding gcc
+    // built-in param type
+    std::vector<tree> call_arguments;
+    // +1 here because gcc built-in expects output pointer as param
+    call_arguments.reserve (param_vars.size () + 1);
+    tree gcc_argument_types = TYPE_ARG_TYPES (TREE_TYPE (gcc_builtin));
+    for (Bvariable *param : param_vars)
+      {
+	tree argument = param->get_tree (locus);
+	tree expected_type = TREE_VALUE (gcc_argument_types);
+	argument = Backend::convert_expression (expected_type, argument, locus);
+	call_arguments.emplace_back (argument);
+	gcc_argument_types = TREE_CHAIN (gcc_argument_types);
+      }
+
+    // the order of llvm built-ins' tuple return types' fields is not
+    // consistent, some are (value, status) and others are (status, value), so
+    // we need to reorder it...
+    tree tuple_type = TREE_TYPE (DECL_RESULT (fndecl));
+    tree first_field = TYPE_FIELDS (tuple_type);
+    tree second_field = DECL_CHAIN (first_field);
+
+    tree value_field
+      = order == OutputTupleOrder::VALUE_STATUS ? first_field : second_field;
+    tree status_field
+      = order == OutputTupleOrder::VALUE_STATUS ? second_field : first_field;
+
+    tree value_type = TREE_TYPE (value_field);
+    tree status_type = TREE_TYPE (status_field);
+
+    tree temporary_stmt = NULL_TREE;
+    Bvariable *value
+      = Backend::temporary_variable (fndecl, NULL_TREE, value_type, NULL_TREE,
+				     true, locus, &temporary_stmt);
+    Bvariable *status
+      = Backend::temporary_variable (fndecl, NULL_TREE, status_type, NULL_TREE,
+				     false, locus, &temporary_stmt);
+
+    // compile the final gcc built-in param which is the output value pointer,
+    // which llvm returns as part of the tuple return type
+    tree gcc_pointer_type = TREE_VALUE (gcc_argument_types);
+    tree block
+      = Backend::block (fndecl, NULL_TREE, {value, status}, locus, locus);
+    ctx->push_block (block);
+
+    tree value_decl = value->get_tree (locus);
+    tree status_decl = status->get_tree (locus);
+
+    tree value_address = build_fold_addr_expr_loc (locus, value_decl);
+    value_address
+      = Backend::convert_expression (gcc_pointer_type, value_address, locus);
+    call_arguments.emplace_back (value_address);
+
+    // call the gcc built-in with the params that were built and assign the
+    // returned val to the status temp var
+    tree builtin_call
+      = build_call_expr_loc_array (locus, gcc_builtin,
+				   static_cast<int> (call_arguments.size ()),
+				   call_arguments.data ());
+    builtin_call
+      = Backend::convert_expression (status_type, builtin_call, locus);
+    ctx->add_statement (
+      Backend::assignment_statement (status_decl, builtin_call, locus));
+
+    // finally compile and add the return statement
+    std::vector<tree> tuple_values;
+    if (order == OutputTupleOrder::VALUE_STATUS)
+      tuple_values = {value_decl, status_decl};
+    else
+      tuple_values = {status_decl, value_decl};
+
+    tree tuple_result
+      = Backend::constructor_expression (tuple_type, false, tuple_values, -1,
+					 locus);
+    ctx->add_statement (
+      Backend::return_statement (fndecl, tuple_result, locus));
+
+    tree body = ctx->pop_block ();
+    DECL_SAVED_TREE (fndecl) = body;
+
+    ctx->push_function (fndecl);
+    return fndecl;
+  }
+
   TyTy::BaseType *concrete;
   tree reference;
   location_t ref_locus;
diff --git a/gcc/rust/rust-lang.cc b/gcc/rust/rust-lang.cc
index dc39bc053..52f6e5a5b 100644
--- a/gcc/rust/rust-lang.cc
+++ b/gcc/rust/rust-lang.cc
@@ -38,6 +38,7 @@
 #include "optional.h"
 #include "rust-unicode.h"
 #include "rust-punycode.h"
+#include "rust-builtins.h"
 
 #include <mpfr.h>
 // note: header files must be in this order or else forward declarations don't
@@ -226,10 +227,11 @@ grs_langhook_type_for_mode (machine_mode mode, int unsignedp)
   return NULL;
 }
 
-// Record a builtin function. We just ignore builtin functions.
+// Record a builtin function.
 static tree
-grs_langhook_builtin_function (tree decl ATTRIBUTE_UNUSED)
+grs_langhook_builtin_function (tree decl)
 {
+  Rust::Compile::BuiltinsContext::get ().register_builtin (decl);
   return decl;
 }
 
diff --git a/gcc/testsuite/rust/compile/llvm_builtins.rs b/gcc/testsuite/rust/compile/llvm_builtins.rs
new file mode 100644
index 000000000..6503c0be2
--- /dev/null
+++ b/gcc/testsuite/rust/compile/llvm_builtins.rs
@@ -0,0 +1,50 @@
+// { dg-options "-mrdrnd" }
+#![feature(no_core, abi_unadjusted)]
+#![no_core]
+
+#[allow(improper_ctypes)]
+extern "unadjusted" {
+    #[link_name = "llvm.x86.rdrand.16"]
+    fn x86_rdrand16_step() -> (u16, i32);
+    #[link_name = "llvm.x86.rdrand.32"]
+    fn x86_rdrand32_step() -> (u32, i32);
+    #[link_name = "llvm.x86.rdrand.64"]
+    fn x86_rdrand64_step() -> (u64, i32);
+    #[link_name = "llvm.x86.rdseed.16"]
+    fn x86_rdseed16_step() -> (u16, i32);
+    #[link_name = "llvm.x86.rdseed.32"]
+    fn x86_rdseed32_step() -> (u32, i32);
+    #[link_name = "llvm.x86.rdseed.64"]
+    fn x86_rdseed64_step() -> (u64, i32);
+
+    #[link_name = "llvm.x86.addcarry.32"]
+    fn llvm_addcarry_u32(a: u8, b: u32, c: u32) -> (u8, u32);
+    // #[link_name = "llvm.x86.addcarryx.u32"]
+    // fn llvm_addcarryx_u32(a: u8, b: u32, c: u32, d: *mut u8) -> u8;
+    #[link_name = "llvm.x86.subborrow.32"]
+    fn llvm_subborrow_u32(a: u8, b: u32, c: u32) -> (u8, u32);
+    #[link_name = "llvm.x86.addcarry.64"]
+    fn llvm_addcarry_u64(a: u8, b: u64, c: u64) -> (u8, u64);
+    // #[link_name = "llvm.x86.addcarryx.u64"]
+    // fn llvm_addcarryx_u64(a: u8, b: u64, c: u64, d: *mut u8) -> u8;
+    #[link_name = "llvm.x86.subborrow.64"]
+    fn llvm_subborrow_u64(a: u8, b: u64, c: u64) -> (u8, u64);
+
+    // #[link_name = "llvm.x86.vcvtph2ps.128"]
+    // fn llvm_vcvtph2ps_128(a: i16x8) -> f32x4;
+    // #[link_name = "llvm.x86.vcvtph2ps.256"]
+    // fn llvm_vcvtph2ps_256(a: i16x8) -> f32x8;
+    // #[link_name = "llvm.x86.vcvtps2ph.128"]
+    // fn llvm_vcvtps2ph_128(a: f32x4, rounding: i32) -> i16x8;
+    // #[link_name = "llvm.x86.vcvtps2ph.256"]
+    // fn llvm_vcvtps2ph_256(a: f32x8, rounding: i32) -> i16x8;
+}
+
+fn main() {
+    let (_status2, _v1) = unsafe {
+        llvm_addcarry_u32(0, 1, 2)
+    };
+    let (_v2, _status2) = unsafe {
+        x86_rdrand16_step()
+    };
+}
-- 
2.55.0



More information about the Gcc-rust mailing list