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
