Skip to content

Conversation

kamaub
Copy link
Contributor

@kamaub kamaub commented Oct 15, 2025

Increase GCC extended ASM Support 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

Constraint Q was not defined as a C_Memory constraint type in the
PowerPC backend. This is a step towards supporting atomic memory
operations using inline assembly.
A reduced test case revealed that input operand constraint modifiers,
commonly known in llvm as Extra Codes, can be "weakly" diagnosed as
"invalid operand in inline asm". This change adds further diagnostics to
state "Unknown modifier in inline asm" when the extra code switch statement
defaults.
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.
@kamaub kamaub self-assigned this Oct 15, 2025
@kamaub kamaub added bug Indicates an unexpected problem or unintended behavior backend:PowerPC inline-asm labels Oct 15, 2025
@llvmbot llvmbot added the clang Clang issues not falling into any other category label Oct 15, 2025
@llvmbot
Copy link
Member

llvmbot commented Oct 15, 2025

@llvm/pr-subscribers-clang

@llvm/pr-subscribers-backend-powerpc

Author: Kamau Bridgeman (kamaub)

Changes

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&lt;In&gt;, %P&lt;Op1&gt;, R&lt;Op2&gt; == 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 &lt;Offset&gt;([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 --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
+}

Copy link

github-actions bot commented Oct 15, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

@kamaub kamaub changed the title PowerPC: Support Atomic Memory Operations in Inline Asm PowerPC: Support Q constraint and P modifier in Inline Asm Oct 20, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backend:PowerPC bug Indicates an unexpected problem or unintended behavior clang Clang issues not falling into any other category inline-asm

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants