[clang] [CIR][X86] Implement xsave/xrstor builtins Fixes part of #167752 (PR #170877)
Medha Tiwari via cfe-commits
cfe-commits at lists.llvm.org
Sat Dec 6 01:53:44 PST 2025
https://github.com/medhatiwari updated https://github.com/llvm/llvm-project/pull/170877
>From e590a91f11e4673920ed56c0da874c9c6a6e9974 Mon Sep 17 00:00:00 2001
From: Medha Tiwari <medhatiwari at ibm.com>
Date: Fri, 5 Dec 2025 21:27:29 +0530
Subject: [PATCH 1/2] [CIR][X86] Implement xsave/xrstor builtins Fixes part of
#167752
---
clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp | 73 +++++++-
.../CIR/CodeGenBuiltins/X86/xsave-builtins.c | 175 ++++++++++++++++++
2 files changed, 247 insertions(+), 1 deletion(-)
create mode 100644 clang/test/CIR/CodeGenBuiltins/X86/xsave-builtins.c
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp
index 1c1ef4da20b0d..26630522de1b0 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp
@@ -533,9 +533,80 @@ 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();
+ mlir::Type i64Ty = builder.getSInt64Ty();
+
+ // Mhi = (uint32_t)(ops[1] >> 32) - extract high 32 bits via right shift
+ cir::ConstantOp shift32 =
+ builder.getConstant(loc, cir::IntAttr::get(i64Ty, 32));
+ mlir::Value mhi =
+ builder.createShift(loc, ops[1], shift32.getResult(), /*isRight=*/true);
+ 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..484f6c402979d
--- /dev/null
+++ b/clang/test/CIR/CodeGenBuiltins/X86/xsave-builtins.c
@@ -0,0 +1,175 @@
+// 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: cir.call_llvm_intrinsic "x86.xsave"
+
+ // LLVM-LABEL: test_xsave
+ // LLVM: call void @llvm.x86.xsave
+
+ // OGCG-LABEL: test_xsave
+ // OGCG: call void @llvm.x86.xsave
+ __builtin_ia32_xsave(p, m);
+}
+
+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);
+}
+
>From 63fa95851c52ad058f705258f2a5eaee9f4263e3 Mon Sep 17 00:00:00 2001
From: Medha Tiwari <medhatiwari at ibm.com>
Date: Sat, 6 Dec 2025 15:23:19 +0530
Subject: [PATCH 2/2] Address review comments
Signed-off-by: Medha Tiwari <medhatiwari at ibm.com>
---
clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp | 6 ++----
clang/test/CIR/CodeGenBuiltins/X86/xsave-builtins.c | 9 ++++++++-
2 files changed, 10 insertions(+), 5 deletions(-)
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp
index 26630522de1b0..be0bf5832b99e 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp
@@ -586,13 +586,11 @@ mlir::Value CIRGenFunction::emitX86BuiltinExpr(unsigned builtinID,
// this mask split into two 32-bit registers: EDX (high 32 bits) and
// EAX (low 32 bits).
mlir::Type i32Ty = builder.getSInt32Ty();
- mlir::Type i64Ty = builder.getSInt64Ty();
// Mhi = (uint32_t)(ops[1] >> 32) - extract high 32 bits via right shift
- cir::ConstantOp shift32 =
- builder.getConstant(loc, cir::IntAttr::get(i64Ty, 32));
+ cir::ConstantOp shift32 = builder.getSInt64(32, loc);
mlir::Value mhi =
- builder.createShift(loc, ops[1], shift32.getResult(), /*isRight=*/true);
+ 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
diff --git a/clang/test/CIR/CodeGenBuiltins/X86/xsave-builtins.c b/clang/test/CIR/CodeGenBuiltins/X86/xsave-builtins.c
index 484f6c402979d..d76bfcb88ef0c 100644
--- a/clang/test/CIR/CodeGenBuiltins/X86/xsave-builtins.c
+++ b/clang/test/CIR/CodeGenBuiltins/X86/xsave-builtins.c
@@ -7,10 +7,17 @@
void test_xsave(void *p, unsigned long long m) {
// CIR-LABEL: test_xsave
+ // CIR: cir.const #cir.int<32> : !s64i
+ // CIR: cir.shift(right, {{.*}} : !u64i, {{.*}} : !s64i) -> !u64i
+ // CIR: cir.cast integral %{{.*}} : !u64i -> !s32i
+ // CIR: cir.cast integral %{{.*}} : !u64i -> !s32i
// CIR: cir.call_llvm_intrinsic "x86.xsave"
// LLVM-LABEL: test_xsave
- // LLVM: call void @llvm.x86.xsave
+ // LLVM: lshr i64 {{.*}}, 32
+ // LLVM: trunc i64 {{.*}} to i32
+ // LLVM: trunc i64 {{.*}} to i32
+ // LLVM: call void @llvm.x86.xsave(ptr {{.*}}, i32 {{.*}}, i32 {{.*}})
// OGCG-LABEL: test_xsave
// OGCG: call void @llvm.x86.xsave
More information about the cfe-commits
mailing list