llvmorg-github-actions[bot] wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-arm

Author: Adhemerval Zanella (zatrazz)

<details>
<summary>Changes</summary>

This series implements three additional Microsoft `intrin.h` intrinsics in 
clang so MSVC-compatible code can build with clang.

| Target | Intrinsic | Description |
|--------|-----------|-------------|
| AArch64 | `__svc` | Supervisor Call (`SVC #imm`) |
| AArch64 | `__hvc` | Hypervisor Call (`HVC #imm`) |
| AArch64 | `_InterlockedCompareExchangePointer_nf` | Pointer 
compare-and-exchange, no memory barrier (relaxed) |

`__hvc` and `__svc` each require a new LLVM intrinsic (`llvm.aarch64.hvc` / 
`llvm.aarch64.svc`) to carry the immediate operand down to instruction 
selection.

`_InterlockedCompareExchangePointer_nf` is the relaxed (`_nf`, "no fence") form 
of the existing `_InterlockedCompareExchangePointer` family and is wired up for 
both the ARM and AArch64 targets.

These follow the MSVC semantics, where the intrinsics behave like inline 
assembly: the compiler emits the requested instruction directly and does not 
verify that the target's enabled ISA actually supports it. The `__hvc` / 
`__svc` immediate is range-checked as a compile-time constant (matching `cl`), 
but there is no feature/`-march` gating — emitting the instruction is the 
user's responsibility.

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


11 Files Affected:

- (modified) clang/include/clang/Basic/BuiltinsAArch64.td (+3) 
- (modified) clang/lib/CodeGen/TargetBuiltins/ARM.cpp (+13) 
- (modified) clang/lib/Headers/intrin.h (+2) 
- (modified) clang/lib/Sema/SemaARM.cpp (+6) 
- (modified) clang/test/CodeGen/arm64-microsoft-intrinsics.c (+20) 
- (modified) clang/test/CodeGen/ms-intrinsics.c (+8) 
- (modified) clang/test/Sema/builtins-microsoft-arm64.c (+12) 
- (modified) llvm/include/llvm/IR/IntrinsicsAArch64.td (+6) 
- (modified) llvm/lib/Target/AArch64/AArch64InstrInfo.td (+4-2) 
- (added) llvm/test/CodeGen/AArch64/arm64-hvc.ll (+10) 
- (added) llvm/test/CodeGen/AArch64/arm64-svc.ll (+10) 


``````````diff
diff --git a/clang/include/clang/Basic/BuiltinsAArch64.td 
b/clang/include/clang/Basic/BuiltinsAArch64.td
index 15257f3db5b41..0d2e936d7b7b3 100644
--- a/clang/include/clang/Basic/BuiltinsAArch64.td
+++ b/clang/include/clang/Basic/BuiltinsAArch64.td
@@ -253,6 +253,7 @@ let Attributes = [NoThrow, RequireDeclaration], Languages = 
"ALL_MS_LANGUAGES",
        def _InterlockedCompareExchange64_nf       : 
AArch64NoPrefixTargetLibBuiltin<"long long int (long long int volatile *, long 
long int, long long int)">;
        def _InterlockedCompareExchange64_rel      : 
AArch64NoPrefixTargetLibBuiltin<"long long int (long long int volatile *, long 
long int, long long int)">;
        def _InterlockedCompareExchangePointer_acq : 
AArch64NoPrefixTargetLibBuiltin<"void * (void * volatile *, void *, void *)">;
+       def _InterlockedCompareExchangePointer_nf  : 
AArch64NoPrefixTargetLibBuiltin<"void * (void * volatile *, void *, void *)">;
        def _InterlockedCompareExchangePointer_rel : 
AArch64NoPrefixTargetLibBuiltin<"void * (void * volatile *, void *, void *)">;
 }
 
@@ -408,4 +409,6 @@ let Attributes = [NoThrow, RequireDeclaration], Languages = 
"ALL_MS_LANGUAGES",
 
 let Attributes = [NoThrow, RequireDeclaration], Languages = 
"ALL_MS_LANGUAGES", Header = "intrin.h" in {
        def __hlt : AArch64NoPrefixTargetLibBuiltin<"unsigned int (unsigned 
int, ...)">;
+       def __hvc : AArch64NoPrefixTargetLibBuiltin<"unsigned int (unsigned 
int, ...)">;
+       def __svc : AArch64NoPrefixTargetLibBuiltin<"unsigned int (unsigned 
int, ...)">;
 }
diff --git a/clang/lib/CodeGen/TargetBuiltins/ARM.cpp 
b/clang/lib/CodeGen/TargetBuiltins/ARM.cpp
index ece8ff21561cf..00b90eee21565 100644
--- a/clang/lib/CodeGen/TargetBuiltins/ARM.cpp
+++ b/clang/lib/CodeGen/TargetBuiltins/ARM.cpp
@@ -106,6 +106,7 @@ translateAarch64ToMsvcIntrin(unsigned BuiltinID) {
   case clang::AArch64::BI_InterlockedCompareExchange16_nf:
   case clang::AArch64::BI_InterlockedCompareExchange_nf:
   case clang::AArch64::BI_InterlockedCompareExchange64_nf:
+  case clang::AArch64::BI_InterlockedCompareExchangePointer_nf:
     return MSVCIntrin::_InterlockedCompareExchange_nf;
   case clang::AArch64::BI_InterlockedCompareExchange128:
     return MSVCIntrin::_InterlockedCompareExchange128;
@@ -5327,6 +5328,18 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned 
BuiltinID,
     return ConstantInt::get(Builder.getInt32Ty(), 0);
   }
 
+  if (BuiltinID == AArch64::BI__hvc) {
+    Function *F = CGM.getIntrinsic(Intrinsic::aarch64_hvc);
+    Builder.CreateCall(F, {EmitScalarExpr(E->getArg(0))});
+    return ConstantInt::get(Builder.getInt32Ty(), 0);
+  }
+
+  if (BuiltinID == AArch64::BI__svc) {
+    Function *F = CGM.getIntrinsic(Intrinsic::aarch64_svc);
+    Builder.CreateCall(F, {EmitScalarExpr(E->getArg(0))});
+    return ConstantInt::get(Builder.getInt32Ty(), 0);
+  }
+
   if (BuiltinID == NEON::BI__builtin_neon_vcvth_bf16_f32)
     return Builder.CreateFPTrunc(
         Builder.CreateBitCast(EmitScalarExpr(E->getArg(0)),
diff --git a/clang/lib/Headers/intrin.h b/clang/lib/Headers/intrin.h
index 4cb8cac960bcf..7dcb5a526afb2 100644
--- a/clang/lib/Headers/intrin.h
+++ b/clang/lib/Headers/intrin.h
@@ -448,6 +448,8 @@ unsigned int _CountTrailingZeros(unsigned long);
 unsigned int _CountTrailingZeros64(unsigned __int64);
 
 unsigned int __hlt(unsigned int, ...);
+unsigned int __hvc(unsigned int, ...);
+unsigned int __svc(unsigned int, ...);
 
 void __cdecl __prefetch(const void *);
 void __cdecl __prefetch2(const void *, unsigned char);
diff --git a/clang/lib/Sema/SemaARM.cpp b/clang/lib/Sema/SemaARM.cpp
index 5e7504fab416d..664525fdb3232 100644
--- a/clang/lib/Sema/SemaARM.cpp
+++ b/clang/lib/Sema/SemaARM.cpp
@@ -1189,6 +1189,12 @@ bool SemaARM::CheckAArch64BuiltinFunctionCall(const 
TargetInfo &TI,
   if (BuiltinID == AArch64::BI__hlt)
     return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 0xffff);
 
+  if (BuiltinID == AArch64::BI__hvc)
+    return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 0xffff);
+
+  if (BuiltinID == AArch64::BI__svc)
+    return SemaRef.BuiltinConstantArgRange(TheCall, 0, 0, 0xffff);
+
   if (CheckNeonBuiltinFunctionCall(TI, BuiltinID, TheCall))
     return true;
 
diff --git a/clang/test/CodeGen/arm64-microsoft-intrinsics.c 
b/clang/test/CodeGen/arm64-microsoft-intrinsics.c
index e6a415a0d8805..5bb7d1f9f4a7d 100644
--- a/clang/test/CodeGen/arm64-microsoft-intrinsics.c
+++ b/clang/test/CodeGen/arm64-microsoft-intrinsics.c
@@ -147,6 +147,26 @@ void check__hlt() {
 // CHECK-MSVC: call void @llvm.aarch64.hlt(i32 0)
 // CHECK-LINUX: error: call to undeclared function '__hlt'
 
+void check__hvc() {
+  __hvc(0);
+  __hvc(1);
+}
+
+// CHECK-MSVC-LABEL: define {{.*}} void @check__hvc()
+// CHECK-MSVC: call void @llvm.aarch64.hvc(i32 0)
+// CHECK-MSVC: call void @llvm.aarch64.hvc(i32 1)
+// CHECK-LINUX: error: call to undeclared function '__hvc'
+
+void check__svc() {
+  __svc(0);
+  __svc(1);
+}
+
+// CHECK-MSVC-LABEL: define {{.*}} void @check__svc()
+// CHECK-MSVC: call void @llvm.aarch64.svc(i32 0)
+// CHECK-MSVC: call void @llvm.aarch64.svc(i32 1)
+// CHECK-LINUX: error: call to undeclared function '__svc'
+
 unsigned __int64 check__getReg(void) {
   unsigned volatile __int64 reg;
   reg = __getReg(18);
diff --git a/clang/test/CodeGen/ms-intrinsics.c 
b/clang/test/CodeGen/ms-intrinsics.c
index 8b719ef8cc1fd..8e1c721ac4bc0 100644
--- a/clang/test/CodeGen/ms-intrinsics.c
+++ b/clang/test/CodeGen/ms-intrinsics.c
@@ -283,6 +283,14 @@ void *test_InterlockedCompareExchangePointer_nf(void * 
volatile *Destination,
 // CHECK:   %[[RESULT:[0-9]+]] = inttoptr [[iPTR]] %[[EXTRACT]] to ptr
 // CHECK:   ret ptr %[[RESULT:[0-9]+]]
 // CHECK: }
+// CHECK-ARM64: define{{.*}}ptr @test_InterlockedCompareExchangePointer_nf(ptr 
{{.*}}%Destination, ptr {{[a-z_ ]*}}%Exchange, ptr {{[a-z_ 
]*}}%Comparand){{.*}}{
+// CHECK-ARM64:   %[[EXCHANGE:[0-9]+]] = ptrtoint ptr %Exchange to [[iPTR]]
+// CHECK-ARM64:   %[[COMPARAND:[0-9]+]] = ptrtoint ptr %Comparand to [[iPTR]]
+// CHECK-ARM64:   %[[XCHG:[0-9]+]] = cmpxchg volatile ptr %[[DEST:.+]], 
[[iPTR]] %[[COMPARAND:[0-9]+]], [[iPTR]] %[[EXCHANGE:[0-9]+]] monotonic 
monotonic, align {{4|8}}
+// CHECK-ARM64:   %[[EXTRACT:[0-9]+]] = extractvalue { [[iPTR]], i1 } 
%[[XCHG]], 0
+// CHECK-ARM64:   %[[RESULT:[0-9]+]] = inttoptr [[iPTR]] %[[EXTRACT]] to ptr
+// CHECK-ARM64:   ret ptr %[[RESULT:[0-9]+]]
+// CHECK-ARM64: }
 
 #if defined(__arm__) || defined(__aarch64__)
 void *test_InterlockedCompareExchangePointer_acq(void * volatile *Destination,
diff --git a/clang/test/Sema/builtins-microsoft-arm64.c 
b/clang/test/Sema/builtins-microsoft-arm64.c
index 22163ab3fa851..6e07a75af9a46 100644
--- a/clang/test/Sema/builtins-microsoft-arm64.c
+++ b/clang/test/Sema/builtins-microsoft-arm64.c
@@ -14,6 +14,18 @@ void check__hlt() {
   __hlt(65536); // expected-error-re {{argument value {{.*}} is outside the 
valid range}}
 }
 
+void check__hvc(unsigned int x) {
+  __hvc(-1); // expected-error-re {{argument value {{.*}} is outside the valid 
range}}
+  __hvc(65536); // expected-error-re {{argument value {{.*}} is outside the 
valid range}}
+  __hvc(x); // expected-error {{argument to '__hvc' must be a constant 
integer}}
+}
+
+void check__svc(unsigned int x) {
+  __svc(-1); // expected-error-re {{argument value {{.*}} is outside the valid 
range}}
+  __svc(65536); // expected-error-re {{argument value {{.*}} is outside the 
valid range}}
+  __svc(x); // expected-error {{argument to '__svc' must be a constant 
integer}}
+}
+
 void check__getReg(void) {
   __getReg(-1); // expected-error-re {{argument value {{.*}} is outside the 
valid range}}
   __getReg(32); // expected-error-re {{argument value {{.*}} is outside the 
valid range}}
diff --git a/llvm/include/llvm/IR/IntrinsicsAArch64.td 
b/llvm/include/llvm/IR/IntrinsicsAArch64.td
index ba0d7c02bf427..ecccf6eddfc64 100644
--- a/llvm/include/llvm/IR/IntrinsicsAArch64.td
+++ b/llvm/include/llvm/IR/IntrinsicsAArch64.td
@@ -72,6 +72,12 @@ def int_aarch64_break : Intrinsic<[], [llvm_i32_ty],
 def int_aarch64_hlt : Intrinsic<[], [llvm_i32_ty],
     [IntrNoMem, IntrHasSideEffects, IntrNoReturn, IntrCold, 
ImmArg<ArgIndex<0>>]>;
 
+def int_aarch64_hvc : Intrinsic<[], [llvm_i32_ty],
+    [IntrNoMem, IntrHasSideEffects, ImmArg<ArgIndex<0>>]>;
+
+def int_aarch64_svc : Intrinsic<[], [llvm_i32_ty],
+    [IntrNoMem, IntrHasSideEffects, ImmArg<ArgIndex<0>>]>;
+
 def int_aarch64_prefetch : Intrinsic<[],
     [llvm_ptr_ty, llvm_i32_ty, llvm_i32_ty, llvm_i32_ty, llvm_i32_ty],
     [IntrInaccessibleMemOrArgMemOnly, IntrWillReturn, ReadOnly<ArgIndex<0>>,
diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td 
b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
index 200808665c93e..aa33c34ce7ab2 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
@@ -3759,9 +3759,11 @@ def DCPS2 : ExceptionGeneration<0b101, 0b10, "dcps2">;
 def DCPS3 : ExceptionGeneration<0b101, 0b11, "dcps3">, Requires<[HasEL3]>;
 def HLT   : ExceptionGeneration<0b010, 0b00, "hlt",
                                 [(int_aarch64_hlt timm32_0_65535:$imm)]>;
-def HVC   : ExceptionGeneration<0b000, 0b10, "hvc">;
+def HVC   : ExceptionGeneration<0b000, 0b10, "hvc",
+                                [(int_aarch64_hvc timm32_0_65535:$imm)]>;
 def SMC   : ExceptionGeneration<0b000, 0b11, "smc">, Requires<[HasEL3]>;
-def SVC   : ExceptionGeneration<0b000, 0b01, "svc">;
+def SVC   : ExceptionGeneration<0b000, 0b01, "svc",
+                                [(int_aarch64_svc timm32_0_65535:$imm)]>;
 
 // DCPSn defaults to an immediate operand of zero if unspecified.
 def : InstAlias<"dcps1", (DCPS1 0)>;
diff --git a/llvm/test/CodeGen/AArch64/arm64-hvc.ll 
b/llvm/test/CodeGen/AArch64/arm64-hvc.ll
new file mode 100644
index 0000000000000..14d7e22b4263f
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/arm64-hvc.ll
@@ -0,0 +1,10 @@
+; RUN: llc < %s -mtriple=arm64-eabi | FileCheck %s
+
+define void @foo() nounwind {
+; CHECK-LABEL: foo
+; CHECK: hvc #0x2
+  tail call void @llvm.aarch64.hvc(i32 2)
+  ret void
+}
+
+declare void @llvm.aarch64.hvc(i32 immarg) nounwind
diff --git a/llvm/test/CodeGen/AArch64/arm64-svc.ll 
b/llvm/test/CodeGen/AArch64/arm64-svc.ll
new file mode 100644
index 0000000000000..2bb0719413429
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/arm64-svc.ll
@@ -0,0 +1,10 @@
+; RUN: llc < %s -mtriple=arm64-eabi | FileCheck %s
+
+define void @foo() nounwind {
+; CHECK-LABEL: foo
+; CHECK: svc #0x2
+  tail call void @llvm.aarch64.svc(i32 2)
+  ret void
+}
+
+declare void @llvm.aarch64.svc(i32 immarg) nounwind

``````````

</details>


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

Reply via email to