Author: Lukacma
Date: 2026-03-23T10:12:41Z
New Revision: 9426fc19afb106ff964a43ab7f3c7a0be940111c

URL: 
https://github.com/llvm/llvm-project/commit/9426fc19afb106ff964a43ab7f3c7a0be940111c
DIFF: 
https://github.com/llvm/llvm-project/commit/9426fc19afb106ff964a43ab7f3c7a0be940111c.diff

LOG: [AArch64] Fix _sys implemantation and MRS/MSR Sema checks (#187290)

This patch fixes lowering of _sys builtin, which used to lower into
invalid MSR S1... instruction. This was fixed by adding new sys llvm
intrinsic and proper lowering into sys instruction and its aliases.

I also fixed the sema check for _sys, _ReadStatusRegister and
_WriteStatusRegister builtins so they correctly capture invalid
usecases.

Added: 
    llvm/test/CodeGen/AArch64/aarch64-sys-intrinsic.ll

Modified: 
    clang/lib/CodeGen/TargetBuiltins/ARM.cpp
    clang/lib/Sema/SemaARM.cpp
    clang/test/CodeGen/arm64-microsoft-sys.c
    clang/test/Sema/builtins-microsoft-arm64.c
    llvm/include/llvm/IR/IntrinsicsAArch64.td
    llvm/lib/Target/AArch64/AArch64InstrFormats.td
    llvm/lib/Target/AArch64/AArch64InstrInfo.td
    llvm/test/tools/llvm-mca/AArch64/Neoverse/V1-misc-instructions.s

Removed: 
    


################################################################################
diff  --git a/clang/lib/CodeGen/TargetBuiltins/ARM.cpp 
b/clang/lib/CodeGen/TargetBuiltins/ARM.cpp
index ed157c198c510..8ec2f5b83085c 100644
--- a/clang/lib/CodeGen/TargetBuiltins/ARM.cpp
+++ b/clang/lib/CodeGen/TargetBuiltins/ARM.cpp
@@ -5022,20 +5022,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) << ":"
+        << (0b10 | SysReg >> 14) << ":" << ((SysReg >> 11) & 7) << ":"
         << ((SysReg >> 7) & 15) << ":" << ((SysReg >> 3) & 15) << ":"
         << (SysReg & 7);
 
@@ -5055,14 +5050,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 f4b811af6a100..e54c8228e5ff8 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, 0x7fff);
+
+  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-sys.c 
b/clang/test/CodeGen/arm64-microsoft-sys.c
index 5913a02d933ae..0268584c5fd13 100644
--- a/clang/test/CodeGen/arm64-microsoft-sys.c
+++ b/clang/test/CodeGen/arm64-microsoft-sys.c
@@ -33,33 +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.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-ASM: sys     #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-ASM: at      s1e2w, 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-ASM: sys     #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-ASM: sys     #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..22163ab3fa851 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(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(0x8000, 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..63500beaa6521 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],
+                       [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 43727188a06d0..19312d34609ce 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;
@@ -2135,6 +2140,10 @@ class SystemXtI<bit L, string asm>
   let Inst{15-12} = Cn;
   let Inst{11-8}  = Cm;
   let Inst{7-5}   = op2;
+
+  let mayLoad = 1;
+  let mayStore = 1;
+  let hasSideEffects = 1;
 }
 
 class SystemLXtI<bit L, string asm>

diff  --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td 
b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
index 44968b14b11a9..2ecfdcf1508ac 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
@@ -2567,12 +2567,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
+}

diff  --git a/llvm/test/tools/llvm-mca/AArch64/Neoverse/V1-misc-instructions.s 
b/llvm/test/tools/llvm-mca/AArch64/Neoverse/V1-misc-instructions.s
index 53ade6eeb77a8..37975ab269d10 100644
--- a/llvm/test/tools/llvm-mca/AArch64/Neoverse/V1-misc-instructions.s
+++ b/llvm/test/tools/llvm-mca/AArch64/Neoverse/V1-misc-instructions.s
@@ -30,7 +30,7 @@ sysl x16, #5, c11, c8, #5
 # CHECK-NEXT: [6]: HasSideEffects (U)
 
 # CHECK:      [1]    [2]    [3]    [4]    [5]    [6]    Instructions:
-# CHECK-NEXT:  1      1     0.13                  U     at     s12e1r, x28
+# CHECK-NEXT:  1      1     0.13    *      *      U     at     s12e1r, x28
 # CHECK-NEXT:  1      1     0.13                  U     brk    #0x8415
 # CHECK-NEXT:  1      1     0.13    *      *      U     clrex
 # CHECK-NEXT:  1      1     0.13    *      *      U     csdb


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to