[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 ¶m : 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