[clang] [CIR][X86] Implement rdrand/rdseed builtins (PR #175439)
via cfe-commits
cfe-commits at lists.llvm.org
Sun Jan 11 06:57:29 PST 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Jiří Filek (fileho)
<details>
<summary>Changes</summary>
Add support for rdrand and rdseed builtins.
Part of #<!-- -->167765
---
Full diff: https://github.com/llvm/llvm-project/pull/175439.diff
2 Files Affected:
- (modified) clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp (+45-1)
- (added) clang/test/CIR/CodeGenBuiltins/X86/rdrand-builtins.c (+146)
``````````diff
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp
index eeecc9cdaa741..c6c5eebde1d29 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp
@@ -1818,7 +1818,51 @@ CIRGenFunction::emitX86BuiltinExpr(unsigned builtinID, const CallExpr *expr) {
case X86::BI__builtin_ia32_rdrand64_step:
case X86::BI__builtin_ia32_rdseed16_step:
case X86::BI__builtin_ia32_rdseed32_step:
- case X86::BI__builtin_ia32_rdseed64_step:
+ case X86::BI__builtin_ia32_rdseed64_step: {
+ llvm::StringRef intrinsicName;
+ switch (builtinID) {
+ default:
+ llvm_unreachable("Unsupported intrinsic!");
+ case X86::BI__builtin_ia32_rdrand16_step:
+ intrinsicName = "x86.rdrand.16";
+ break;
+ case X86::BI__builtin_ia32_rdrand32_step:
+ intrinsicName = "x86.rdrand.32";
+ break;
+ case X86::BI__builtin_ia32_rdrand64_step:
+ intrinsicName = "x86.rdrand.64";
+ break;
+ case X86::BI__builtin_ia32_rdseed16_step:
+ intrinsicName = "x86.rdseed.16";
+ break;
+ case X86::BI__builtin_ia32_rdseed32_step:
+ intrinsicName = "x86.rdseed.32";
+ break;
+ case X86::BI__builtin_ia32_rdseed64_step:
+ intrinsicName = "x86.rdseed.64";
+ break;
+ }
+
+ mlir::Location loc = getLoc(expr->getExprLoc());
+ mlir::Type randTy = cast<cir::PointerType>(ops[0].getType()).getPointee();
+ llvm::SmallVector<mlir::Type, 2> resultTypes = {randTy,
+ builder.getUInt32Ty()};
+ cir::RecordType resRecord =
+ cir::RecordType::get(&getMLIRContext(), resultTypes, false, false,
+ cir::RecordType::RecordKind::Struct);
+
+ mlir::Value call =
+ emitIntrinsicCallOp(builder, loc, intrinsicName, resRecord);
+ mlir::Value rand =
+ cir::ExtractMemberOp::create(builder, loc, randTy, call, 0);
+ Address addr =
+ Address(ops[0], clang::CharUnits::fromQuantity(
+ builder.getCIRIntOrFloatBitWidth(randTy) / 8));
+ builder.createStore(loc, rand, addr);
+
+ return cir::ExtractMemberOp::create(builder, loc, builder.getUInt32Ty(),
+ call, 1);
+ }
case X86::BI__builtin_ia32_addcarryx_u32:
case X86::BI__builtin_ia32_addcarryx_u64:
case X86::BI__builtin_ia32_subborrow_u32:
diff --git a/clang/test/CIR/CodeGenBuiltins/X86/rdrand-builtins.c b/clang/test/CIR/CodeGenBuiltins/X86/rdrand-builtins.c
new file mode 100644
index 0000000000000..bd4c49050477c
--- /dev/null
+++ b/clang/test/CIR/CodeGenBuiltins/X86/rdrand-builtins.c
@@ -0,0 +1,146 @@
+// RUN: %clang_cc1 -x c -ffreestanding -triple x86_64-unknown-linux -target-feature +rdrnd -target-feature +rdseed -Wno-implicit-function-declaration -fclangir -emit-cir -o %t.cir %s
+// RUN: FileCheck --check-prefixes=CIR,CIR-X64 --input-file=%t.cir %s
+// RUN: %clang_cc1 -x c++ -ffreestanding -triple x86_64-unknown-linux -target-feature +rdrnd -target-feature +rdseed -Wno-implicit-function-declaration -fclangir -emit-cir -o %t.cir %s
+// RUN: FileCheck --check-prefixes=CIR,CIR-X64 --input-file=%t.cir %s
+
+// RUN: %clang_cc1 -x c -ffreestanding -triple x86_64-unknown-linux -target-feature +rdrnd -target-feature +rdseed -Wno-implicit-function-declaration -fclangir -emit-llvm -o %t.ll %s
+// RUN: FileCheck --check-prefixes=LLVM,LLVM-X64 --input-file=%t.ll %s
+// RUN: %clang_cc1 -x c++ -ffreestanding -triple x86_64-unknown-linux -target-feature +rdrnd -target-feature +rdseed -Wno-implicit-function-declaration -fclangir -emit-llvm -o %t.ll %s
+// RUN: FileCheck --check-prefixes=LLVM,LLVM-X64 --input-file=%t.ll %s
+
+// RUN: %clang_cc1 -x c -ffreestanding -triple=x86_64-unknown-linux -target-feature +rdrnd -target-feature +rdseed -emit-llvm -Wall -Werror %s -o - | FileCheck %s -check-prefixes=OGCG,OGCG-X64
+// RUN: %clang_cc1 -x c++ -ffreestanding -triple=x86_64-unknown-linux -target-feature +rdrnd -target-feature +rdseed -emit-llvm -Wall -Werror %s -o - | FileCheck %s -check-prefixes=OGCG,OGCG-X64
+
+// 32-bit tests for _rdrand64_step()
+// RUN: %clang_cc1 -x c -ffreestanding -triple i386-unknown-linux -target-feature +rdrnd -target-feature +rdseed -Wno-implicit-function-declaration -fclangir -emit-cir -o %t.cir %s
+// RUN: FileCheck --check-prefixes=CIR,CIR-X86 --input-file=%t.cir %s
+// RUN: %clang_cc1 -x c -ffreestanding -triple i386-unknown-linux -target-feature +rdrnd -target-feature +rdseed -Wno-implicit-function-declaration -fclangir -emit-llvm -o %t.ll %s
+// RUN: FileCheck --check-prefixes=LLVM,LLVM-X86 --input-file=%t.ll %s
+// RUN: %clang_cc1 -x c -ffreestanding -triple=i386-unknown-linux -target-feature +rdrnd -target-feature +rdseed -emit-llvm -Wall -Werror %s -o - | FileCheck %s -check-prefixes=OGCG,OGCG-X86
+
+// This test mimics clang/test/CodeGen/X86/rdrand-builtins.c
+
+#include <immintrin.h>
+
+int test_rdrand16(unsigned short *p) {
+ // CIR-LABEL: rdrand16
+ // CIR: {{%.*}} = cir.call_llvm_intrinsic "x86.rdrand.16"
+ // CIR: {{%.*}} = cir.extract_member {{%.*}}[0]
+ // CIR: cir.store align(2) {{%.*}}, {{%.*}} : !u16i, !cir.ptr<!u16i>
+ // CIR: {{%.*}} = cir.extract_member {{%.*}}[1]
+ // LLVM-LABEL: rdrand16
+ // LLVM: call { i16, i32 } @llvm.x86.rdrand.16
+ // LLVM: extractvalue { i16, i32 } {{%.*}}, 0
+ // LLVM: store i16
+ // LLVM: extractvalue { i16, i32 } {{%.*}}, 1
+ // OGCG-LABEL: rdrand16
+ // OGCG: call { i16, i32 } @llvm.x86.rdrand.16
+ // OGCG: extractvalue { i16, i32 } {{%.*}}, 0
+ // OGCG: store i16
+ // OGCG: extractvalue { i16, i32 } {{%.*}}, 1
+ return _rdrand16_step(p);
+}
+
+int test_rdrand32(unsigned *p) {
+ // CIR-LABEL: rdrand32
+ // CIR: {{%.*}} = cir.call_llvm_intrinsic "x86.rdrand.32"
+ // CIR: {{%.*}} = cir.extract_member {{%.*}}[0]
+ // CIR: cir.store align(4) {{%.*}}, {{%.*}} : !u32i, !cir.ptr<!u32i>
+ // CIR: {{%.*}} = cir.extract_member {{%.*}}[1]
+ // LLVM-LABEL: rdrand32
+ // LLVM: call { i32, i32 } @llvm.x86.rdrand.32
+ // LLVM: extractvalue { i32, i32 } {{%.*}}, 0
+ // LLVM: store i32
+ // LLVM: extractvalue { i32, i32 } {{%.*}}, 1
+ // OGCG-LABEL: rdrand32
+ // OGCG: call { i32, i32 } @llvm.x86.rdrand.32
+ // OGCG: extractvalue { i32, i32 } {{%.*}}, 0
+ // OGCG: store i32
+ // OGCG: extractvalue { i32, i32 } {{%.*}}, 1
+ return _rdrand32_step(p);
+}
+
+int test_rdrand64(unsigned long long *p) {
+ // CIR-LABEL: rdrand64
+ // CIR-X64: {{%.*}} = cir.call_llvm_intrinsic "x86.rdrand.64"
+ // CIR-X64: {{%.*}} = cir.extract_member {{%.*}}[0]
+ // CIR-X64: cir.store align(8) {{%.*}}, {{%.*}} : !u64i, !cir.ptr<!u64i>
+ // CIR-X64: {{%.*}} = cir.extract_member {{%.*}}[1]
+ // LLVM-LABEL: rdrand64
+ // LLVM-X64: call { i64, i32 } @llvm.x86.rdrand.64
+ // LLVM-X64: extractvalue { i64, i32 } {{%.*}}, 0
+ // LLVM-X64: store i64
+ // LLVM-X64: extractvalue { i64, i32 } {{%.*}}, 1
+ // OGCG-LABEL: rdrand64
+ // OGCG-X64: call { i64, i32 } @llvm.x86.rdrand.64
+ // OGCG-X64: extractvalue { i64, i32 } {{%.*}}, 0
+ // OGCG-X64: store i64
+ // OGCG-X64: extractvalue { i64, i32 } {{%.*}}, 1
+
+ // CIR-X86: {{%.*}} = cir.call_llvm_intrinsic "x86.rdrand.32"
+ // CIR-X86: {{%.*}} = cir.call_llvm_intrinsic "x86.rdrand.32"
+ // LLVM-X86: call { i32, i32 } @llvm.x86.rdrand.32
+ // LLVM-X86: call { i32, i32 } @llvm.x86.rdrand.32
+ // OGCG-X86: call { i32, i32 } @llvm.x86.rdrand.32
+ // OGCG-X86: call { i32, i32 } @llvm.x86.rdrand.32
+ return _rdrand64_step(p);
+}
+
+int test_rdseed16(unsigned short *p) {
+ // CIR-LABEL: rdseed16
+ // CIR: {{%.*}} = cir.call_llvm_intrinsic "x86.rdseed.16"
+ // CIR: {{%.*}} = cir.extract_member {{%.*}}[0]
+ // CIR: cir.store align(2) {{%.*}}, {{%.*}} : !u16i, !cir.ptr<!u16i>
+ // CIR: {{%.*}} = cir.extract_member {{%.*}}[1]
+ // LLVM-LABEL: rdseed16
+ // LLVM: call { i16, i32 } @llvm.x86.rdseed.16
+ // LLVM: extractvalue { i16, i32 } {{%.*}}, 0
+ // LLVM: store i16
+ // LLVM: extractvalue { i16, i32 } {{%.*}}, 1
+ // OGCG-LABEL: rdseed16
+ // OGCG: call { i16, i32 } @llvm.x86.rdseed.16
+ // OGCG: extractvalue { i16, i32 } {{%.*}}, 0
+ // OGCG: store i16
+ // OGCG: extractvalue { i16, i32 } {{%.*}}, 1
+ return _rdseed16_step(p);
+}
+
+int test_rdseed32(unsigned *p) {
+ // CIR-LABEL: rdseed32
+ // CIR: {{%.*}} = cir.call_llvm_intrinsic "x86.rdseed.32"
+ // CIR: {{%.*}} = cir.extract_member {{%.*}}[0]
+ // CIR: cir.store align(4) {{%.*}}, {{%.*}} : !u32i, !cir.ptr<!u32i>
+ // CIR: {{%.*}} = cir.extract_member {{%.*}}[1]
+ // LLVM-LABEL: rdseed32
+ // LLVM: call { i32, i32 } @llvm.x86.rdseed.32
+ // LLVM: extractvalue { i32, i32 } {{%.*}}, 0
+ // LLVM: store i32
+ // LLVM: extractvalue { i32, i32 } {{%.*}}, 1
+ // OGCG-LABEL: rdseed32
+ // OGCG: call { i32, i32 } @llvm.x86.rdseed.32
+ // OGCG: extractvalue { i32, i32 } {{%.*}}, 0
+ // OGCG: store i32
+ // OGCG: extractvalue { i32, i32 } {{%.*}}, 1
+ return _rdseed32_step(p);
+}
+
+#if __x86_64__
+int test_rdseed64(unsigned long long *p) {
+ // CIR-X64-LABEL: rdseed64
+ // CIR-X64: {{%.*}} = cir.call_llvm_intrinsic "x86.rdseed.64"
+ // CIR-X64: {{%.*}} = cir.extract_member {{%.*}}[0]
+ // CIR-X64: cir.store align(8) {{%.*}}, {{%.*}} : !u64i, !cir.ptr<!u64i>
+ // CIR-X64: {{%.*}} = cir.extract_member {{%.*}}[1]
+ // LLVM-X64-LABEL: rdseed64
+ // LLVM-X64: call { i64, i32 } @llvm.x86.rdseed.64
+ // LLVM-X64: extractvalue { i64, i32 } {{%.*}}, 0
+ // LLVM-X64: store i64
+ // LLVM-X64: extractvalue { i64, i32 } {{%.*}}, 1
+ // OGCG-X64-LABEL: rdseed64
+ // OGCG-X64: call { i64, i32 } @llvm.x86.rdseed.64
+ // OGCG-X64: extractvalue { i64, i32 } {{%.*}}, 0
+ // OGCG-X64: store i64
+ // OGCG-X64: extractvalue { i64, i32 } {{%.*}}, 1
+ return _rdseed64_step(p);
+}
+#endif
``````````
</details>
https://github.com/llvm/llvm-project/pull/175439
More information about the cfe-commits
mailing list