llvmbot wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Adam Glass (AdamGlass)

<details>
<summary>Changes</summary>

Adds support for __sys Clang builtin for Aarch64

__sys is a long existing MSVC intrinsic used to manage caches, tlbs, etc by 
writing to system registers:
• It takes a macro-generated constant and uses it to form the AArch64 SYS 
instruction which is MSR with op0=1.  The macro drops op0 and expects the 
implementation to hardcode it to 1 in the encoding.
• Volume use is in systems code (kernels, hypervisors, boot environments, 
firmware)
• Has an unused return value due to MSVC cut/paste error

Implementation:
• Clang builtin, sharing code with Read/WriteStatusReg
• Hardcodes the op0=1
• Explicitly returns 0
• Code-format change from clang-format
• Unittests included
• Not limited to MSVC-environment as its generally useful and neutral

Adam Glass
adamglass@<!-- -->spottedfoobar.com 
adamglass@<!-- -->microsoft.com              
@<!-- -->dpaoliello
        

---
Full diff: https://github.com/llvm/llvm-project/pull/145079.diff


6 Files Affected:

- (modified) clang/include/clang/Basic/BuiltinsAArch64.def (+1) 
- (modified) clang/lib/CodeGen/TargetBuiltins/ARM.cpp (+16-9) 
- (modified) clang/lib/Headers/intrin.h (+1) 
- (modified) clang/lib/Sema/SemaARM.cpp (+1-1) 
- (added) clang/test/CodeGen/arm64-microsoft-sys.c (+68) 
- (modified) clang/test/Sema/builtins-microsoft-arm64.c (+9) 


``````````diff
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
+}

``````````

</details>


https://github.com/llvm/llvm-project/pull/145079
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to