[clang] [llvm] PowerPC: Support Atomic Memory Operations in Inline Asm (PR #163616)

via cfe-commits cfe-commits at lists.llvm.org
Wed Oct 15 12:06:49 PDT 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-powerpc

Author: Kamau Bridgeman (kamaub)

<details>
<summary>Changes</summary>

Support atomic memory operations by enabling `P` argument modified `Q`
constrained inputs to inline assembly memory operations.
Constraint Q was not defined as a C_Memory constraint type in the
PowerPC backend.
The `P` constraint argument modifier is an GCC extended inline asm feature that
has been observed to translate to an X-Form [Reg] register allocation and
address mode encoding. i.e `ldx R<In>, %P<Op1>, R<Op2> == ldx r3, r1, r2`.
This allows users to modify the default addressing mode, D-Form,
to X-Form for `Q`, `m`, and `Z`, inline asm constraint types.
These constraints produce `<Offset>([reg])` otherwise.
References: 

1. https://gcc.gnu.org/onlinedocs/gcc/Machine-Constraints.html
2. https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#Generic-Operand-Modifiers
3. https://llvm.org/docs/LangRef.html#asm-template-argument-modifiers


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


4 Files Affected:

- (added) clang/test/CodeGen/PowerPC/inline-asm-constraints.c (+29) 
- (modified) llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp (+18-2) 
- (modified) llvm/lib/Target/PowerPC/PPCISelLowering.cpp (+1) 
- (added) llvm/test/CodeGen/PowerPC/inline-asm-constraints.ll (+21) 


``````````diff
diff --git a/clang/test/CodeGen/PowerPC/inline-asm-constraints.c b/clang/test/CodeGen/PowerPC/inline-asm-constraints.c
new file mode 100644
index 0000000000000..1464500359046
--- /dev/null
+++ b/clang/test/CodeGen/PowerPC/inline-asm-constraints.c
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -emit-llvm -triple powerpc64-ibm-aix-xcoff \
+// RUN:   %s -o - | FileCheck %s
+
+#include <stdint.h>
+
+// Test Atomic Memory Operation Support:
+// This test case takes an address and performs an atomic load at that address.
+// The purpose is to test the Q machine constraint and P machine constraint
+// argument modifier together.
+// These constraints on the pointer `ptr` read as: constrain (uint32_t*)ptr to
+// read and writeable X-Form Addressed Memory operands.
+static __attribute__((noinline))
+uint32_t atomic_load(uint32_t *ptr, uint32_t val)
+{
+// CHECK-LABEL: define{{.*}} i32 @atomic_load(ptr noundef %ptr, i32 noundef zeroext %val)
+// CHECK:  %3 = call { i128, i32 } asm sideeffect "mr ${1:L},$3\0A\09 lwat $1,${0:P},$4\0A\09 mr $2,$1\0A", "=*Q,=&r,=r,r,n,0"(ptr elementtype(i32) %arrayidx, i32 %2, i32 0, i32 %1)
+  unsigned __int128 tmp;
+  uint32_t ret;
+  __asm__ volatile ("mr %L1,%3\n"
+                    "\t lwat %1,%P0,%4\n"
+                    "\t mr %2,%1\n"
+                    : "+Q" (ptr[0]), "=&r" (tmp), "=r" (ret)
+                    : "r" (val), "n" (0x00));
+  return ret;
+}
+
+int main(int argc, char **argv) {
+   return atomic_load((uint32_t*)argv[1], (uint32_t)*(argv[2]));
+}
\ No newline at end of file
diff --git a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
index bcb3f507e98d6..2e31ea7392aeb 100644
--- a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
+++ b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
@@ -411,11 +411,24 @@ bool PPCAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
 bool PPCAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
                                           const char *ExtraCode,
                                           raw_ostream &O) {
+  auto reportAsmMemError = [&] (StringRef errMsg) {
+    const char *AsmStr = MI->getOperand(0).getSymbolName();
+    const MDNode *LocMD = MI->getLocCookieMD();
+    uint64_t LocCookie = LocMD ?
+     mdconst::extract<ConstantInt>(LocMD->getOperand(0))->getZExtValue() : 0;
+    const Function &Fn = MI->getMF()->getFunction();
+    Fn.getContext().diagnose(DiagnosticInfoInlineAsm(
+        LocCookie, errMsg + Twine(AsmStr) + "'"));
+    return true;
+  };
   if (ExtraCode && ExtraCode[0]) {
-    if (ExtraCode[1] != 0) return true; // Unknown modifier.
+    if (ExtraCode[1] != 0)
+      return reportAsmMemError("Unknown modifier in inline asm:");
 
     switch (ExtraCode[0]) {
-    default: return true;  // Unknown modifier.
+    default: {
+      return reportAsmMemError("Unknown modifier in inline asm:");
+    }
     case 'L': // A memory reference to the upper word of a double word op.
       O << getDataLayout().getPointerSize() << "(";
       printOperand(MI, OpNo, O);
@@ -425,6 +438,9 @@ bool PPCAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
       O << "0, ";
       printOperand(MI, OpNo, O);
       return false;
+    case 'P': // A memory reference for an single inout to an X-form instr.
+      printOperand(MI, OpNo, O);
+      return false;
     case 'I':
       // Write 'i' if an integer constant, otherwise nothing.  Used to print
       // addi vs add, etc.
diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
index 8bf0d118da575..de26677c161d1 100644
--- a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
+++ b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
@@ -17882,6 +17882,7 @@ PPCTargetLowering::getConstraintType(StringRef Constraint) const {
     case 'y':
       return C_RegisterClass;
     case 'Z':
+    case 'Q':
       // FIXME: While Z does indicate a memory constraint, it specifically
       // indicates an r+r address (used in conjunction with the 'y' modifier
       // in the replacement string). Currently, we're forcing the base
diff --git a/llvm/test/CodeGen/PowerPC/inline-asm-constraints.ll b/llvm/test/CodeGen/PowerPC/inline-asm-constraints.ll
new file mode 100644
index 0000000000000..72d370ce8567f
--- /dev/null
+++ b/llvm/test/CodeGen/PowerPC/inline-asm-constraints.ll
@@ -0,0 +1,21 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc -verify-machineinstrs < %s -mcpu=pwr8 \
+; RUN:  -mtriple=powerpc64-ibm-aix-xcoff | FileCheck %s
+
+define zeroext i32 @atomic_load(ptr %ptr, i32 zeroext range(i32 0, 256) %val) {
+; CHECK-LABEL: atomic_load:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    mr 6, 4
+; CHECK-NEXT:    lwat 5, 3, 0
+; CHECK-NEXT:    mr 3, 5
+; CHECK-EMPTY:
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    clrldi 3, 3, 32
+; CHECK-NEXT:    blr
+entry:
+  %0 = load i32, ptr %ptr, align 4
+  %1 = tail call { i128, i32 } asm sideeffect "mr ${1:L},$3\0A\09 lwat $1,${0:P},$4\0A\09 mr $2,$1\0A", "=*Q,=&r,=r,r,n,0"(ptr nonnull elementtype(i32) %ptr, i32 %val, i32 0, i32 %0)
+  %asmresult1 = extractvalue { i128, i32 } %1, 1
+  ret i32 %asmresult1
+}

``````````

</details>


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


More information about the cfe-commits mailing list