[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