[clang] 019a294 - [CIR][X86] Implement xsave/xrstor builtins Fixes part of #167752 (#170877)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Dec 9 12:49:46 PST 2025
Author: Medha Tiwari
Date: 2025-12-09T12:49:42-08:00
New Revision: 019a2947719b979a4192ad4baa96e155e240f145
URL: https://github.com/llvm/llvm-project/commit/019a2947719b979a4192ad4baa96e155e240f145
DIFF: https://github.com/llvm/llvm-project/commit/019a2947719b979a4192ad4baa96e155e240f145.diff
LOG: [CIR][X86] Implement xsave/xrstor builtins Fixes part of #167752 (#170877)
Handle xsave/xrstor family of X86 builtins in ClangIR
Part of #167752
---------
Signed-off-by: Medha Tiwari <medhatiwari at ibm.com>
Added:
clang/test/CIR/CodeGenBuiltins/X86/xsave-builtins.c
Modified:
clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp
Removed:
################################################################################
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp
index 855134ba2b249..62836ce0f7537 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp
@@ -544,9 +544,78 @@ mlir::Value CIRGenFunction::emitX86BuiltinExpr(unsigned builtinID,
case X86::BI__builtin_ia32_xsaves:
case X86::BI__builtin_ia32_xsaves64:
case X86::BI__builtin_ia32_xsetbv:
- case X86::BI_xsetbv:
+ case X86::BI_xsetbv: {
+ mlir::Location loc = getLoc(expr->getExprLoc());
+ StringRef intrinsicName;
+ switch (builtinID) {
+ default:
+ llvm_unreachable("Unexpected builtin");
+ case X86::BI__builtin_ia32_xsave:
+ intrinsicName = "x86.xsave";
+ break;
+ case X86::BI__builtin_ia32_xsave64:
+ intrinsicName = "x86.xsave64";
+ break;
+ case X86::BI__builtin_ia32_xrstor:
+ intrinsicName = "x86.xrstor";
+ break;
+ case X86::BI__builtin_ia32_xrstor64:
+ intrinsicName = "x86.xrstor64";
+ break;
+ case X86::BI__builtin_ia32_xsaveopt:
+ intrinsicName = "x86.xsaveopt";
+ break;
+ case X86::BI__builtin_ia32_xsaveopt64:
+ intrinsicName = "x86.xsaveopt64";
+ break;
+ case X86::BI__builtin_ia32_xrstors:
+ intrinsicName = "x86.xrstors";
+ break;
+ case X86::BI__builtin_ia32_xrstors64:
+ intrinsicName = "x86.xrstors64";
+ break;
+ case X86::BI__builtin_ia32_xsavec:
+ intrinsicName = "x86.xsavec";
+ break;
+ case X86::BI__builtin_ia32_xsavec64:
+ intrinsicName = "x86.xsavec64";
+ break;
+ case X86::BI__builtin_ia32_xsaves:
+ intrinsicName = "x86.xsaves";
+ break;
+ case X86::BI__builtin_ia32_xsaves64:
+ intrinsicName = "x86.xsaves64";
+ break;
+ case X86::BI__builtin_ia32_xsetbv:
+ case X86::BI_xsetbv:
+ intrinsicName = "x86.xsetbv";
+ break;
+ }
+
+ // The xsave family of instructions take a 64-bit mask that specifies
+ // which processor state components to save/restore. The hardware expects
+ // this mask split into two 32-bit registers: EDX (high 32 bits) and
+ // EAX (low 32 bits).
+ mlir::Type i32Ty = builder.getSInt32Ty();
+
+ // Mhi = (uint32_t)(ops[1] >> 32) - extract high 32 bits via right shift
+ cir::ConstantOp shift32 = builder.getSInt64(32, loc);
+ mlir::Value mhi = builder.createShift(loc, ops[1], shift32.getResult(),
+ /*isShiftLeft=*/false);
+ mhi = builder.createIntCast(mhi, i32Ty);
+
+ // Mlo = (uint32_t)ops[1] - extract low 32 bits by truncation
+ mlir::Value mlo = builder.createIntCast(ops[1], i32Ty);
+
+ return emitIntrinsicCallOp(builder, loc, intrinsicName, voidTy,
+ mlir::ValueRange{ops[0], mhi, mlo});
+ }
case X86::BI__builtin_ia32_xgetbv:
case X86::BI_xgetbv:
+ // xgetbv reads the extended control register specified by ops[0] (ECX)
+ // and returns the 64-bit value
+ return emitIntrinsicCallOp(builder, getLoc(expr->getExprLoc()),
+ "x86.xgetbv", builder.getUInt64Ty(), ops[0]);
case X86::BI__builtin_ia32_storedqudi128_mask:
case X86::BI__builtin_ia32_storedqusi128_mask:
case X86::BI__builtin_ia32_storedquhi128_mask:
diff --git a/clang/test/CIR/CodeGenBuiltins/X86/xsave-builtins.c b/clang/test/CIR/CodeGenBuiltins/X86/xsave-builtins.c
new file mode 100644
index 0000000000000..23d6edc6c8c6e
--- /dev/null
+++ b/clang/test/CIR/CodeGenBuiltins/X86/xsave-builtins.c
@@ -0,0 +1,194 @@
+// RUN: %clang_cc1 -x c -ffreestanding %s -triple=x86_64-unknown-linux -target-feature +xsave -target-feature +xsaveopt -target-feature +xsavec -target-feature +xsaves -fclangir -emit-cir -o %t.cir -Wall -Werror
+// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
+// RUN: %clang_cc1 -x c -ffreestanding %s -triple=x86_64-unknown-linux -target-feature +xsave -target-feature +xsaveopt -target-feature +xsavec -target-feature +xsaves -fclangir -emit-llvm -o %t.ll -Wall -Werror
+// RUN: FileCheck --check-prefixes=LLVM --input-file=%t.ll %s
+
+// RUN: %clang_cc1 -x c -ffreestanding %s -triple=x86_64-unknown-linux -target-feature +xsave -target-feature +xsaveopt -target-feature +xsavec -target-feature +xsaves -emit-llvm -o - -Wall -Werror | FileCheck %s -check-prefix=OGCG
+
+void test_xsave(void *p, unsigned long long m) {
+ // CIR-LABEL: test_xsave
+ // CIR: [[P:%.*]] = cir.load {{.*}} : !cir.ptr<!cir.ptr<!void>>, !cir.ptr<!void>
+ // CIR: [[M:%.*]] = cir.load {{.*}} : !cir.ptr<!u64i>, !u64i
+ // CIR: [[CONST:%.*]] = cir.const #cir.int<32> : !s64i
+ // CIR: [[SHIFT:%.*]] = cir.shift(right, [[M]] : !u64i, [[CONST]] : !s64i) -> !u64i
+ // CIR: [[CAST1:%.*]] = cir.cast integral [[SHIFT]] : !u64i -> !s32i
+ // CIR: [[CAST2:%.*]] = cir.cast integral [[M]] : !u64i -> !s32i
+ // CIR: cir.call_llvm_intrinsic "x86.xsave" [[P]], [[CAST1]], [[CAST2]]
+
+ // LLVM-LABEL: test_xsave
+ // LLVM: [[LP:%.*]] = load ptr, ptr
+ // LLVM: [[LM:%.*]] = load i64, ptr
+ // LLVM: [[LSHIFT:%.*]] = lshr i64 [[LM]], 32
+ // LLVM: [[LCAST1:%.*]] = trunc i64 [[LSHIFT]] to i32
+ // LLVM: [[LCAST2:%.*]] = trunc i64 [[LM]] to i32
+ // LLVM: call void @llvm.x86.xsave(ptr [[LP]], i32 [[LCAST1]], i32 [[LCAST2]])
+
+ // OGCG-LABEL: test_xsave
+ // OGCG: [[OP:%.*]] = load ptr, ptr
+ // OGCG: [[OM:%.*]] = load i64, ptr
+ // OGCG: [[OSHIFT:%.*]] = lshr i64 [[OM]], 32
+ // OGCG: [[OCAST1:%.*]] = trunc i64 [[OSHIFT]] to i32
+ // OGCG: [[OCAST2:%.*]] = trunc i64 [[OM]] to i32
+ // OGCG: call void @llvm.x86.xsave(ptr [[OP]], i32 [[OCAST1]], i32 [[OCAST2]])
+ __builtin_ia32_xsave(p, m);
+}
+
+// The following tests use the same pattern as test_xsave (load, shift, cast, cast, intrinsic call).
+// Only the intrinsic name
diff ers, so we just check the intrinsic call.
+
+void test_xsave64(void *p, unsigned long long m) {
+ // CIR-LABEL: test_xsave64
+ // CIR: cir.call_llvm_intrinsic "x86.xsave64"
+
+ // LLVM-LABEL: test_xsave64
+ // LLVM: call void @llvm.x86.xsave64
+
+ // OGCG-LABEL: test_xsave64
+ // OGCG: call void @llvm.x86.xsave64
+ __builtin_ia32_xsave64(p, m);
+}
+
+void test_xrstor(void *p, unsigned long long m) {
+ // CIR-LABEL: test_xrstor
+ // CIR: cir.call_llvm_intrinsic "x86.xrstor"
+
+ // LLVM-LABEL: test_xrstor
+ // LLVM: call void @llvm.x86.xrstor
+
+ // OGCG-LABEL: test_xrstor
+ // OGCG: call void @llvm.x86.xrstor
+ __builtin_ia32_xrstor(p, m);
+}
+
+void test_xrstor64(void *p, unsigned long long m) {
+ // CIR-LABEL: test_xrstor64
+ // CIR: cir.call_llvm_intrinsic "x86.xrstor64"
+
+ // LLVM-LABEL: test_xrstor64
+ // LLVM: call void @llvm.x86.xrstor64
+
+ // OGCG-LABEL: test_xrstor64
+ // OGCG: call void @llvm.x86.xrstor64
+ __builtin_ia32_xrstor64(p, m);
+}
+
+void test_xsaveopt(void *p, unsigned long long m) {
+ // CIR-LABEL: test_xsaveopt
+ // CIR: cir.call_llvm_intrinsic "x86.xsaveopt"
+
+ // LLVM-LABEL: test_xsaveopt
+ // LLVM: call void @llvm.x86.xsaveopt
+
+ // OGCG-LABEL: test_xsaveopt
+ // OGCG: call void @llvm.x86.xsaveopt
+ __builtin_ia32_xsaveopt(p, m);
+}
+
+void test_xsaveopt64(void *p, unsigned long long m) {
+ // CIR-LABEL: test_xsaveopt64
+ // CIR: cir.call_llvm_intrinsic "x86.xsaveopt64"
+
+ // LLVM-LABEL: test_xsaveopt64
+ // LLVM: call void @llvm.x86.xsaveopt64
+
+ // OGCG-LABEL: test_xsaveopt64
+ // OGCG: call void @llvm.x86.xsaveopt64
+ __builtin_ia32_xsaveopt64(p, m);
+}
+
+void test_xsavec(void *p, unsigned long long m) {
+ // CIR-LABEL: test_xsavec
+ // CIR: cir.call_llvm_intrinsic "x86.xsavec"
+
+ // LLVM-LABEL: test_xsavec
+ // LLVM: call void @llvm.x86.xsavec
+
+ // OGCG-LABEL: test_xsavec
+ // OGCG: call void @llvm.x86.xsavec
+ __builtin_ia32_xsavec(p, m);
+}
+
+void test_xsavec64(void *p, unsigned long long m) {
+ // CIR-LABEL: test_xsavec64
+ // CIR: cir.call_llvm_intrinsic "x86.xsavec64"
+
+ // LLVM-LABEL: test_xsavec64
+ // LLVM: call void @llvm.x86.xsavec64
+
+ // OGCG-LABEL: test_xsavec64
+ // OGCG: call void @llvm.x86.xsavec64
+ __builtin_ia32_xsavec64(p, m);
+}
+
+void test_xsaves(void *p, unsigned long long m) {
+ // CIR-LABEL: test_xsaves
+ // CIR: cir.call_llvm_intrinsic "x86.xsaves"
+
+ // LLVM-LABEL: test_xsaves
+ // LLVM: call void @llvm.x86.xsaves
+
+ // OGCG-LABEL: test_xsaves
+ // OGCG: call void @llvm.x86.xsaves
+ __builtin_ia32_xsaves(p, m);
+}
+
+void test_xsaves64(void *p, unsigned long long m) {
+ // CIR-LABEL: test_xsaves64
+ // CIR: cir.call_llvm_intrinsic "x86.xsaves64"
+
+ // LLVM-LABEL: test_xsaves64
+ // LLVM: call void @llvm.x86.xsaves64
+
+ // OGCG-LABEL: test_xsaves64
+ // OGCG: call void @llvm.x86.xsaves64
+ __builtin_ia32_xsaves64(p, m);
+}
+
+void test_xrstors(void *p, unsigned long long m) {
+ // CIR-LABEL: test_xrstors
+ // CIR: cir.call_llvm_intrinsic "x86.xrstors"
+
+ // LLVM-LABEL: test_xrstors
+ // LLVM: call void @llvm.x86.xrstors
+
+ // OGCG-LABEL: test_xrstors
+ // OGCG: call void @llvm.x86.xrstors
+ __builtin_ia32_xrstors(p, m);
+}
+
+void test_xrstors64(void *p, unsigned long long m) {
+ // CIR-LABEL: test_xrstors64
+ // CIR: cir.call_llvm_intrinsic "x86.xrstors64"
+
+ // LLVM-LABEL: test_xrstors64
+ // LLVM: call void @llvm.x86.xrstors64
+
+ // OGCG-LABEL: test_xrstors64
+ // OGCG: call void @llvm.x86.xrstors64
+ __builtin_ia32_xrstors64(p, m);
+}
+
+unsigned long long test_xgetbv(unsigned int a) {
+ // CIR-LABEL: test_xgetbv
+ // CIR: cir.call_llvm_intrinsic "x86.xgetbv"
+
+ // LLVM-LABEL: test_xgetbv
+ // LLVM: call i64 @llvm.x86.xgetbv
+
+ // OGCG-LABEL: test_xgetbv
+ // OGCG: call i64 @llvm.x86.xgetbv
+ return __builtin_ia32_xgetbv(a);
+}
+
+void test_xsetbv(unsigned int a, unsigned long long m) {
+ // CIR-LABEL: test_xsetbv
+ // CIR: cir.call_llvm_intrinsic "x86.xsetbv"
+
+ // LLVM-LABEL: test_xsetbv
+ // LLVM: call void @llvm.x86.xsetbv
+
+ // OGCG-LABEL: test_xsetbv
+ // OGCG: call void @llvm.x86.xsetbv
+ __builtin_ia32_xsetbv(a, m);
+}
+
More information about the cfe-commits
mailing list