Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 70 additions & 1 deletion clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -533,9 +533,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:
Expand Down
182 changes: 182 additions & 0 deletions clang/test/CIR/CodeGenBuiltins/X86/xsave-builtins.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
// 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.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"
Copy link
Contributor

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?

Copy link
Contributor Author

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.


// LLVM-LABEL: test_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
__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);
}

Loading