[clang] [llvm] PowerPC: Support Atomic Memory Operations in Inline Asm (PR #163616)
Kamau Bridgeman via cfe-commits
cfe-commits at lists.llvm.org
Wed Oct 15 12:06:25 PDT 2025
https://github.com/kamaub created https://github.com/llvm/llvm-project/pull/163616
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
>From ab459844273fad0c17f42bfbcba20b7a9091b30c Mon Sep 17 00:00:00 2001
From: Kamau Bridgeman <kamau.a.bridgeman at gmail.com>
Date: Wed, 15 Oct 2025 14:47:44 -0400
Subject: [PATCH 1/6] Initial Commit: Define Qs constraint type
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.
---
clang/lib/Sema/SemaStmtAsm.cpp | 4 +++-
llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp | 4 ++++
llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp | 11 ++++++++++-
llvm/lib/Target/PowerPC/PPCISelLowering.cpp | 2 ++
4 files changed, 19 insertions(+), 2 deletions(-)
diff --git a/clang/lib/Sema/SemaStmtAsm.cpp b/clang/lib/Sema/SemaStmtAsm.cpp
index 0438af752a69e..11580cba7a3ed 100644
--- a/clang/lib/Sema/SemaStmtAsm.cpp
+++ b/clang/lib/Sema/SemaStmtAsm.cpp
@@ -306,7 +306,9 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
std::string ConstraintStr =
GCCAsmStmt::ExtractStringFromGCCAsmStmtComponent(Constraint);
- TargetInfo::ConstraintInfo Info(ConstraintStr, OutputName);
+ fprintf(stderr, "Expr: ");
+ Exprs[i]->dump();
+ TargetInfo::ConstraintInfo Info(ConstraintStr, OutputName);
if (!Context.getTargetInfo().validateOutputConstraint(Info) &&
!(LangOpts.HIPStdPar && LangOpts.CUDAIsDevice)) {
targetDiag(Constraint->getBeginLoc(),
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index 0f2b5188fc10a..0333c2621b854 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -10296,6 +10296,8 @@ void SelectionDAGBuilder::visitInlineAsm(const CallBase &Call,
break;
}
+ fprintf(stderr,"ConstraintType: %i\n",OpInfo.ConstraintType);
+ fprintf(stderr,"ConstraintCode: %s\n",OpInfo.ConstraintCode.c_str());
// Treat indirect 'X' constraint as memory.
if (OpInfo.ConstraintType == TargetLowering::C_Other &&
OpInfo.isIndirect)
@@ -10378,6 +10380,8 @@ void SelectionDAGBuilder::visitInlineAsm(const CallBase &Call,
break;
}
+ fprintf(stderr,"ConstraintType: %i\n",OpInfo.ConstraintType);
+ fprintf(stderr,"ConstraintCode: %s\n",OpInfo.ConstraintCode.c_str());
if (OpInfo.ConstraintType != TargetLowering::C_RegisterClass &&
OpInfo.ConstraintType != TargetLowering::C_Register) {
emitInlineAsmError(Call, "unknown asm constraint '" +
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
index 6c11c5b815b6b..84aa1d161a3f4 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
@@ -2300,6 +2300,10 @@ void SelectionDAGISel::SelectInlineAsmMemoryOperands(std::vector<SDValue> &Ops,
while (i != e) {
InlineAsm::Flag Flags(Ops[i]->getAsZExtVal());
+ fprintf(stderr,"inlineasm nodes during select:");
+ Ops[i].dump();
+ fprintf(stderr,"Op %x flag kind:%s\n", i, Flags.getKindName().str().c_str());
+ Ops[i + 1].dump();
if (!Flags.isMemKind() && !Flags.isFuncKind()) {
// Just skip over this operand, copying the operands verbatim.
Handles.insert(Handles.end(), Ops.begin() + i,
@@ -2324,6 +2328,8 @@ void SelectionDAGISel::SelectInlineAsmMemoryOperands(std::vector<SDValue> &Ops,
std::vector<SDValue> SelOps;
const InlineAsm::ConstraintCode ConstraintID =
Flags.getMemoryConstraintID();
+ fprintf(stderr,"inlineasm node during target select:");
+ Ops[i + 1].dump();
if (SelectInlineAsmMemoryOperand(Ops[i + 1], ConstraintID, SelOps))
report_fatal_error("Could not match memory address. Inline asm"
" failure!");
@@ -2469,7 +2475,8 @@ bool SelectionDAGISel::IsLegalToFold(SDValue N, SDNode *U, SDNode *Root,
void SelectionDAGISel::Select_INLINEASM(SDNode *N) {
SDLoc DL(N);
-
+ fprintf(stderr,"inlineasm node before select:");
+ N->dump();
std::vector<SDValue> Ops(N->op_begin(), N->op_end());
SelectInlineAsmMemoryOperands(Ops, DL);
@@ -2478,6 +2485,8 @@ void SelectionDAGISel::Select_INLINEASM(SDNode *N) {
New->setNodeId(-1);
ReplaceUses(N, New.getNode());
CurDAG->RemoveDeadNode(N);
+ fprintf(stderr,"inlineasm node after select:");
+ New->dump();
}
void SelectionDAGISel::Select_READ_REGISTER(SDNode *Op) {
diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
index 8bf0d118da575..c95db8aaea17d 100644
--- a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
+++ b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
@@ -3928,6 +3928,7 @@ SDValue PPCTargetLowering::LowerADJUST_TRAMPOLINE(SDValue Op,
}
SDValue PPCTargetLowering::LowerINLINEASM(SDValue Op, SelectionDAG &DAG) const {
+ LLVM_DEBUG(dbgs() << "Lowering inline asm: "; Op.dump(&DAG));
MachineFunction &MF = DAG.getMachineFunction();
PPCFunctionInfo &MFI = *MF.getInfo<PPCFunctionInfo>();
@@ -17882,6 +17883,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
>From 37c382aed40a063e8977602d4735ac89e5b72405 Mon Sep 17 00:00:00 2001
From: Kamau Bridgeman <kamau.a.bridgeman at gmail.com>
Date: Wed, 15 Oct 2025 14:49:24 -0400
Subject: [PATCH 2/6] Adding a Diagnostics for unknown extra codes to the PPC
ASM Printer
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.
---
llvm/lib/IR/Verifier.cpp | 4 ++++
llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp | 21 ++++++++++++++++++++-
2 files changed, 24 insertions(+), 1 deletion(-)
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index c79a95087dbdd..d9582943f165d 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -2689,6 +2689,8 @@ void Verifier::verifyInlineAsmCall(const CallBase &Call) {
const InlineAsm *IA = cast<InlineAsm>(Call.getCalledOperand());
unsigned ArgNo = 0;
unsigned LabelNo = 0;
+ fprintf(stderr,"Call:\n");
+ Call.dump();
for (const InlineAsm::ConstraintInfo &CI : IA->ParseConstraints()) {
if (CI.Type == InlineAsm::isLabel) {
++LabelNo;
@@ -2701,6 +2703,8 @@ void Verifier::verifyInlineAsmCall(const CallBase &Call) {
if (CI.isIndirect) {
const Value *Arg = Call.getArgOperand(ArgNo);
+ fprintf(stderr,"Arg:\n");
+ Arg->dump();
Check(Arg->getType()->isPointerTy(),
"Operand for indirect constraint must have pointer type", &Call);
diff --git a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
index bcb3f507e98d6..b76c45ed3769a 100644
--- a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
+++ b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
@@ -411,11 +411,30 @@ bool PPCAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
bool PPCAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
const char *ExtraCode,
raw_ostream &O) {
+ fprintf(stderr, "Printing Inline ASM:\n");
+ MI->dump();
+ fprintf(stderr, "Operand #%i to be printed:\n", OpNo);
+ MI->getOperand(OpNo).dump();
+ for(int i = 0; i < MI->getNumOperands(); i++) {
+ if (i == OpNo) continue;
+ fprintf(stderr, "Other Operand #%i:\n", i);
+ MI->getOperand(i).dump();
+ }
if (ExtraCode && ExtraCode[0]) {
+ fprintf(stderr, "ExtraCode[0] is %c\n", ExtraCode[0]);
if (ExtraCode[1] != 0) return true; // Unknown modifier.
switch (ExtraCode[0]) {
- default: return true; // Unknown modifier.
+ default: {
+ 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,
+ "Unknown modifier in inline asm: '" + Twine(AsmStr) + "'"));
+ return true; // Unknown modifier.
+ }
case 'L': // A memory reference to the upper word of a double word op.
O << getDataLayout().getPointerSize() << "(";
printOperand(MI, OpNo, O);
>From d05348b094d9f3d964a8cfcc982d495cdc14a105 Mon Sep 17 00:00:00 2001
From: Kamau Bridgeman <kamau.a.bridgeman at gmail.com>
Date: Wed, 15 Oct 2025 14:52:22 -0400
Subject: [PATCH 3/6] Support the `P` constraint argument modifier in the PPC
ASM printer
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.
---
llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp | 25 +++++++++++++++--------
1 file changed, 16 insertions(+), 9 deletions(-)
diff --git a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
index b76c45ed3769a..9e47344edfe7f 100644
--- a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
+++ b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
@@ -420,20 +420,24 @@ bool PPCAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
fprintf(stderr, "Other Operand #%i:\n", i);
MI->getOperand(i).dump();
}
+ 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]) {
fprintf(stderr, "ExtraCode[0] is %c\n", 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: {
- 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,
- "Unknown modifier in inline asm: '" + Twine(AsmStr) + "'"));
- return true; // Unknown modifier.
+ return reportAsmMemError("Unknown modifier in inline asm:");
}
case 'L': // A memory reference to the upper word of a double word op.
O << getDataLayout().getPointerSize() << "(";
@@ -444,6 +448,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.
>From d6e99ad80d99eb26bea0c9302a24cd367a88dbb2 Mon Sep 17 00:00:00 2001
From: Kamau Bridgeman <kamau.a.bridgeman at gmail.com>
Date: Wed, 15 Oct 2025 14:54:15 -0400
Subject: [PATCH 4/6] Removing debug print statements
---
clang/lib/Sema/SemaStmtAsm.cpp | 4 +---
llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp | 4 ----
llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp | 10 ----------
llvm/lib/IR/Verifier.cpp | 4 ----
llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp | 10 ----------
llvm/lib/Target/PowerPC/PPCISelLowering.cpp | 1 -
6 files changed, 1 insertion(+), 32 deletions(-)
diff --git a/clang/lib/Sema/SemaStmtAsm.cpp b/clang/lib/Sema/SemaStmtAsm.cpp
index 11580cba7a3ed..0438af752a69e 100644
--- a/clang/lib/Sema/SemaStmtAsm.cpp
+++ b/clang/lib/Sema/SemaStmtAsm.cpp
@@ -306,9 +306,7 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
std::string ConstraintStr =
GCCAsmStmt::ExtractStringFromGCCAsmStmtComponent(Constraint);
- fprintf(stderr, "Expr: ");
- Exprs[i]->dump();
- TargetInfo::ConstraintInfo Info(ConstraintStr, OutputName);
+ TargetInfo::ConstraintInfo Info(ConstraintStr, OutputName);
if (!Context.getTargetInfo().validateOutputConstraint(Info) &&
!(LangOpts.HIPStdPar && LangOpts.CUDAIsDevice)) {
targetDiag(Constraint->getBeginLoc(),
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index 0333c2621b854..0f2b5188fc10a 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -10296,8 +10296,6 @@ void SelectionDAGBuilder::visitInlineAsm(const CallBase &Call,
break;
}
- fprintf(stderr,"ConstraintType: %i\n",OpInfo.ConstraintType);
- fprintf(stderr,"ConstraintCode: %s\n",OpInfo.ConstraintCode.c_str());
// Treat indirect 'X' constraint as memory.
if (OpInfo.ConstraintType == TargetLowering::C_Other &&
OpInfo.isIndirect)
@@ -10380,8 +10378,6 @@ void SelectionDAGBuilder::visitInlineAsm(const CallBase &Call,
break;
}
- fprintf(stderr,"ConstraintType: %i\n",OpInfo.ConstraintType);
- fprintf(stderr,"ConstraintCode: %s\n",OpInfo.ConstraintCode.c_str());
if (OpInfo.ConstraintType != TargetLowering::C_RegisterClass &&
OpInfo.ConstraintType != TargetLowering::C_Register) {
emitInlineAsmError(Call, "unknown asm constraint '" +
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
index 84aa1d161a3f4..8fc6e47c3fddf 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
@@ -2300,10 +2300,6 @@ void SelectionDAGISel::SelectInlineAsmMemoryOperands(std::vector<SDValue> &Ops,
while (i != e) {
InlineAsm::Flag Flags(Ops[i]->getAsZExtVal());
- fprintf(stderr,"inlineasm nodes during select:");
- Ops[i].dump();
- fprintf(stderr,"Op %x flag kind:%s\n", i, Flags.getKindName().str().c_str());
- Ops[i + 1].dump();
if (!Flags.isMemKind() && !Flags.isFuncKind()) {
// Just skip over this operand, copying the operands verbatim.
Handles.insert(Handles.end(), Ops.begin() + i,
@@ -2328,8 +2324,6 @@ void SelectionDAGISel::SelectInlineAsmMemoryOperands(std::vector<SDValue> &Ops,
std::vector<SDValue> SelOps;
const InlineAsm::ConstraintCode ConstraintID =
Flags.getMemoryConstraintID();
- fprintf(stderr,"inlineasm node during target select:");
- Ops[i + 1].dump();
if (SelectInlineAsmMemoryOperand(Ops[i + 1], ConstraintID, SelOps))
report_fatal_error("Could not match memory address. Inline asm"
" failure!");
@@ -2475,8 +2469,6 @@ bool SelectionDAGISel::IsLegalToFold(SDValue N, SDNode *U, SDNode *Root,
void SelectionDAGISel::Select_INLINEASM(SDNode *N) {
SDLoc DL(N);
- fprintf(stderr,"inlineasm node before select:");
- N->dump();
std::vector<SDValue> Ops(N->op_begin(), N->op_end());
SelectInlineAsmMemoryOperands(Ops, DL);
@@ -2485,8 +2477,6 @@ void SelectionDAGISel::Select_INLINEASM(SDNode *N) {
New->setNodeId(-1);
ReplaceUses(N, New.getNode());
CurDAG->RemoveDeadNode(N);
- fprintf(stderr,"inlineasm node after select:");
- New->dump();
}
void SelectionDAGISel::Select_READ_REGISTER(SDNode *Op) {
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index d9582943f165d..c79a95087dbdd 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -2689,8 +2689,6 @@ void Verifier::verifyInlineAsmCall(const CallBase &Call) {
const InlineAsm *IA = cast<InlineAsm>(Call.getCalledOperand());
unsigned ArgNo = 0;
unsigned LabelNo = 0;
- fprintf(stderr,"Call:\n");
- Call.dump();
for (const InlineAsm::ConstraintInfo &CI : IA->ParseConstraints()) {
if (CI.Type == InlineAsm::isLabel) {
++LabelNo;
@@ -2703,8 +2701,6 @@ void Verifier::verifyInlineAsmCall(const CallBase &Call) {
if (CI.isIndirect) {
const Value *Arg = Call.getArgOperand(ArgNo);
- fprintf(stderr,"Arg:\n");
- Arg->dump();
Check(Arg->getType()->isPointerTy(),
"Operand for indirect constraint must have pointer type", &Call);
diff --git a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
index 9e47344edfe7f..2e31ea7392aeb 100644
--- a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
+++ b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
@@ -411,15 +411,6 @@ bool PPCAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
bool PPCAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
const char *ExtraCode,
raw_ostream &O) {
- fprintf(stderr, "Printing Inline ASM:\n");
- MI->dump();
- fprintf(stderr, "Operand #%i to be printed:\n", OpNo);
- MI->getOperand(OpNo).dump();
- for(int i = 0; i < MI->getNumOperands(); i++) {
- if (i == OpNo) continue;
- fprintf(stderr, "Other Operand #%i:\n", i);
- MI->getOperand(i).dump();
- }
auto reportAsmMemError = [&] (StringRef errMsg) {
const char *AsmStr = MI->getOperand(0).getSymbolName();
const MDNode *LocMD = MI->getLocCookieMD();
@@ -431,7 +422,6 @@ bool PPCAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
return true;
};
if (ExtraCode && ExtraCode[0]) {
- fprintf(stderr, "ExtraCode[0] is %c\n", ExtraCode[0]);
if (ExtraCode[1] != 0)
return reportAsmMemError("Unknown modifier in inline asm:");
diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
index c95db8aaea17d..de26677c161d1 100644
--- a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
+++ b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
@@ -3928,7 +3928,6 @@ SDValue PPCTargetLowering::LowerADJUST_TRAMPOLINE(SDValue Op,
}
SDValue PPCTargetLowering::LowerINLINEASM(SDValue Op, SelectionDAG &DAG) const {
- LLVM_DEBUG(dbgs() << "Lowering inline asm: "; Op.dump(&DAG));
MachineFunction &MF = DAG.getMachineFunction();
PPCFunctionInfo &MFI = *MF.getInfo<PPCFunctionInfo>();
>From f5095e92bb7507a3248750d5194a739acc400f55 Mon Sep 17 00:00:00 2001
From: Kamau Bridgeman <kamau.a.bridgeman at gmail.com>
Date: Wed, 15 Oct 2025 14:55:11 -0400
Subject: [PATCH 5/6] Reinserting accidental whitespace removal
---
llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp | 1 +
1 file changed, 1 insertion(+)
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
index 8fc6e47c3fddf..6c11c5b815b6b 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
@@ -2469,6 +2469,7 @@ bool SelectionDAGISel::IsLegalToFold(SDValue N, SDNode *U, SDNode *Root,
void SelectionDAGISel::Select_INLINEASM(SDNode *N) {
SDLoc DL(N);
+
std::vector<SDValue> Ops(N->op_begin(), N->op_end());
SelectInlineAsmMemoryOperands(Ops, DL);
>From 04e5e72be2087b0e8fc3bc79790e7a17d8cdbd86 Mon Sep 17 00:00:00 2001
From: Kamau Bridgeman <kamau.a.bridgeman at gmail.com>
Date: Wed, 15 Oct 2025 14:55:58 -0400
Subject: [PATCH 6/6] Adding Test Cases
---
.../CodeGen/PowerPC/inline-asm-constraints.c | 29 +++++++++++++++++++
.../CodeGen/PowerPC/inline-asm-constraints.ll | 21 ++++++++++++++
2 files changed, 50 insertions(+)
create mode 100644 clang/test/CodeGen/PowerPC/inline-asm-constraints.c
create mode 100644 llvm/test/CodeGen/PowerPC/inline-asm-constraints.ll
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/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
+}
More information about the cfe-commits
mailing list