[clang] [CIR][X86] Implement xsave/xrstor builtins Fixes part of #167752 (PR #170877)

2025-12-09 Thread Andy Kaylor via cfe-commits

https://github.com/andykaylor closed 
https://github.com/llvm/llvm-project/pull/170877
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [CIR][X86] Implement xsave/xrstor builtins Fixes part of #167752 (PR #170877)

2025-12-09 Thread Andy Kaylor via cfe-commits

https://github.com/andykaylor edited 
https://github.com/llvm/llvm-project/pull/170877
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [CIR][X86] Implement xsave/xrstor builtins Fixes part of #167752 (PR #170877)

2025-12-09 Thread Andy Kaylor via cfe-commits


@@ -7,23 +7,35 @@
 
 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"
+  // CIR: [[P:%.*]] = cir.load {{.*}} : !cir.ptr>, 
!cir.ptr
+  // CIR: [[M:%.*]] = cir.load {{.*}} : !cir.ptr, !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: lshr i64 {{.*}}, 32
-  // LLVM: trunc i64 {{.*}} to i32
-  // LLVM: trunc i64 {{.*}} to i32
-  // LLVM: call void @llvm.x86.xsave(ptr {{.*}}, i32 {{.*}}, i32 {{.*}})
+  // 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: call void @llvm.x86.xsave
+  // OGCG: [[OP:%.*]] = load ptr, ptr

andykaylor wrote:

This is fine, but it isn't necessary to use different identifiers between LLVM 
checks and OGCG checks. We often even reuse identifiers between different test 
cases with the same output type.

https://github.com/llvm/llvm-project/pull/170877
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [CIR][X86] Implement xsave/xrstor builtins Fixes part of #167752 (PR #170877)

2025-12-09 Thread Andy Kaylor via cfe-commits

https://github.com/andykaylor approved this pull request.

lgtm

https://github.com/llvm/llvm-project/pull/170877
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [CIR][X86] Implement xsave/xrstor builtins Fixes part of #167752 (PR #170877)

2025-12-09 Thread Medha Tiwari via cfe-commits


@@ -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"

medhatiwari wrote:

Updated! Added detailed checks for test_xsave showing the full use-def flow 
(load → const → shift → cast → intrinsic call) for CIR, LLVM, and OGCG. Added a 
comment explaining that the other tests follow the same pattern.

https://github.com/llvm/llvm-project/pull/170877
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [CIR][X86] Implement xsave/xrstor builtins Fixes part of #167752 (PR #170877)

2025-12-09 Thread Medha Tiwari via cfe-commits

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 
Date: Fri, 5 Dec 2025 21:27:29 +0530
Subject: [PATCH 1/3] [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 0..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, 

[clang] [CIR][X86] Implement xsave/xrstor builtins Fixes part of #167752 (PR #170877)

2025-12-08 Thread Andy Kaylor via cfe-commits


@@ -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"

andykaylor wrote:

```suggestion
  // CIR: [[P:.*]] = cir.load
  // CIR: [[M:.*]] = cir.load
  // 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]]
```
This is the level of detail I was hoping to see, here and in the LLVM and OGCG 
checks for this case. I want to be able to see the entire use-def flow. It's 
fine to omit it for the others though, since as you noted they follow the same 
pattern, though a comment explaining that would be useful.

https://github.com/llvm/llvm-project/pull/170877
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [CIR][X86] Implement xsave/xrstor builtins Fixes part of #167752 (PR #170877)

2025-12-06 Thread Medha Tiwari via cfe-commits

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 
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 0..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, 

[clang] [CIR][X86] Implement xsave/xrstor builtins Fixes part of #167752 (PR #170877)

2025-12-06 Thread via cfe-commits

github-actions[bot] wrote:




:warning: C/C++ code formatter, clang-format found issues in your code. 
:warning:



You can test this locally with the following command:


``bash
git-clang-format --diff origin/main HEAD --extensions cpp,c -- 
clang/test/CIR/CodeGenBuiltins/X86/xsave-builtins.c 
clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp --diff_from_common_commit
``

:warning:
The reproduction instructions above might return results for more than one PR
in a stack if you are using a stacked PR workflow. You can limit the results by
changing `origin/main` to the base branch/commit you want to compare against.
:warning:





View the diff from clang-format here.


``diff
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp 
b/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp
index be0bf5832..850aa0ecb 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp
@@ -589,8 +589,8 @@ mlir::Value CIRGenFunction::emitX86BuiltinExpr(unsigned 
builtinID,
 
 // 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);
+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

``




https://github.com/llvm/llvm-project/pull/170877
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [CIR][X86] Implement xsave/xrstor builtins Fixes part of #167752 (PR #170877)

2025-12-06 Thread Medha Tiwari via cfe-commits


@@ -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"

medhatiwari wrote:

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.

https://github.com/llvm/llvm-project/pull/170877
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [CIR][X86] Implement xsave/xrstor builtins Fixes part of #167752 (PR #170877)

2025-12-06 Thread Medha Tiwari via cfe-commits


@@ -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));

medhatiwari wrote:

Done, changed to builder.getSInt64(32, loc). Also fixed the parameter name to 
/*isShiftLeft=*/false for clarity.


https://github.com/llvm/llvm-project/pull/170877
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [CIR][X86] Implement xsave/xrstor builtins Fixes part of #167752 (PR #170877)

2025-12-06 Thread Medha Tiwari via cfe-commits

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 
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 0..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, 

[clang] [CIR][X86] Implement xsave/xrstor builtins Fixes part of #167752 (PR #170877)

2025-12-05 Thread Andy Kaylor via cfe-commits


@@ -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));

andykaylor wrote:

```suggestion
cir::ConstantOp shift32 = builder.getSInt64(32, loc);
```

https://github.com/llvm/llvm-project/pull/170877
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [CIR][X86] Implement xsave/xrstor builtins Fixes part of #167752 (PR #170877)

2025-12-05 Thread Andy Kaylor via cfe-commits


@@ -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"

andykaylor wrote:

Can you add checks that show all the casts, shifts, and parameters?

https://github.com/llvm/llvm-project/pull/170877
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [CIR][X86] Implement xsave/xrstor builtins Fixes part of #167752 (PR #170877)

2025-12-05 Thread Andy Kaylor via cfe-commits

https://github.com/andykaylor commented:

Thanks for the PR! This looks pretty good. I just have one minor suggestion and 
a request for improving the test.

https://github.com/llvm/llvm-project/pull/170877
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [CIR][X86] Implement xsave/xrstor builtins Fixes part of #167752 (PR #170877)

2025-12-05 Thread Andy Kaylor via cfe-commits

https://github.com/andykaylor edited 
https://github.com/llvm/llvm-project/pull/170877
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [CIR][X86] Implement xsave/xrstor builtins Fixes part of #167752 (PR #170877)

2025-12-05 Thread via cfe-commits

llvmbot wrote:




@llvm/pr-subscribers-clang

Author: Medha Tiwari (medhatiwari)


Changes

Handle 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:

- (modified) clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp (+72-1) 
- (added) clang/test/CIR/CodeGenBuiltins/X86/xsave-builtins.c (+175) 


``diff
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 0..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.

[clang] [CIR][X86] Implement xsave/xrstor builtins Fixes part of #167752 (PR #170877)

2025-12-05 Thread Medha Tiwari via cfe-commits

https://github.com/medhatiwari created 
https://github.com/llvm/llvm-project/pull/170877

Handle xsave/xrstor family of X86 builtins in ClangIR

Part of #167752

>From e590a91f11e4673920ed56c0da874c9c6a6e9974 Mon Sep 17 00:00:00 2001
From: Medha Tiwari 
Date: Fri, 5 Dec 2025 21:27:29 +0530
Subject: [PATCH] [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 0..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 -We