Skip to content

gccrs: Support some LLVM builtin functions - #4809

Merged
philberty merged 4 commits into
Rust-GCC:masterfrom
Polygonalr:llvm-extern2
Aug 31, 2026
Merged

gccrs: Support some LLVM builtin functions#4809
philberty merged 4 commits into
Rust-GCC:masterfrom
Polygonalr:llvm-extern2

Conversation

@Polygonalr

@Polygonalr Polygonalr commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

Closes #4818, currently it only supports the rdrand and rdseed functions, I'll need to write more function adapters to support other LLVM built-ins.

In theory it should support all the LLVM built-ins used in stdarch, though llvm.x86.vcvtph2ps and llvm.x86.vcvtps2ph requires the SIMD types to be compiled as well (which will also be compiled as part of core_arch within stdarch).

@Polygonalr
Polygonalr marked this pull request as draft August 23, 2026 08:07
@powerboat9

Copy link
Copy Markdown
Collaborator

Could you replace "frontend" in your first commit with "front end"? Also, you should probably replace the mention of (BuiltinsContext) with a mention of (BuiltinsContext::get) and a (BuiltinsContext::BuiltinsContext): Likewise..

This is part of making LLVM builtins work for gccrs.

gcc/rust/ChangeLog:

	* backend/rust-builtins.h (BuiltinsContext::SetupState): New enum.
	* backend/rust-builtins.cc (BuiltinsContext::get): Ensure that BuiltinsContext is only
	initialized once.
	(BuiltinsContext::BuiltinsContext): Likewise.
	(BuiltinsContext::setup): Call targetm.init_builtins to make GCC builtins available
	to the frontend.
	* rust-gcc.cc (init): Eagerly initialize BuiltinsContext.

Signed-Off-By: 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>
…res with GCC built-ins

Similar to the previous commit, but for FORWARD_ARGUMENTS cases in CompileExternItem::visit
(ExternalFunctionItem). Compiled 006t.original output from compiling llvm_builtins.rs for only
the enabled FORWARD_ARGUMENT cases ():

```
u8 llvm_addcarryx_u32 (const u8 a, const u32 b, const u32 c, u8 * const {ref-all} d)
{
  return (u8) __builtin_ia32_addcarryx_u32 ((unsigned char) a, (u32) b, (u32) c, (u32 *) d);
}

u8 llvm_addcarryx_u64 (const u8 a, const u64 b, const u64 c, u8 * const {ref-all} d)
{
  return (u8) __builtin_ia32_addcarryx_u64 ((unsigned char) a, (unsigned long) b, (unsigned long) c, (unsigned long *) d);
}
```

vcvtph2ps and vcvtps2ph functions are not supported yet as gccrs doesn't support SIMD types yet.

gcc/rust/ChangeLog:

	* backend/rust-builtins.cc (BuiltinsContext::register_llvm_to_gcc_builtin): Add entries
	for vcvtph2ps & vcvtps2ph cases (currently unused due to the reason mentioned above).
	* backend/rust-compile-extern.h (CompileExternItem::visit(HIR::ExternalFunctionItem)):
	Remove placeholder function in the FORWARD_ARGUMENTS case under compilation of UNADJUSTED
	ABI.
	(CompileExternItem::compile_x86_forwarding_adapter): New function to adapt LLVM's addcarryx
	function signatures by simply forwarding the parameters and return var without changes.

gcc/testsuite/ChangeLog:

	* rust/compile/llvm_builtins.rs: Enable addcarryx cases, add TODO comment for vcvtph2ps &
	vcvtps2ph cases.

Signed-off-by: Yap Zhi Heng <yapzhhg@gmail.com>
@Polygonalr
Polygonalr marked this pull request as ready for review August 29, 2026 08:27
@Polygonalr

Copy link
Copy Markdown
Contributor Author

Tests are not final yet.

  • It seems like tests on the 32-bit arches are failing due to not having 64-bit built-ins such as __builtin_ia32_rdrand64_step and __builtin_ia32_rdseed_di_step, wondering if I should remove them or find a way to exclude these functions from the 32-bit arches.
  • I'll also need to include some dg-final directives in my tests similar to what I did in #[repr(transparent)] initial implementation #4650.

@powerboat9

Copy link
Copy Markdown
Collaborator

I think the test should probably be restricted to run only on x86_64

@Polygonalr
Polygonalr force-pushed the llvm-extern2 branch 2 times, most recently from 3329098 to e92e3a6 Compare August 30, 2026 11:43
gcc/testsuite/ChangeLog:

	* rust/compile/llvm_builtins.rs: Removed 64-bit functions, ensure main calls all llvm
	built-ins, add dg-final directives to check the generated tree dump, ensure the test
	only gets compiled on x86 targets.
	* rust/compile/llvm_builtins_64_bit.rs: New test derived from llvm_builtins.rs, but
	for 64-bit functions.

Signed-off-by: Yap Zhi Heng <yapzhhg@gmail.com>

@philberty philberty left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

#[link_name = "llvm.x86.subborrow.32"]
fn llvm_subborrow_u32(a: u8, b: u32, c: u32) -> (u8, u32);

// TODO implement the SIMD types (i16x8, f32x4, f32x8) before

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

repr simd should be there they will be VECTOR_TYPES which are basically structs in a lot of ways

@philberty
philberty added this pull request to the merge queue Aug 31, 2026
Merged via the queue into Rust-GCC:master with commit 63ea23d Aug 31, 2026
13 of 14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Compile UNADJUSTED ABI extern functions

3 participants