From cd5afb986fbbc6ceb68e2b4c6afc48bd1c8bf02e Mon Sep 17 00:00:00 2001 From: Adam Glass Date: Fri, 13 Jun 2025 17:59:20 -0700 Subject: [PATCH 1/2] __sys builtin support --- clang/include/clang/Basic/BuiltinsAArch64.def | 1 + clang/lib/CodeGen/TargetBuiltins/ARM.cpp | 25 ++++--- clang/lib/Headers/intrin.h | 1 + clang/lib/Sema/SemaARM.cpp | 2 +- clang/test/CodeGen/arm64-microsoft-sys.c | 68 +++++++++++++++++++ clang/test/Sema/builtins-microsoft-arm64.c | 9 +++ 6 files changed, 96 insertions(+), 10 deletions(-) create mode 100644 clang/test/CodeGen/arm64-microsoft-sys.c diff --git a/clang/include/clang/Basic/BuiltinsAArch64.def b/clang/include/clang/Basic/BuiltinsAArch64.def index 8867a9fe09fb9..3bb329d210c07 100644 --- a/clang/include/clang/Basic/BuiltinsAArch64.def +++ b/clang/include/clang/Basic/BuiltinsAArch64.def @@ -267,6 +267,7 @@ TARGET_HEADER_BUILTIN(_ReadWriteBarrier, "v", "nh", INTRIN_H, ALL_MS_LANGUAGES, TARGET_HEADER_BUILTIN(__getReg, "ULLii", "nh", INTRIN_H, ALL_MS_LANGUAGES, "") TARGET_HEADER_BUILTIN(_ReadStatusReg, "LLii", "nh", INTRIN_H, ALL_MS_LANGUAGES, "") TARGET_HEADER_BUILTIN(_WriteStatusReg, "viLLi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "") +TARGET_HEADER_BUILTIN(__sys, "UiiLLi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "") TARGET_HEADER_BUILTIN(_AddressOfReturnAddress, "v*", "nh", INTRIN_H, ALL_MS_LANGUAGES, "") TARGET_HEADER_BUILTIN(__mulh, "SLLiSLLiSLLi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "") diff --git a/clang/lib/CodeGen/TargetBuiltins/ARM.cpp b/clang/lib/CodeGen/TargetBuiltins/ARM.cpp index dab311903f6dd..d1c62c6b754a5 100644 --- a/clang/lib/CodeGen/TargetBuiltins/ARM.cpp +++ b/clang/lib/CodeGen/TargetBuiltins/ARM.cpp @@ -5471,19 +5471,21 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID, } if (BuiltinID == clang::AArch64::BI_ReadStatusReg || - BuiltinID == clang::AArch64::BI_WriteStatusReg) { + BuiltinID == clang::AArch64::BI_WriteStatusReg || + BuiltinID == clang::AArch64::BI__sys) { LLVMContext &Context = CGM.getLLVMContext(); unsigned SysReg = E->getArg(0)->EvaluateKnownConstInt(getContext()).getZExtValue(); std::string SysRegStr; - llvm::raw_string_ostream(SysRegStr) << - ((1 << 1) | ((SysReg >> 14) & 1)) << ":" << - ((SysReg >> 11) & 7) << ":" << - ((SysReg >> 7) & 15) << ":" << - ((SysReg >> 3) & 15) << ":" << - ( SysReg & 7); + unsigned SysRegOp0 = (BuiltinID != clang::AArch64::BI__sys) + ? ((1 << 1) | ((SysReg >> 14) & 1)) + : 1; + llvm::raw_string_ostream(SysRegStr) + << SysRegOp0 << ":" << ((SysReg >> 11) & 7) << ":" + << ((SysReg >> 7) & 15) << ":" << ((SysReg >> 3) & 15) << ":" + << (SysReg & 7); llvm::Metadata *Ops[] = { llvm::MDString::get(Context, SysRegStr) }; llvm::MDNode *RegName = llvm::MDNode::get(Context, Ops); @@ -5500,8 +5502,13 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID, llvm::Function *F = CGM.getIntrinsic(Intrinsic::write_register, Types); llvm::Value *ArgValue = EmitScalarExpr(E->getArg(1)); - - return Builder.CreateCall(F, { Metadata, ArgValue }); + 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_AddressOfReturnAddress) { diff --git a/clang/lib/Headers/intrin.h b/clang/lib/Headers/intrin.h index 3dd1eb45817d4..0ab69fd403d2d 100644 --- a/clang/lib/Headers/intrin.h +++ b/clang/lib/Headers/intrin.h @@ -374,6 +374,7 @@ long _InterlockedAdd(long volatile *Addend, long Value); __int64 _InterlockedAdd64(__int64 volatile *Addend, __int64 Value); __int64 _ReadStatusReg(int); void _WriteStatusReg(int, __int64); +unsigned int __sys(int, __int64); unsigned short __cdecl _byteswap_ushort(unsigned short val); unsigned long __cdecl _byteswap_ulong (unsigned long val); diff --git a/clang/lib/Sema/SemaARM.cpp b/clang/lib/Sema/SemaARM.cpp index e992a1012fde0..d76f1a62ff2b7 100644 --- a/clang/lib/Sema/SemaARM.cpp +++ b/clang/lib/Sema/SemaARM.cpp @@ -1084,7 +1084,7 @@ bool SemaARM::CheckAArch64BuiltinFunctionCall(const TargetInfo &TI, // converted to a register of the form S1_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_WriteStatusReg || BuiltinID == AArch64::BI__sys) return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 0x7fff); if (BuiltinID == AArch64::BI__getReg) diff --git a/clang/test/CodeGen/arm64-microsoft-sys.c b/clang/test/CodeGen/arm64-microsoft-sys.c new file mode 100644 index 0000000000000..a9790de43341f --- /dev/null +++ b/clang/test/CodeGen/arm64-microsoft-sys.c @@ -0,0 +1,68 @@ +// REQUIRES: aarch64-registered-target + +// RUN: %clang_cc1 -triple arm64-windows -fms-compatibility -S \ +// RUN: -o - %s | FileCheck %s -check-prefix CHECK-ASM + +// RUN: %clang_cc1 -triple arm64-darwin -fms-compatibility -S \ +// RUN: -o - %s | FileCheck %s -check-prefix CHECK-ASM + +// RUN: %clang_cc1 -triple arm64-windows -fms-compatibility -emit-llvm \ +// RUN: -o - %s | FileCheck %s -check-prefix CHECK-IR + +// RUN: %clang_cc1 -triple arm64-darwin -fms-compatibility -emit-llvm \ +// RUN: -o - %s | FileCheck %s -check-prefix CHECK-IR + +// From winnt.h +// op0=1 encodings, use with __sys +#define ARM64_SYSINSTR(op0, op1, crn, crm, op2) \ + ( ((op1 & 7) << 11) | \ + ((crn & 15) << 7) | \ + ((crm & 15) << 3) | \ + ((op2 & 7) << 0) ) + +// +// 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 + +// From intrin.h +unsigned int __sys(int, __int64); + +void check__sys(__int64 v) { + __int64 ret; + + __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]]) + + __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]]) + + __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]]) + + __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]]) + + __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: ![[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 322cf7542f43a..a915a370cde14 100644 --- a/clang/test/Sema/builtins-microsoft-arm64.c +++ b/clang/test/Sema/builtins-microsoft-arm64.c @@ -24,3 +24,12 @@ void check_ReadWriteStatusReg(int v) { _ReadStatusReg(x); // expected-error {{argument to '_ReadStatusReg' must be a constant integer}} _WriteStatusReg(x, v); // expected-error {{argument to '_WriteStatusReg' must be a constant integer}} } + +void check__sys(int v) { + int x; + __sys(x, v); // expected-error {{argument to '__sys' must be a constant integer}} +} + +unsigned int check__sys_retval() { + return __sys(0, 1); // builtin has superfluous return value for MSVC compatibility +} From fa253f40895f3347b6d7ddd2027c4b93d6e5d2db Mon Sep 17 00:00:00 2001 From: Adam Glass Date: Fri, 20 Jun 2025 18:16:37 -0700 Subject: [PATCH 2/2] Address feedback --- clang/lib/CodeGen/TargetBuiltins/ARM.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clang/lib/CodeGen/TargetBuiltins/ARM.cpp b/clang/lib/CodeGen/TargetBuiltins/ARM.cpp index d1c62c6b754a5..935447f0b0931 100644 --- a/clang/lib/CodeGen/TargetBuiltins/ARM.cpp +++ b/clang/lib/CodeGen/TargetBuiltins/ARM.cpp @@ -5479,7 +5479,8 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID, E->getArg(0)->EvaluateKnownConstInt(getContext()).getZExtValue(); std::string SysRegStr; - unsigned SysRegOp0 = (BuiltinID != clang::AArch64::BI__sys) + unsigned SysRegOp0 = (BuiltinID == clang::AArch64::BI_ReadStatusReg || + BuiltinID == clang::AArch64::BI_WriteStatusReg) ? ((1 << 1) | ((SysReg >> 14) & 1)) : 1; llvm::raw_string_ostream(SysRegStr)