[llvm] [clang] [X86] Add "Ws" constraint and "p" modifier for symbolic address/label reference (PR #77886)

via llvm-commits llvm-commits at lists.llvm.org
Thu Jan 11 23:43:13 PST 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Fangrui Song (MaskRay)

<details>
<summary>Changes</summary>

Printing the raw symbol is useful in inline asm (e.g. getting the C++
mangled name, referencing a symbol in a custom way while ensuring it is
not optimized out even if internal). Similar constraints are available
in other targets (e.g. "S" for aarch64/riscv, "Cs" for m68k).

```
namespace ns { extern int var; }
asm (".pushsection .xxx,\"aw\"; .dc.a %p0; .popsection" :: "Ws"(&var));
asm (".reloc ., BFD_RELOC_NONE, %p0" :: "Ws"(&var));
```

DO NOT SUBMIT wait for Ws patch https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105576


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


8 Files Affected:

- (modified) clang/lib/Basic/Targets/X86.cpp (+11) 
- (modified) clang/test/CodeGen/X86/inline-asm-constraints.c (+8) 
- (modified) clang/test/Sema/inline-asm-validate-x86.c (+4) 
- (modified) llvm/docs/LangRef.rst (+2) 
- (modified) llvm/lib/Target/X86/X86AsmPrinter.cpp (+8) 
- (modified) llvm/lib/Target/X86/X86ISelLowering.cpp (+15-5) 
- (added) llvm/test/CodeGen/X86/inline-asm-Ws-constraint-error.ll (+9) 
- (added) llvm/test/CodeGen/X86/inline-asm-Ws-constraint.ll (+34) 


``````````diff
diff --git a/clang/lib/Basic/Targets/X86.cpp b/clang/lib/Basic/Targets/X86.cpp
index 64e281b888a95f..a68b662d9401aa 100644
--- a/clang/lib/Basic/Targets/X86.cpp
+++ b/clang/lib/Basic/Targets/X86.cpp
@@ -1418,6 +1418,14 @@ bool X86TargetInfo::validateAsmConstraint(
   case 'O':
     Info.setRequiresImmediate(0, 127);
     return true;
+  case 'W':
+    switch (*++Name) {
+    default:
+      return false;
+    case 's':
+      Info.setAllowsRegister();
+      return true;
+    }
   // Register constraints.
   case 'Y': // 'Y' is the first character for several 2-character constraints.
     // Shift the pointer to the second character of the constraint.
@@ -1715,6 +1723,9 @@ std::string X86TargetInfo::convertConstraint(const char *&Constraint) const {
     return std::string("{st}");
   case 'u':                        // second from top of floating point stack.
     return std::string("{st(1)}"); // second from top of floating point stack.
+  case 'W':
+    assert(Constraint[1] == 's');
+    return '^' + std::string(Constraint++, 2);
   case 'Y':
     switch (Constraint[1]) {
     default:
diff --git a/clang/test/CodeGen/X86/inline-asm-constraints.c b/clang/test/CodeGen/X86/inline-asm-constraints.c
index b75a84d7a7bcbf..bfcbbca7c4f6bf 100644
--- a/clang/test/CodeGen/X86/inline-asm-constraints.c
+++ b/clang/test/CodeGen/X86/inline-asm-constraints.c
@@ -53,3 +53,11 @@ __m512 testZMM0(void) {
 #endif
   return zmm0;
 }
+
+extern int var;
+
+// CHECK-LABEL: test_Ws(
+// CHECK:         call void asm sideeffect "// ${0:p} ${1:p}", "^Ws,^Ws,~{dirflag},~{fpsr},~{flags}"(ptr @var, ptr @test_Ws)
+void test_Ws(void) {
+  asm("// %p0 %p1" :: "Ws"(&var), "Ws"(test_Ws));
+}
diff --git a/clang/test/Sema/inline-asm-validate-x86.c b/clang/test/Sema/inline-asm-validate-x86.c
index 87b60a0955301a..032d76477c4ae6 100644
--- a/clang/test/Sema/inline-asm-validate-x86.c
+++ b/clang/test/Sema/inline-asm-validate-x86.c
@@ -130,3 +130,7 @@ void pr40890(void) {
   __asm__ __volatile__("\n#define BEEF abcd%0\n" : : "n"((int*)0xdeadbeeeeeef));
 #endif
 }
+
+void test_W() {
+  asm("" : : "Wd"(test_W)); // expected-error{{invalid input constraint 'Wd' in asm}}
+}
diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index d881deb30049a2..076029976ffc5d 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -5336,6 +5336,7 @@ X86:
   operand in a SSE register. If AVX is also enabled, can also be a 256-bit
   vector operand in an AVX register. If AVX-512 is also enabled, can also be a
   512-bit vector operand in an AVX512 register. Otherwise, an error.
+- ``Ws``: A symbolic reference or label reference.
 - ``x``: The same as ``v``, except that when AVX-512 is enabled, the ``x`` code
   only allocates into the first 16 AVX-512 registers, while the ``v`` code
   allocates into any of the 32 AVX-512 registers.
@@ -5518,6 +5519,7 @@ X86:
   the operand. (The behavior for relocatable symbol expressions is a
   target-specific behavior for this typically target-independent modifier)
 - ``H``: Print a memory reference with additional offset +8.
+- ``p``: Print a raw symbol name (without syntax-specific prefixes).
 - ``P``: Print a memory reference used as the argument of a call instruction or
   used with explicit base reg and index reg as its offset. So it can not use
   additional regs to present the memory reference. (E.g. omit ``(rip)``, even
diff --git a/llvm/lib/Target/X86/X86AsmPrinter.cpp b/llvm/lib/Target/X86/X86AsmPrinter.cpp
index 15cfd247f125ca..9f0fd4d0938e97 100644
--- a/llvm/lib/Target/X86/X86AsmPrinter.cpp
+++ b/llvm/lib/Target/X86/X86AsmPrinter.cpp
@@ -774,6 +774,14 @@ bool X86AsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
       PrintOperand(MI, OpNo, O);
       return false;
 
+    case 'p': {
+      const MachineOperand &MO = MI->getOperand(OpNo);
+      if (MO.getType() != MachineOperand::MO_GlobalAddress)
+        return true;
+      PrintSymbolOperand(MO, O);
+      return false;
+    }
+
     case 'P': // This is the operand of a call, treat specially.
       PrintPCRelImm(MI, OpNo, O);
       return false;
diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp
index 700ab797b2f69f..aea8e8b40ff631 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.cpp
+++ b/llvm/lib/Target/X86/X86ISelLowering.cpp
@@ -56676,6 +56676,10 @@ X86TargetLowering::getConstraintType(StringRef Constraint) const {
     switch (Constraint[0]) {
     default:
       break;
+    case 'W':
+      if (Constraint[1] != 's')
+        break;
+      return C_Other;
     case 'Y':
       switch (Constraint[1]) {
       default:
@@ -56880,11 +56884,6 @@ void X86TargetLowering::LowerAsmOperandForConstraint(SDValue Op,
                                                      std::vector<SDValue> &Ops,
                                                      SelectionDAG &DAG) const {
   SDValue Result;
-
-  // Only support length 1 constraints for now.
-  if (Constraint.size() > 1)
-    return;
-
   char ConstraintLetter = Constraint[0];
   switch (ConstraintLetter) {
   default: break;
@@ -56966,6 +56965,17 @@ void X86TargetLowering::LowerAsmOperandForConstraint(SDValue Op,
     }
     return;
   }
+  case 'W': {
+    assert(Constraint[1] == 's');
+    if (const auto *GA = dyn_cast<GlobalAddressSDNode>(Op)) {
+      Ops.push_back(DAG.getTargetGlobalAddress(GA->getGlobal(), SDLoc(Op),
+                                               GA->getValueType(0)));
+    } else if (const auto *BA = dyn_cast<BlockAddressSDNode>(Op)) {
+      Ops.push_back(DAG.getTargetBlockAddress(BA->getBlockAddress(),
+                                              BA->getValueType(0)));
+    }
+    return;
+  }
   case 'Z': {
     // 32-bit unsigned value
     if (auto *C = dyn_cast<ConstantSDNode>(Op)) {
diff --git a/llvm/test/CodeGen/X86/inline-asm-Ws-constraint-error.ll b/llvm/test/CodeGen/X86/inline-asm-Ws-constraint-error.ll
new file mode 100644
index 00000000000000..38d0f08dfbd865
--- /dev/null
+++ b/llvm/test/CodeGen/X86/inline-asm-Ws-constraint-error.ll
@@ -0,0 +1,9 @@
+; RUN: not llc -mtriple=x86_64 < %s 2>&1 | FileCheck %s
+
+; CHECK: error: invalid operand for inline asm constraint 'Ws'
+define void @test() {
+entry:
+  %x = alloca i32, align 4
+  call void asm sideeffect "// ${0:p}", "^Ws,~{dirflag},~{fpsr},~{flags}"(ptr %x)
+  ret void
+}
diff --git a/llvm/test/CodeGen/X86/inline-asm-Ws-constraint.ll b/llvm/test/CodeGen/X86/inline-asm-Ws-constraint.ll
new file mode 100644
index 00000000000000..72fc13795f08ce
--- /dev/null
+++ b/llvm/test/CodeGen/X86/inline-asm-Ws-constraint.ll
@@ -0,0 +1,34 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=i686 < %s | FileCheck %s
+; RUN: llc -mtriple=x86_64 < %s | FileCheck %s
+
+ at var = external dso_local global i32, align 4
+
+define dso_local void @test() {
+; CHECK-LABEL: test:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    # var test
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    ret{{[l|q]}}
+entry:
+  call void asm sideeffect "// ${0:p} ${1:p}", "^Ws,^Ws,~{dirflag},~{fpsr},~{flags}"(ptr @var, ptr @test)
+  ret void
+}
+
+define dso_local void @test_label() {
+; CHECK-LABEL: test_label:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:  .Ltmp0: # Block address taken
+; CHECK-NEXT:  # %bb.1: # %label
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    # .Ltmp0
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    ret{{[l|q]}}
+entry:
+  br label %label
+
+label:
+  tail call void asm sideeffect "// ${0:p}", "Ws,~{dirflag},~{fpsr},~{flags}"(ptr blockaddress(@test_label, %label))
+  ret void
+}

``````````

</details>


https://github.com/llvm/llvm-project/pull/77886


More information about the llvm-commits mailing list