-
Notifications
You must be signed in to change notification settings - Fork 15.4k
[CIR][X86] Implement xsave/xrstor builtins Fixes part of #167752 #170877
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
@llvm/pr-subscribers-clangir @llvm/pr-subscribers-clang Author: Medha Tiwari (medhatiwari) ChangesHandle xsave/xrstor family of X86 builtins in ClangIR Part of #167752 Full diff: https://github.com/llvm/llvm-project/pull/170877.diff 2 Files Affected:
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);
+}
+
|
andykaylor
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the PR! This looks pretty good. I just have one minor suggestion and a request for improving the test.
| cir::ConstantOp shift32 = | ||
| builder.getConstant(loc, cir::IntAttr::get(i64Ty, 32)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| cir::ConstantOp shift32 = | |
| builder.getConstant(loc, cir::IntAttr::get(i64Ty, 32)); | |
| cir::ConstantOp shift32 = builder.getSInt64(32, loc); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done, changed to builder.getSInt64(32, loc). Also fixed the parameter name to /isShiftLeft=/false for clarity.
|
|
||
| void test_xsave(void *p, unsigned long long m) { | ||
| // CIR-LABEL: test_xsave | ||
| // CIR: cir.call_llvm_intrinsic "x86.xsave" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add checks that show all the casts, shifts, and parameters?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added detailed CIR and LLVM checks for test_xsave showing the shift, casts, and intrinsic call with parameters. The pattern is the same for all other xsave variants, so I kept just the intrinsic name check for the rest to avoid redundancy.
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
Signed-off-by: Medha Tiwari <medhatiwari@ibm.com>
63fa958 to
f53280c
Compare
Handle xsave/xrstor family of X86 builtins in ClangIR
Part of #167752