Skip to content

Commit 019a294

Browse files
authored
[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@ibm.com>
1 parent 0895163 commit 019a294

File tree

2 files changed

+264
-1
lines changed

2 files changed

+264
-1
lines changed

clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -544,9 +544,78 @@ mlir::Value CIRGenFunction::emitX86BuiltinExpr(unsigned builtinID,
544544
case X86::BI__builtin_ia32_xsaves:
545545
case X86::BI__builtin_ia32_xsaves64:
546546
case X86::BI__builtin_ia32_xsetbv:
547-
case X86::BI_xsetbv:
547+
case X86::BI_xsetbv: {
548+
mlir::Location loc = getLoc(expr->getExprLoc());
549+
StringRef intrinsicName;
550+
switch (builtinID) {
551+
default:
552+
llvm_unreachable("Unexpected builtin");
553+
case X86::BI__builtin_ia32_xsave:
554+
intrinsicName = "x86.xsave";
555+
break;
556+
case X86::BI__builtin_ia32_xsave64:
557+
intrinsicName = "x86.xsave64";
558+
break;
559+
case X86::BI__builtin_ia32_xrstor:
560+
intrinsicName = "x86.xrstor";
561+
break;
562+
case X86::BI__builtin_ia32_xrstor64:
563+
intrinsicName = "x86.xrstor64";
564+
break;
565+
case X86::BI__builtin_ia32_xsaveopt:
566+
intrinsicName = "x86.xsaveopt";
567+
break;
568+
case X86::BI__builtin_ia32_xsaveopt64:
569+
intrinsicName = "x86.xsaveopt64";
570+
break;
571+
case X86::BI__builtin_ia32_xrstors:
572+
intrinsicName = "x86.xrstors";
573+
break;
574+
case X86::BI__builtin_ia32_xrstors64:
575+
intrinsicName = "x86.xrstors64";
576+
break;
577+
case X86::BI__builtin_ia32_xsavec:
578+
intrinsicName = "x86.xsavec";
579+
break;
580+
case X86::BI__builtin_ia32_xsavec64:
581+
intrinsicName = "x86.xsavec64";
582+
break;
583+
case X86::BI__builtin_ia32_xsaves:
584+
intrinsicName = "x86.xsaves";
585+
break;
586+
case X86::BI__builtin_ia32_xsaves64:
587+
intrinsicName = "x86.xsaves64";
588+
break;
589+
case X86::BI__builtin_ia32_xsetbv:
590+
case X86::BI_xsetbv:
591+
intrinsicName = "x86.xsetbv";
592+
break;
593+
}
594+
595+
// The xsave family of instructions take a 64-bit mask that specifies
596+
// which processor state components to save/restore. The hardware expects
597+
// this mask split into two 32-bit registers: EDX (high 32 bits) and
598+
// EAX (low 32 bits).
599+
mlir::Type i32Ty = builder.getSInt32Ty();
600+
601+
// Mhi = (uint32_t)(ops[1] >> 32) - extract high 32 bits via right shift
602+
cir::ConstantOp shift32 = builder.getSInt64(32, loc);
603+
mlir::Value mhi = builder.createShift(loc, ops[1], shift32.getResult(),
604+
/*isShiftLeft=*/false);
605+
mhi = builder.createIntCast(mhi, i32Ty);
606+
607+
// Mlo = (uint32_t)ops[1] - extract low 32 bits by truncation
608+
mlir::Value mlo = builder.createIntCast(ops[1], i32Ty);
609+
610+
return emitIntrinsicCallOp(builder, loc, intrinsicName, voidTy,
611+
mlir::ValueRange{ops[0], mhi, mlo});
612+
}
548613
case X86::BI__builtin_ia32_xgetbv:
549614
case X86::BI_xgetbv:
615+
// xgetbv reads the extended control register specified by ops[0] (ECX)
616+
// and returns the 64-bit value
617+
return emitIntrinsicCallOp(builder, getLoc(expr->getExprLoc()),
618+
"x86.xgetbv", builder.getUInt64Ty(), ops[0]);
550619
case X86::BI__builtin_ia32_storedqudi128_mask:
551620
case X86::BI__builtin_ia32_storedqusi128_mask:
552621
case X86::BI__builtin_ia32_storedquhi128_mask:
Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
// 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
2+
// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
3+
// 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
4+
// RUN: FileCheck --check-prefixes=LLVM --input-file=%t.ll %s
5+
6+
// 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
7+
8+
void test_xsave(void *p, unsigned long long m) {
9+
// CIR-LABEL: test_xsave
10+
// CIR: [[P:%.*]] = cir.load {{.*}} : !cir.ptr<!cir.ptr<!void>>, !cir.ptr<!void>
11+
// CIR: [[M:%.*]] = cir.load {{.*}} : !cir.ptr<!u64i>, !u64i
12+
// CIR: [[CONST:%.*]] = cir.const #cir.int<32> : !s64i
13+
// CIR: [[SHIFT:%.*]] = cir.shift(right, [[M]] : !u64i, [[CONST]] : !s64i) -> !u64i
14+
// CIR: [[CAST1:%.*]] = cir.cast integral [[SHIFT]] : !u64i -> !s32i
15+
// CIR: [[CAST2:%.*]] = cir.cast integral [[M]] : !u64i -> !s32i
16+
// CIR: cir.call_llvm_intrinsic "x86.xsave" [[P]], [[CAST1]], [[CAST2]]
17+
18+
// LLVM-LABEL: test_xsave
19+
// LLVM: [[LP:%.*]] = load ptr, ptr
20+
// LLVM: [[LM:%.*]] = load i64, ptr
21+
// LLVM: [[LSHIFT:%.*]] = lshr i64 [[LM]], 32
22+
// LLVM: [[LCAST1:%.*]] = trunc i64 [[LSHIFT]] to i32
23+
// LLVM: [[LCAST2:%.*]] = trunc i64 [[LM]] to i32
24+
// LLVM: call void @llvm.x86.xsave(ptr [[LP]], i32 [[LCAST1]], i32 [[LCAST2]])
25+
26+
// OGCG-LABEL: test_xsave
27+
// OGCG: [[OP:%.*]] = load ptr, ptr
28+
// OGCG: [[OM:%.*]] = load i64, ptr
29+
// OGCG: [[OSHIFT:%.*]] = lshr i64 [[OM]], 32
30+
// OGCG: [[OCAST1:%.*]] = trunc i64 [[OSHIFT]] to i32
31+
// OGCG: [[OCAST2:%.*]] = trunc i64 [[OM]] to i32
32+
// OGCG: call void @llvm.x86.xsave(ptr [[OP]], i32 [[OCAST1]], i32 [[OCAST2]])
33+
__builtin_ia32_xsave(p, m);
34+
}
35+
36+
// The following tests use the same pattern as test_xsave (load, shift, cast, cast, intrinsic call).
37+
// Only the intrinsic name differs, so we just check the intrinsic call.
38+
39+
void test_xsave64(void *p, unsigned long long m) {
40+
// CIR-LABEL: test_xsave64
41+
// CIR: cir.call_llvm_intrinsic "x86.xsave64"
42+
43+
// LLVM-LABEL: test_xsave64
44+
// LLVM: call void @llvm.x86.xsave64
45+
46+
// OGCG-LABEL: test_xsave64
47+
// OGCG: call void @llvm.x86.xsave64
48+
__builtin_ia32_xsave64(p, m);
49+
}
50+
51+
void test_xrstor(void *p, unsigned long long m) {
52+
// CIR-LABEL: test_xrstor
53+
// CIR: cir.call_llvm_intrinsic "x86.xrstor"
54+
55+
// LLVM-LABEL: test_xrstor
56+
// LLVM: call void @llvm.x86.xrstor
57+
58+
// OGCG-LABEL: test_xrstor
59+
// OGCG: call void @llvm.x86.xrstor
60+
__builtin_ia32_xrstor(p, m);
61+
}
62+
63+
void test_xrstor64(void *p, unsigned long long m) {
64+
// CIR-LABEL: test_xrstor64
65+
// CIR: cir.call_llvm_intrinsic "x86.xrstor64"
66+
67+
// LLVM-LABEL: test_xrstor64
68+
// LLVM: call void @llvm.x86.xrstor64
69+
70+
// OGCG-LABEL: test_xrstor64
71+
// OGCG: call void @llvm.x86.xrstor64
72+
__builtin_ia32_xrstor64(p, m);
73+
}
74+
75+
void test_xsaveopt(void *p, unsigned long long m) {
76+
// CIR-LABEL: test_xsaveopt
77+
// CIR: cir.call_llvm_intrinsic "x86.xsaveopt"
78+
79+
// LLVM-LABEL: test_xsaveopt
80+
// LLVM: call void @llvm.x86.xsaveopt
81+
82+
// OGCG-LABEL: test_xsaveopt
83+
// OGCG: call void @llvm.x86.xsaveopt
84+
__builtin_ia32_xsaveopt(p, m);
85+
}
86+
87+
void test_xsaveopt64(void *p, unsigned long long m) {
88+
// CIR-LABEL: test_xsaveopt64
89+
// CIR: cir.call_llvm_intrinsic "x86.xsaveopt64"
90+
91+
// LLVM-LABEL: test_xsaveopt64
92+
// LLVM: call void @llvm.x86.xsaveopt64
93+
94+
// OGCG-LABEL: test_xsaveopt64
95+
// OGCG: call void @llvm.x86.xsaveopt64
96+
__builtin_ia32_xsaveopt64(p, m);
97+
}
98+
99+
void test_xsavec(void *p, unsigned long long m) {
100+
// CIR-LABEL: test_xsavec
101+
// CIR: cir.call_llvm_intrinsic "x86.xsavec"
102+
103+
// LLVM-LABEL: test_xsavec
104+
// LLVM: call void @llvm.x86.xsavec
105+
106+
// OGCG-LABEL: test_xsavec
107+
// OGCG: call void @llvm.x86.xsavec
108+
__builtin_ia32_xsavec(p, m);
109+
}
110+
111+
void test_xsavec64(void *p, unsigned long long m) {
112+
// CIR-LABEL: test_xsavec64
113+
// CIR: cir.call_llvm_intrinsic "x86.xsavec64"
114+
115+
// LLVM-LABEL: test_xsavec64
116+
// LLVM: call void @llvm.x86.xsavec64
117+
118+
// OGCG-LABEL: test_xsavec64
119+
// OGCG: call void @llvm.x86.xsavec64
120+
__builtin_ia32_xsavec64(p, m);
121+
}
122+
123+
void test_xsaves(void *p, unsigned long long m) {
124+
// CIR-LABEL: test_xsaves
125+
// CIR: cir.call_llvm_intrinsic "x86.xsaves"
126+
127+
// LLVM-LABEL: test_xsaves
128+
// LLVM: call void @llvm.x86.xsaves
129+
130+
// OGCG-LABEL: test_xsaves
131+
// OGCG: call void @llvm.x86.xsaves
132+
__builtin_ia32_xsaves(p, m);
133+
}
134+
135+
void test_xsaves64(void *p, unsigned long long m) {
136+
// CIR-LABEL: test_xsaves64
137+
// CIR: cir.call_llvm_intrinsic "x86.xsaves64"
138+
139+
// LLVM-LABEL: test_xsaves64
140+
// LLVM: call void @llvm.x86.xsaves64
141+
142+
// OGCG-LABEL: test_xsaves64
143+
// OGCG: call void @llvm.x86.xsaves64
144+
__builtin_ia32_xsaves64(p, m);
145+
}
146+
147+
void test_xrstors(void *p, unsigned long long m) {
148+
// CIR-LABEL: test_xrstors
149+
// CIR: cir.call_llvm_intrinsic "x86.xrstors"
150+
151+
// LLVM-LABEL: test_xrstors
152+
// LLVM: call void @llvm.x86.xrstors
153+
154+
// OGCG-LABEL: test_xrstors
155+
// OGCG: call void @llvm.x86.xrstors
156+
__builtin_ia32_xrstors(p, m);
157+
}
158+
159+
void test_xrstors64(void *p, unsigned long long m) {
160+
// CIR-LABEL: test_xrstors64
161+
// CIR: cir.call_llvm_intrinsic "x86.xrstors64"
162+
163+
// LLVM-LABEL: test_xrstors64
164+
// LLVM: call void @llvm.x86.xrstors64
165+
166+
// OGCG-LABEL: test_xrstors64
167+
// OGCG: call void @llvm.x86.xrstors64
168+
__builtin_ia32_xrstors64(p, m);
169+
}
170+
171+
unsigned long long test_xgetbv(unsigned int a) {
172+
// CIR-LABEL: test_xgetbv
173+
// CIR: cir.call_llvm_intrinsic "x86.xgetbv"
174+
175+
// LLVM-LABEL: test_xgetbv
176+
// LLVM: call i64 @llvm.x86.xgetbv
177+
178+
// OGCG-LABEL: test_xgetbv
179+
// OGCG: call i64 @llvm.x86.xgetbv
180+
return __builtin_ia32_xgetbv(a);
181+
}
182+
183+
void test_xsetbv(unsigned int a, unsigned long long m) {
184+
// CIR-LABEL: test_xsetbv
185+
// CIR: cir.call_llvm_intrinsic "x86.xsetbv"
186+
187+
// LLVM-LABEL: test_xsetbv
188+
// LLVM: call void @llvm.x86.xsetbv
189+
190+
// OGCG-LABEL: test_xsetbv
191+
// OGCG: call void @llvm.x86.xsetbv
192+
__builtin_ia32_xsetbv(a, m);
193+
}
194+

0 commit comments

Comments
 (0)