[clang] [llvm] [AArch64] Fix _sys implemantation and MRS/MSR Sema checks (PR #187290)

via cfe-commits cfe-commits at lists.llvm.org
Thu Mar 19 09:29:54 PDT 2026


https://github.com/Lukacma updated https://github.com/llvm/llvm-project/pull/187290

>From 9855a9c8ed42ff4d2accc4566544c2d1723ff279 Mon Sep 17 00:00:00 2001
From: Marian Lukac <Marian.Lukac at arm.com>
Date: Wed, 18 Mar 2026 14:26:52 +0000
Subject: [PATCH 1/5] [AArch64] Fix _sys implemantation and MRS/MSR Sema checks

---
 clang/lib/CodeGen/TargetBuiltins/ARM.cpp      |  33 +++--
 clang/lib/Sema/SemaARM.cpp                    |   9 +-
 .../CodeGen/arm64-microsoft-status-reg.cpp    |   2 +-
 clang/test/CodeGen/arm64-microsoft-sys.c      |  28 ++--
 clang/test/Sema/builtins-microsoft-arm64.c    |  13 ++
 llvm/include/llvm/IR/IntrinsicsAArch64.td     |   5 +-
 .../lib/Target/AArch64/AArch64InstrFormats.td |  15 ++-
 llvm/lib/Target/AArch64/AArch64InstrInfo.td   |   6 +-
 .../CodeGen/AArch64/aarch64-sys-intrinsic.ll  | 126 ++++++++++++++++++
 9 files changed, 195 insertions(+), 42 deletions(-)
 create mode 100644 llvm/test/CodeGen/AArch64/aarch64-sys-intrinsic.ll

diff --git a/clang/lib/CodeGen/TargetBuiltins/ARM.cpp b/clang/lib/CodeGen/TargetBuiltins/ARM.cpp
index cdee440a5c60e..bda096f99d001 100644
--- a/clang/lib/CodeGen/TargetBuiltins/ARM.cpp
+++ b/clang/lib/CodeGen/TargetBuiltins/ARM.cpp
@@ -5639,20 +5639,15 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
   }
 
   if (BuiltinID == clang::AArch64::BI_ReadStatusReg ||
-      BuiltinID == clang::AArch64::BI_WriteStatusReg ||
-      BuiltinID == clang::AArch64::BI__sys) {
+      BuiltinID == clang::AArch64::BI_WriteStatusReg) {
     LLVMContext &Context = CGM.getLLVMContext();
 
     unsigned SysReg =
       E->getArg(0)->EvaluateKnownConstInt(getContext()).getZExtValue();
 
     std::string SysRegStr;
-    unsigned SysRegOp0 = (BuiltinID == clang::AArch64::BI_ReadStatusReg ||
-                          BuiltinID == clang::AArch64::BI_WriteStatusReg)
-                             ? ((1 << 1) | ((SysReg >> 14) & 1))
-                             : 1;
     llvm::raw_string_ostream(SysRegStr)
-        << SysRegOp0 << ":" << ((SysReg >> 11) & 7) << ":"
+        << (SysReg >> 14) << ":" << ((SysReg >> 11) & 7) << ":"
         << ((SysReg >> 7) & 15) << ":" << ((SysReg >> 3) & 15) << ":"
         << (SysReg & 7);
 
@@ -5672,14 +5667,28 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
     llvm::Function *F = CGM.getIntrinsic(Intrinsic::write_register, Types);
     llvm::Value *ArgValue = EmitScalarExpr(E->getArg(1));
     llvm::Value *Result = Builder.CreateCall(F, {Metadata, ArgValue});
-    if (BuiltinID == clang::AArch64::BI__sys) {
-      // Return 0 for convenience, even though MSVC returns some other undefined
-      // value.
-      Result = ConstantInt::get(Builder.getInt32Ty(), 0);
-    }
+
     return Result;
   }
 
+  if (BuiltinID == clang::AArch64::BI__sys) {
+    unsigned SysReg =
+        E->getArg(0)->EvaluateKnownConstInt(getContext()).getZExtValue();
+    const unsigned Op1 = SysReg >> 11;
+    const unsigned CRn = (SysReg >> 7) & 0xf;
+    const unsigned CRm = (SysReg >> 3) & 0xf;
+    const unsigned Op2 = SysReg & 0x7;
+
+    Builder.CreateCall(CGM.getIntrinsic(Intrinsic::aarch64_sys),
+                       {Builder.getInt32(Op1), Builder.getInt32(CRn),
+                        Builder.getInt32(CRm), Builder.getInt32(Op2),
+                        EmitScalarExpr(E->getArg(1))});
+
+    // Return 0 for convenience, even though MSVC returns some other undefined
+    // value.
+    return ConstantInt::get(Builder.getInt32Ty(), 0);
+  }
+
   if (BuiltinID == clang::AArch64::BI_AddressOfReturnAddress) {
     llvm::Function *F =
         CGM.getIntrinsic(Intrinsic::addressofreturnaddress, AllocaInt8PtrTy);
diff --git a/clang/lib/Sema/SemaARM.cpp b/clang/lib/Sema/SemaARM.cpp
index 693a936b7b35b..fa4463c03b047 100644
--- a/clang/lib/Sema/SemaARM.cpp
+++ b/clang/lib/Sema/SemaARM.cpp
@@ -1260,11 +1260,14 @@ bool SemaARM::CheckAArch64BuiltinFunctionCall(const TargetInfo &TI,
     return BuiltinARMSpecialReg(BuiltinID, TheCall, 0, 5, true);
 
   // Only check the valid encoding range. Any constant in this range would be
-  // converted to a register of the form S1_2_C3_C4_5. Let the hardware throw
+  // converted to a register of the form S2_2_C3_C4_5. Let the hardware throw
   // an exception for incorrect registers. This matches MSVC behavior.
   if (BuiltinID == AArch64::BI_ReadStatusReg ||
-      BuiltinID == AArch64::BI_WriteStatusReg || BuiltinID == AArch64::BI__sys)
-    return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 0x7fff);
+      BuiltinID == AArch64::BI_WriteStatusReg)
+    return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0x4000, 0xffff);
+
+  if (BuiltinID == AArch64::BI__sys)
+    return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 0x3fff);
 
   if (BuiltinID == AArch64::BI__getReg)
     return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 31);
diff --git a/clang/test/CodeGen/arm64-microsoft-status-reg.cpp b/clang/test/CodeGen/arm64-microsoft-status-reg.cpp
index 5a942169394e3..c182fdf062ab8 100644
--- a/clang/test/CodeGen/arm64-microsoft-status-reg.cpp
+++ b/clang/test/CodeGen/arm64-microsoft-status-reg.cpp
@@ -14,7 +14,7 @@
 
 // From winnt.h
 #define ARM64_SYSREG(op0, op1, crn, crm, op2) \
-        ( ((op0 & 1) << 14) | \
+        ( ((op0 & 3) << 14) | \
           ((op1 & 7) << 11) | \
           ((crn & 15) << 7) | \
           ((crm & 15) << 3) | \
diff --git a/clang/test/CodeGen/arm64-microsoft-sys.c b/clang/test/CodeGen/arm64-microsoft-sys.c
index 5913a02d933ae..0abc9ea665fef 100644
--- a/clang/test/CodeGen/arm64-microsoft-sys.c
+++ b/clang/test/CodeGen/arm64-microsoft-sys.c
@@ -11,7 +11,7 @@
 
 // From winnt.h
 // op0=1 encodings, use with __sys
-#define ARM64_SYSINSTR(op0, op1, crn, crm, op2) \
+#define ARM64_SYSINSTR(op1, crn, crm, op2) \
         ( ((op1 & 7) << 11) | \
           ((crn & 15) << 7) | \
           ((crm & 15) << 3) | \
@@ -20,11 +20,11 @@
 //
 // Sampling of instructions
 //
-#define ARM64_DC_CGDSW_EL1      ARM64_SYSINSTR(1,0, 7,10,6) // Clean of Data and Allocation Tags by Set/Way
-#define ARM64_IC_IALLU_EL1      ARM64_SYSINSTR(1,0, 7, 5,0) // Instruction Cache Invalidate All to PoU
-#define ARM64_AT_S1E2W          ARM64_SYSINSTR(1,4, 7, 8,1) // Translate Stage1, EL2, write
-#define ARM64_TLBI_VMALLE1      ARM64_SYSINSTR(1,0, 8, 7,0) // Invalidate stage 1 TLB [CP15_TLBIALL]
-#define ARM64_CFP_RCTX          ARM64_SYSINSTR(1,3, 7, 3,4) // Control Flow Prediction Restriction by Context
+#define ARM64_DC_CGDSW_EL1      ARM64_SYSINSTR(0, 7,10,6) // Clean of Data and Allocation Tags by Set/Way
+#define ARM64_IC_IALLU_EL1      ARM64_SYSINSTR(0, 7, 5,0) // Instruction Cache Invalidate All to PoU
+#define ARM64_AT_S1E2W          ARM64_SYSINSTR(4, 7, 8,1) // Translate Stage1, EL2, write
+#define ARM64_TLBI_VMALLE1      ARM64_SYSINSTR(0, 8, 7,0) // Invalidate stage 1 TLB [CP15_TLBIALL]
+#define ARM64_CFP_RCTX          ARM64_SYSINSTR(3, 7, 3,4) // Control Flow Prediction Restriction by Context
 
 // From intrin.h
 unsigned int __sys(int, __int64);
@@ -35,31 +35,25 @@ void check__sys(__int64 v) {
   __sys(ARM64_DC_CGDSW_EL1, v);
 // CHECK-ASM: msr     S1_0_C7_C10_6, x8
 // CHECK-IR: %[[VAR:.*]] = load i64,
-// CHECK-IR-NEXT: call void @llvm.write_register.i64(metadata ![[MD2:.*]], i64 %[[VAR]])
+// CHECK-IR-NEXT: call void @llvm.aarch64.sys(i32 0, i32 7, i32 10, i32 6, i64 %[[VAR]])
 
   __sys(ARM64_IC_IALLU_EL1, v);
 // CHECK-ASM: msr     S1_0_C7_C5_0, x8
 // CHECK-IR: %[[VAR:.*]] = load i64,
-// CHECK-IR-NEXT: call void @llvm.write_register.i64(metadata ![[MD3:.*]], i64 %[[VAR]])
+// CHECK-IR-NEXT: call void @llvm.aarch64.sys(i32 0, i32 7, i32 5, i32 0, i64 %[[VAR]])
 
   __sys(ARM64_AT_S1E2W, v);
 // CHECK-ASM: msr     S1_4_C7_C8_1, x8
 // CHECK-IR: %[[VAR:.*]] = load i64,
-// CHECK-IR-NEXT: call void @llvm.write_register.i64(metadata ![[MD4:.*]], i64 %[[VAR]])
+// CHECK-IR-NEXT: call void @llvm.aarch64.sys(i32 4, i32 7, i32 8, i32 1, i64 %[[VAR]])
 
   __sys(ARM64_TLBI_VMALLE1, v);
 // CHECK-ASM: msr     S1_0_C8_C7_0, x8
 // CHECK-IR: %[[VAR:.*]] = load i64,
-// CHECK-IR-NEXT: call void @llvm.write_register.i64(metadata ![[MD5:.*]], i64 %[[VAR]])
+// CHECK-IR-NEXT: call void @llvm.aarch64.sys(i32 0, i32 8, i32 7, i32 0, i64 %[[VAR]])
 
   __sys(ARM64_CFP_RCTX, v);
 // CHECK-ASM: msr     S1_3_C7_C3_4, x8
 // CHECK-IR: %[[VAR:.*]] = load i64,
-// CHECK-IR-NEXT: call void @llvm.write_register.i64(metadata ![[MD6:.*]], i64 %[[VAR]])
+// CHECK-IR-NEXT: call void @llvm.aarch64.sys(i32 3, i32 7, i32 3, i32 4, i64 %[[VAR]])
 }
-
-// CHECK-IR: ![[MD2]] = !{!"1:0:7:10:6"}
-// CHECK-IR: ![[MD3]] = !{!"1:0:7:5:0"}
-// CHECK-IR: ![[MD4]] = !{!"1:4:7:8:1"}
-// CHECK-IR: ![[MD5]] = !{!"1:0:8:7:0"}
-// CHECK-IR: ![[MD6]] = !{!"1:3:7:3:4"}
diff --git a/clang/test/Sema/builtins-microsoft-arm64.c b/clang/test/Sema/builtins-microsoft-arm64.c
index a915a370cde14..738f8c6e02bd5 100644
--- a/clang/test/Sema/builtins-microsoft-arm64.c
+++ b/clang/test/Sema/builtins-microsoft-arm64.c
@@ -25,11 +25,24 @@ void check_ReadWriteStatusReg(int v) {
   _WriteStatusReg(x, v); // expected-error {{argument to '_WriteStatusReg' must be a constant integer}}
 }
 
+void check_ReadWriteStatusReg_range(int v) {
+  _ReadStatusReg(0x3fff);      // expected-error-re {{argument value {{.*}} is outside the valid range}}
+  _ReadStatusReg(0x10000); // expected-error-re {{argument value {{.*}} is outside the valid range}}
+
+  _WriteStatusReg(0x3fff, v);  // expected-error-re {{argument value {{.*}} is outside the valid range}}
+  _WriteStatusReg(0x10000, v); // expected-error-re {{argument value {{.*}} is outside the valid range}}
+}
+
 void check__sys(int v) {
   int x;
   __sys(x, v); // expected-error {{argument to '__sys' must be a constant integer}}
 }
 
+void check__sys_range(int v) {
+  __sys(-1, v);      // expected-error-re {{argument value {{.*}} is outside the valid range}}
+  __sys(0x4000, v);  // expected-error-re {{argument value {{.*}} is outside the valid range}}
+}
+
 unsigned int check__sys_retval() {
   return __sys(0, 1); // builtin has superfluous return value for MSVC compatibility
 }
diff --git a/llvm/include/llvm/IR/IntrinsicsAArch64.td b/llvm/include/llvm/IR/IntrinsicsAArch64.td
index 75929cbc222ad..6f645548abe1d 100644
--- a/llvm/include/llvm/IR/IntrinsicsAArch64.td
+++ b/llvm/include/llvm/IR/IntrinsicsAArch64.td
@@ -57,7 +57,10 @@ def int_aarch64_frint64x
     : DefaultAttrsIntrinsic<[ llvm_anyfloat_ty ], [ LLVMMatchType<0> ],
                             [ IntrNoMem ]>;
 
-
+def int_aarch64_sys  : DefaultAttrsIntrinsic<[], [llvm_i32_ty, llvm_i32_ty,
+                 llvm_i32_ty, llvm_i32_ty, llvm_i64_ty],
+    [IntrNoMem, IntrHasSideEffects, ImmArg<ArgIndex<0>>, ImmArg<ArgIndex<1>>, ImmArg<ArgIndex<2>>,
+     ImmArg<ArgIndex<3>>]>;
 //===----------------------------------------------------------------------===//
 // HINT
 
diff --git a/llvm/lib/Target/AArch64/AArch64InstrFormats.td b/llvm/lib/Target/AArch64/AArch64InstrFormats.td
index 5fdb9814cc2e8..c9c4c3919b40f 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrFormats.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrFormats.td
@@ -2116,16 +2116,21 @@ def SysCRAsmOperand : AsmOperandClass {
   let ParserMethod = "tryParseSysCROperand";
 }
 
-def sys_cr_op : Operand<i32> {
+def sys_cr_op : Operand<i32>, TImmLeaf<i32, [{
+  return ((uint32_t)Imm) < 16;
+}]> {
   let PrintMethod = "printSysCROperand";
   let ParserMatchClass = SysCRAsmOperand;
   let OperandType = "OPERAND_IMMEDIATE";
 }
 
-class SystemXtI<bit L, string asm>
-  : RtSystemI<L, (outs),
-       (ins imm0_7:$op1, sys_cr_op:$Cn, sys_cr_op:$Cm, imm0_7:$op2, GPR64:$Rt),
-       asm, "\t$op1, $Cn, $Cm, $op2, $Rt"> {
+class SystemXtI<string asm>
+  : RtSystemI<0, (outs),
+       (ins imm32_0_7:$op1, sys_cr_op:$Cn, sys_cr_op:$Cm, imm32_0_7:$op2,
+            GPR64:$Rt),
+       asm, "\t$op1, $Cn, $Cm, $op2, $Rt",
+       [(int_aarch64_sys timm32_0_7:$op1, sys_cr_op:$Cn, sys_cr_op:$Cm,
+                          timm32_0_7:$op2, GPR64:$Rt)]> {
   bits<3> op1;
   bits<4> Cn;
   bits<4> Cm;
diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
index 2900cf073b5aa..5a91d4361a41f 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
@@ -2560,12 +2560,12 @@ def MSR_FPMR : Pseudo<(outs), (ins GPR64:$val),
                Sched<[WriteSys]>;
 
 // Generic system instructions
-def SYSxt  : SystemXtI<0, "sys">;
+def SYSxt  : SystemXtI<"sys">;
 def SYSLxt : SystemLXtI<1, "sysl">;
 
 def : InstAlias<"sys $op1, $Cn, $Cm, $op2",
-                (SYSxt imm0_7:$op1, sys_cr_op:$Cn,
-                 sys_cr_op:$Cm, imm0_7:$op2, XZR)>;
+                (SYSxt timm32_0_7:$op1, sys_cr_op:$Cn,
+                 sys_cr_op:$Cm, timm32_0_7:$op2, XZR)>;
 
 
 //===----------------------------------------------------------------------===//
diff --git a/llvm/test/CodeGen/AArch64/aarch64-sys-intrinsic.ll b/llvm/test/CodeGen/AArch64/aarch64-sys-intrinsic.ll
new file mode 100644
index 0000000000000..79ee54a97e53a
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/aarch64-sys-intrinsic.ll
@@ -0,0 +1,126 @@
+; RUN: llc < %s -mtriple=aarch64 -asm-verbose=false | FileCheck %s --check-prefix=CHECK
+; RUN: llc < %s -mtriple=aarch64 -mattr=+predres -asm-verbose=false | FileCheck %s --check-prefix=PREDRES
+; RUN: llc < %s -mtriple=aarch64 -mattr=+specres2 -asm-verbose=false | FileCheck %s --check-prefix=SPECRES2
+; RUN: llc < %s -mtriple=aarch64 -mattr=+gcie -asm-verbose=false | FileCheck %s --check-prefix=GCIE
+; RUN: llc < %s -mtriple=aarch64 -mattr=+poe2 -asm-verbose=false | FileCheck %s --check-prefix=POE2
+; RUN: llc < %s -mtriple=aarch64 -mattr=+mpamv2 -asm-verbose=false | FileCheck %s --check-prefix=MPAMV2
+
+declare void @llvm.aarch64.sys(i32 immarg, i32 immarg, i32 immarg, i32 immarg,
+                               i64)
+
+define void @sys_random(i64 %x) {
+; CHECK-LABEL: sys_random:
+; CHECK:       sys #0, c7, c10, #6, x0
+; CHECK-NEXT:  ret
+entry:
+  call void @llvm.aarch64.sys(i32 0, i32 7, i32 10, i32 6, i64 %x)
+  ret void
+}
+
+define void @sys_ic_iallu() {
+; CHECK-LABEL: sys_ic_iallu:
+; CHECK:       ic iallu
+; CHECK-NEXT:  ret
+entry:
+  call void @llvm.aarch64.sys(i32 0, i32 7, i32 5, i32 0, i64 0)
+  ret void
+}
+
+define void @sys_dc_cvac(i64 %x) {
+; CHECK-LABEL: sys_dc_cvac:
+; CHECK:       dc cvac, x0
+; CHECK-NEXT:  ret
+entry:
+  call void @llvm.aarch64.sys(i32 3, i32 7, i32 10, i32 1, i64 %x)
+  ret void
+}
+
+define void @sys_at_s1e2w(i64 %x) {
+; CHECK-LABEL: sys_at_s1e2w:
+; CHECK:       at s1e2w, x0
+; CHECK-NEXT:  ret
+entry:
+  call void @llvm.aarch64.sys(i32 4, i32 7, i32 8, i32 1, i64 %x)
+  ret void
+}
+
+define void @sys_tlbi_vmalle1() {
+; CHECK-LABEL: sys_tlbi_vmalle1:
+; CHECK:       tlbi vmalle1
+; CHECK-NEXT:  ret
+entry:
+  call void @llvm.aarch64.sys(i32 0, i32 8, i32 7, i32 0, i64 0)
+  ret void
+}
+
+define void @sys_cfp_rctx(i64 %x) {
+; PREDRES-LABEL: sys_cfp_rctx:
+; PREDRES:       cfp rctx, x0
+; PREDRES-NEXT:  ret
+entry:
+  call void @llvm.aarch64.sys(i32 3, i32 7, i32 3, i32 4, i64 %x)
+  ret void
+}
+
+define void @sys_dvp_rctx(i64 %x) {
+; PREDRES-LABEL: sys_dvp_rctx:
+; PREDRES:       dvp rctx, x0
+; PREDRES-NEXT:  ret
+entry:
+  call void @llvm.aarch64.sys(i32 3, i32 7, i32 3, i32 5, i64 %x)
+  ret void
+}
+
+define void @sys_cpp_rctx(i64 %x) {
+; PREDRES-LABEL: sys_cpp_rctx:
+; PREDRES:       cpp rctx, x0
+; PREDRES-NEXT:  ret
+entry:
+  call void @llvm.aarch64.sys(i32 3, i32 7, i32 3, i32 7, i64 %x)
+  ret void
+}
+
+define void @sys_cosp_rctx(i64 %x) {
+; SPECRES2-LABEL: sys_cosp_rctx:
+; SPECRES2:       cosp rctx, x0
+; SPECRES2-NEXT:  ret
+entry:
+  call void @llvm.aarch64.sys(i32 3, i32 7, i32 3, i32 6, i64 %x)
+  ret void
+}
+
+define void @sys_gic_cdaff(i64 %x) {
+; GCIE-LABEL: sys_gic_cdaff:
+; GCIE:       gic cdaff, x0
+; GCIE-NEXT:  ret
+entry:
+  call void @llvm.aarch64.sys(i32 0, i32 12, i32 1, i32 3, i64 %x)
+  ret void
+}
+
+define void @sys_gsb_sys() {
+; GCIE-LABEL: sys_gsb_sys:
+; GCIE:       gsb sys
+; GCIE-NEXT:  ret
+entry:
+  call void @llvm.aarch64.sys(i32 0, i32 12, i32 0, i32 0, i64 0)
+  ret void
+}
+
+define void @sys_plbi_vmalle1() {
+; POE2-LABEL: sys_plbi_vmalle1:
+; POE2:       plbi vmalle1
+; POE2-NEXT:  ret
+entry:
+  call void @llvm.aarch64.sys(i32 0, i32 10, i32 7, i32 0, i64 0)
+  ret void
+}
+
+define void @sys_mlbi_vmalle1() {
+; MPAMV2-LABEL: sys_mlbi_vmalle1:
+; MPAMV2:       mlbi vmalle1
+; MPAMV2-NEXT:  ret
+entry:
+  call void @llvm.aarch64.sys(i32 4, i32 7, i32 0, i32 5, i64 0)
+  ret void
+}

>From 86de7c98362f4f2782540d66b3ac666dabbc07fd Mon Sep 17 00:00:00 2001
From: Marian Lukac <Marian.Lukac at arm.com>
Date: Wed, 18 Mar 2026 15:39:02 +0000
Subject: [PATCH 2/5] update test

---
 clang/test/CodeGen/arm64-microsoft-sys.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/clang/test/CodeGen/arm64-microsoft-sys.c b/clang/test/CodeGen/arm64-microsoft-sys.c
index 0abc9ea665fef..31df201fa37d3 100644
--- a/clang/test/CodeGen/arm64-microsoft-sys.c
+++ b/clang/test/CodeGen/arm64-microsoft-sys.c
@@ -33,27 +33,27 @@ void check__sys(__int64 v) {
   __int64 ret;
 
   __sys(ARM64_DC_CGDSW_EL1, v);
-// CHECK-ASM: msr     S1_0_C7_C10_6, x8
+// CHECK-ASM: sys     #0, c7, c10, #6, x8
 // CHECK-IR: %[[VAR:.*]] = load i64,
 // CHECK-IR-NEXT: call void @llvm.aarch64.sys(i32 0, i32 7, i32 10, i32 6, i64 %[[VAR]])
 
   __sys(ARM64_IC_IALLU_EL1, v);
-// CHECK-ASM: msr     S1_0_C7_C5_0, x8
+// CHECK-ASM: sys     #0, c7, c5, #0, x8
 // CHECK-IR: %[[VAR:.*]] = load i64,
 // CHECK-IR-NEXT: call void @llvm.aarch64.sys(i32 0, i32 7, i32 5, i32 0, i64 %[[VAR]])
 
   __sys(ARM64_AT_S1E2W, v);
-// CHECK-ASM: msr     S1_4_C7_C8_1, x8
+// CHECK-ASM: at      s1e2w, x8
 // CHECK-IR: %[[VAR:.*]] = load i64,
 // CHECK-IR-NEXT: call void @llvm.aarch64.sys(i32 4, i32 7, i32 8, i32 1, i64 %[[VAR]])
 
   __sys(ARM64_TLBI_VMALLE1, v);
-// CHECK-ASM: msr     S1_0_C8_C7_0, x8
+// CHECK-ASM: sys     #0, c8, c7, #0, x8
 // CHECK-IR: %[[VAR:.*]] = load i64,
 // CHECK-IR-NEXT: call void @llvm.aarch64.sys(i32 0, i32 8, i32 7, i32 0, i64 %[[VAR]])
 
   __sys(ARM64_CFP_RCTX, v);
-// CHECK-ASM: msr     S1_3_C7_C3_4, x8
+// CHECK-ASM: sys     #3, c7, c3, #4, x8
 // CHECK-IR: %[[VAR:.*]] = load i64,
 // CHECK-IR-NEXT: call void @llvm.aarch64.sys(i32 3, i32 7, i32 3, i32 4, i64 %[[VAR]])
 }

>From d144e287849ee18d1888ce1b0ce61ed799bc6a35 Mon Sep 17 00:00:00 2001
From: Marian Lukac <Marian.Lukac at arm.com>
Date: Wed, 18 Mar 2026 17:16:46 +0000
Subject: [PATCH 3/5] address comments

---
 clang/lib/CodeGen/TargetBuiltins/ARM.cpp      |  2 +-
 clang/lib/Sema/SemaARM.cpp                    |  2 +-
 .../CodeGen/arm64-microsoft-status-reg.cpp    |  2 +-
 clang/test/CodeGen/arm64-microsoft-sys.c      | 17 +++++---
 clang/test/Sema/builtins-microsoft-arm64.c    |  4 +-
 llvm/include/llvm/IR/IntrinsicsAArch64.td     |  6 +--
 .../CodeGen/AArch64/aarch64-sys-intrinsic.s   | 39 +++++++++++++++++++
 7 files changed, 58 insertions(+), 14 deletions(-)
 create mode 100644 llvm/test/CodeGen/AArch64/aarch64-sys-intrinsic.s

diff --git a/clang/lib/CodeGen/TargetBuiltins/ARM.cpp b/clang/lib/CodeGen/TargetBuiltins/ARM.cpp
index bda096f99d001..fa62e302383d1 100644
--- a/clang/lib/CodeGen/TargetBuiltins/ARM.cpp
+++ b/clang/lib/CodeGen/TargetBuiltins/ARM.cpp
@@ -5647,7 +5647,7 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
 
     std::string SysRegStr;
     llvm::raw_string_ostream(SysRegStr)
-        << (SysReg >> 14) << ":" << ((SysReg >> 11) & 7) << ":"
+        << (0b10 | SysReg >> 14) << ":" << ((SysReg >> 11) & 7) << ":"
         << ((SysReg >> 7) & 15) << ":" << ((SysReg >> 3) & 15) << ":"
         << (SysReg & 7);
 
diff --git a/clang/lib/Sema/SemaARM.cpp b/clang/lib/Sema/SemaARM.cpp
index fa4463c03b047..23ca13b495cb0 100644
--- a/clang/lib/Sema/SemaARM.cpp
+++ b/clang/lib/Sema/SemaARM.cpp
@@ -1264,7 +1264,7 @@ bool SemaARM::CheckAArch64BuiltinFunctionCall(const TargetInfo &TI,
   // an exception for incorrect registers. This matches MSVC behavior.
   if (BuiltinID == AArch64::BI_ReadStatusReg ||
       BuiltinID == AArch64::BI_WriteStatusReg)
-    return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0x4000, 0xffff);
+    return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0x4000, 0x7fff);
 
   if (BuiltinID == AArch64::BI__sys)
     return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 0x3fff);
diff --git a/clang/test/CodeGen/arm64-microsoft-status-reg.cpp b/clang/test/CodeGen/arm64-microsoft-status-reg.cpp
index c182fdf062ab8..5a942169394e3 100644
--- a/clang/test/CodeGen/arm64-microsoft-status-reg.cpp
+++ b/clang/test/CodeGen/arm64-microsoft-status-reg.cpp
@@ -14,7 +14,7 @@
 
 // From winnt.h
 #define ARM64_SYSREG(op0, op1, crn, crm, op2) \
-        ( ((op0 & 3) << 14) | \
+        ( ((op0 & 1) << 14) | \
           ((op1 & 7) << 11) | \
           ((crn & 15) << 7) | \
           ((crm & 15) << 3) | \
diff --git a/clang/test/CodeGen/arm64-microsoft-sys.c b/clang/test/CodeGen/arm64-microsoft-sys.c
index 31df201fa37d3..8a9b2cc084cc1 100644
--- a/clang/test/CodeGen/arm64-microsoft-sys.c
+++ b/clang/test/CodeGen/arm64-microsoft-sys.c
@@ -11,7 +11,7 @@
 
 // From winnt.h
 // op0=1 encodings, use with __sys
-#define ARM64_SYSINSTR(op1, crn, crm, op2) \
+#define ARM64_SYSINSTR(op0, op1, crn, crm, op2) \
         ( ((op1 & 7) << 11) | \
           ((crn & 15) << 7) | \
           ((crm & 15) << 3) | \
@@ -20,11 +20,11 @@
 //
 // Sampling of instructions
 //
-#define ARM64_DC_CGDSW_EL1      ARM64_SYSINSTR(0, 7,10,6) // Clean of Data and Allocation Tags by Set/Way
-#define ARM64_IC_IALLU_EL1      ARM64_SYSINSTR(0, 7, 5,0) // Instruction Cache Invalidate All to PoU
-#define ARM64_AT_S1E2W          ARM64_SYSINSTR(4, 7, 8,1) // Translate Stage1, EL2, write
-#define ARM64_TLBI_VMALLE1      ARM64_SYSINSTR(0, 8, 7,0) // Invalidate stage 1 TLB [CP15_TLBIALL]
-#define ARM64_CFP_RCTX          ARM64_SYSINSTR(3, 7, 3,4) // Control Flow Prediction Restriction by Context
+#define ARM64_DC_CGDSW_EL1      ARM64_SYSINSTR(1,0, 7,10,6) // Clean of Data and Allocation Tags by Set/Way
+#define ARM64_IC_IALLU_EL1      ARM64_SYSINSTR(1,0, 7, 5,0) // Instruction Cache Invalidate All to PoU
+#define ARM64_AT_S1E2W          ARM64_SYSINSTR(1,4, 7, 8,1) // Translate Stage1, EL2, write
+#define ARM64_TLBI_VMALLE1      ARM64_SYSINSTR(1,0, 8, 7,0) // Invalidate stage 1 TLB [CP15_TLBIALL]
+#define ARM64_CFP_RCTX          ARM64_SYSINSTR(1,3, 7, 3,4) // Control Flow Prediction Restriction by Context
 
 // From intrin.h
 unsigned int __sys(int, __int64);
@@ -50,6 +50,11 @@ void check__sys(__int64 v) {
   __sys(ARM64_TLBI_VMALLE1, v);
 // CHECK-ASM: sys     #0, c8, c7, #0, x8
 // CHECK-IR: %[[VAR:.*]] = load i64,
+// CHECK-IR-NEXT: call void @llvm.aarch64.sys(i32 0, i32 8, i32 7, i32 0, i64 %[[VAR]])
+
+  __sys(ARM64_TLBI_VMALLE1, 0);
+// CHECK-ASM: sys     #0, c8, c7, #0, x8
+// CHECK-IR: %[[VAR:.*]] = load i64,
 // CHECK-IR-NEXT: call void @llvm.aarch64.sys(i32 0, i32 8, i32 7, i32 0, i64 %[[VAR]])
 
   __sys(ARM64_CFP_RCTX, v);
diff --git a/clang/test/Sema/builtins-microsoft-arm64.c b/clang/test/Sema/builtins-microsoft-arm64.c
index 738f8c6e02bd5..22163ab3fa851 100644
--- a/clang/test/Sema/builtins-microsoft-arm64.c
+++ b/clang/test/Sema/builtins-microsoft-arm64.c
@@ -27,10 +27,10 @@ void check_ReadWriteStatusReg(int v) {
 
 void check_ReadWriteStatusReg_range(int v) {
   _ReadStatusReg(0x3fff);      // expected-error-re {{argument value {{.*}} is outside the valid range}}
-  _ReadStatusReg(0x10000); // expected-error-re {{argument value {{.*}} is outside the valid range}}
+  _ReadStatusReg(0x8000); // expected-error-re {{argument value {{.*}} is outside the valid range}}
 
   _WriteStatusReg(0x3fff, v);  // expected-error-re {{argument value {{.*}} is outside the valid range}}
-  _WriteStatusReg(0x10000, v); // expected-error-re {{argument value {{.*}} is outside the valid range}}
+  _WriteStatusReg(0x8000, v); // expected-error-re {{argument value {{.*}} is outside the valid range}}
 }
 
 void check__sys(int v) {
diff --git a/llvm/include/llvm/IR/IntrinsicsAArch64.td b/llvm/include/llvm/IR/IntrinsicsAArch64.td
index 6f645548abe1d..63500beaa6521 100644
--- a/llvm/include/llvm/IR/IntrinsicsAArch64.td
+++ b/llvm/include/llvm/IR/IntrinsicsAArch64.td
@@ -58,9 +58,9 @@ def int_aarch64_frint64x
                             [ IntrNoMem ]>;
 
 def int_aarch64_sys  : DefaultAttrsIntrinsic<[], [llvm_i32_ty, llvm_i32_ty,
-                 llvm_i32_ty, llvm_i32_ty, llvm_i64_ty],
-    [IntrNoMem, IntrHasSideEffects, ImmArg<ArgIndex<0>>, ImmArg<ArgIndex<1>>, ImmArg<ArgIndex<2>>,
-     ImmArg<ArgIndex<3>>]>;
+                       llvm_i32_ty, llvm_i32_ty, llvm_i64_ty],
+                       [ImmArg<ArgIndex<0>>, ImmArg<ArgIndex<1>>, ImmArg<ArgIndex<2>>,
+                       ImmArg<ArgIndex<3>>]>;
 //===----------------------------------------------------------------------===//
 // HINT
 
diff --git a/llvm/test/CodeGen/AArch64/aarch64-sys-intrinsic.s b/llvm/test/CodeGen/AArch64/aarch64-sys-intrinsic.s
new file mode 100644
index 0000000000000..7d2ccb9f459ca
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/aarch64-sys-intrinsic.s
@@ -0,0 +1,39 @@
+	.file	"aarch64-sys-intrinsic.ll"
+	.text
+	.globl	sys_cgdsw                       // -- Begin function sys_cgdsw
+	.p2align	2
+	.type	sys_cgdsw, at function
+sys_cgdsw:                              // @sys_cgdsw
+	.cfi_startproc
+// %bb.0:                               // %entry
+	sys	#0, c7, c10, #6, x0
+	ret
+.Lfunc_end0:
+	.size	sys_cgdsw, .Lfunc_end0-sys_cgdsw
+	.cfi_endproc
+                                        // -- End function
+	.globl	sys_s1e2w                       // -- Begin function sys_s1e2w
+	.p2align	2
+	.type	sys_s1e2w, at function
+sys_s1e2w:                              // @sys_s1e2w
+	.cfi_startproc
+// %bb.0:                               // %entry
+	at	s1e2w, x0
+	ret
+.Lfunc_end1:
+	.size	sys_s1e2w, .Lfunc_end1-sys_s1e2w
+	.cfi_endproc
+                                        // -- End function
+	.globl	sys_vmalle1                     // -- Begin function sys_vmalle1
+	.p2align	2
+	.type	sys_vmalle1, at function
+sys_vmalle1:                            // @sys_vmalle1
+	.cfi_startproc
+// %bb.0:                               // %entry
+	sys	#0, c8, c7, #0, x0
+	ret
+.Lfunc_end2:
+	.size	sys_vmalle1, .Lfunc_end2-sys_vmalle1
+	.cfi_endproc
+                                        // -- End function
+	.section	".note.GNU-stack","", at progbits

>From 8270373838e0b05342c11f11dacbe7aa57654a86 Mon Sep 17 00:00:00 2001
From: Marian Lukac <Marian.Lukac at arm.com>
Date: Wed, 18 Mar 2026 17:45:34 +0000
Subject: [PATCH 4/5] remove pointless test

---
 clang/test/CodeGen/arm64-microsoft-sys.c | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/clang/test/CodeGen/arm64-microsoft-sys.c b/clang/test/CodeGen/arm64-microsoft-sys.c
index 8a9b2cc084cc1..0268584c5fd13 100644
--- a/clang/test/CodeGen/arm64-microsoft-sys.c
+++ b/clang/test/CodeGen/arm64-microsoft-sys.c
@@ -50,11 +50,6 @@ void check__sys(__int64 v) {
   __sys(ARM64_TLBI_VMALLE1, v);
 // CHECK-ASM: sys     #0, c8, c7, #0, x8
 // CHECK-IR: %[[VAR:.*]] = load i64,
-// CHECK-IR-NEXT: call void @llvm.aarch64.sys(i32 0, i32 8, i32 7, i32 0, i64 %[[VAR]])
-
-  __sys(ARM64_TLBI_VMALLE1, 0);
-// CHECK-ASM: sys     #0, c8, c7, #0, x8
-// CHECK-IR: %[[VAR:.*]] = load i64,
 // CHECK-IR-NEXT: call void @llvm.aarch64.sys(i32 0, i32 8, i32 7, i32 0, i64 %[[VAR]])
 
   __sys(ARM64_CFP_RCTX, v);

>From e87fa1ecbf4772d8139ec00b5dc9459df551724b Mon Sep 17 00:00:00 2001
From: Marian Lukac <Marian.Lukac at arm.com>
Date: Thu, 19 Mar 2026 16:29:01 +0000
Subject: [PATCH 5/5] remove s file

---
 .../CodeGen/AArch64/aarch64-sys-intrinsic.s   | 39 -------------------
 1 file changed, 39 deletions(-)
 delete mode 100644 llvm/test/CodeGen/AArch64/aarch64-sys-intrinsic.s

diff --git a/llvm/test/CodeGen/AArch64/aarch64-sys-intrinsic.s b/llvm/test/CodeGen/AArch64/aarch64-sys-intrinsic.s
deleted file mode 100644
index 7d2ccb9f459ca..0000000000000
--- a/llvm/test/CodeGen/AArch64/aarch64-sys-intrinsic.s
+++ /dev/null
@@ -1,39 +0,0 @@
-	.file	"aarch64-sys-intrinsic.ll"
-	.text
-	.globl	sys_cgdsw                       // -- Begin function sys_cgdsw
-	.p2align	2
-	.type	sys_cgdsw, at function
-sys_cgdsw:                              // @sys_cgdsw
-	.cfi_startproc
-// %bb.0:                               // %entry
-	sys	#0, c7, c10, #6, x0
-	ret
-.Lfunc_end0:
-	.size	sys_cgdsw, .Lfunc_end0-sys_cgdsw
-	.cfi_endproc
-                                        // -- End function
-	.globl	sys_s1e2w                       // -- Begin function sys_s1e2w
-	.p2align	2
-	.type	sys_s1e2w, at function
-sys_s1e2w:                              // @sys_s1e2w
-	.cfi_startproc
-// %bb.0:                               // %entry
-	at	s1e2w, x0
-	ret
-.Lfunc_end1:
-	.size	sys_s1e2w, .Lfunc_end1-sys_s1e2w
-	.cfi_endproc
-                                        // -- End function
-	.globl	sys_vmalle1                     // -- Begin function sys_vmalle1
-	.p2align	2
-	.type	sys_vmalle1, at function
-sys_vmalle1:                            // @sys_vmalle1
-	.cfi_startproc
-// %bb.0:                               // %entry
-	sys	#0, c8, c7, #0, x0
-	ret
-.Lfunc_end2:
-	.size	sys_vmalle1, .Lfunc_end2-sys_vmalle1
-	.cfi_endproc
-                                        // -- End function
-	.section	".note.GNU-stack","", at progbits



More information about the cfe-commits mailing list