https://github.com/fileho created https://github.com/llvm/llvm-project/pull/175439
Add support for rdrand and rdseed builtins. Part of #167765 From 54dd8c6cf38ca5267a7c1665234541542790155d Mon Sep 17 00:00:00 2001 From: Jiri Filek <[email protected]> Date: Sun, 11 Jan 2026 15:27:22 +0100 Subject: [PATCH] [CIR][X86] Implement rdrand/rdseed builtins --- clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp | 46 +++++- .../CIR/CodeGenBuiltins/X86/rdrand-builtins.c | 146 ++++++++++++++++++ 2 files changed, 191 insertions(+), 1 deletion(-) create mode 100644 clang/test/CIR/CodeGenBuiltins/X86/rdrand-builtins.c 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 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
