[clang] [llvm] Support the inline asm 'a' constraint on PowerPC (PR #141604)
Kamau Bridgeman via llvm-commits
llvm-commits at lists.llvm.org
Wed Oct 8 11:18:39 PDT 2025
https://github.com/kamaub updated https://github.com/llvm/llvm-project/pull/141604
>From e4102e3c4ec77e98c9a5efd3c79cd6a7690ba6a1 Mon Sep 17 00:00:00 2001
From: Kamau Bridgeman <kamau.bridgeman at ibm.com>
Date: Tue, 27 May 2025 09:39:07 -0400
Subject: [PATCH 1/5] [WIP] Support the inline asm 'a' constraint on PowerPC
This patch adds backend and frontend support for address operand
constraint `a` for GCC style inline assembly. It allows the user
to specify X-FORM addressing mode operations in inline assmebly
without doing a [0 + Reg] index using the y constraint modifier.
---
clang/lib/Basic/Targets/PPC.h | 4 +-
.../PowerPC/inline-asm-constraints-error.c | 12 +-
.../CodeGen/PowerPC/inline-asm-constraints.c | 66 +++++++++
llvm/include/llvm/IR/InlineAsm.h | 3 +
llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp | 8 ++
llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp | 1 +
llvm/lib/Target/PowerPC/PPCISelLowering.cpp | 2 +
llvm/lib/Target/PowerPC/PPCISelLowering.h | 16 +--
.../PowerPC/inline-asm-constraints-error.ll | 26 ++++
.../CodeGen/PowerPC/inline-asm-constraints.ll | 127 ++++++++++++++++++
10 files changed, 250 insertions(+), 15 deletions(-)
create mode 100644 clang/test/CodeGen/PowerPC/inline-asm-constraints.c
create mode 100644 llvm/test/CodeGen/PowerPC/inline-asm-constraints-error.ll
create mode 100644 llvm/test/CodeGen/PowerPC/inline-asm-constraints.ll
diff --git a/clang/lib/Basic/Targets/PPC.h b/clang/lib/Basic/Targets/PPC.h
index 17057cef97a57..76fb24ed40050 100644
--- a/clang/lib/Basic/Targets/PPC.h
+++ b/clang/lib/Basic/Targets/PPC.h
@@ -303,8 +303,8 @@ class LLVM_LIBRARY_VISIBILITY PPCTargetInfo : public TargetInfo {
break;
case 'a': // Address operand that is an indexed or indirect from a
// register (`p' is preferable for asm statements)
- // TODO: Add full support for this constraint
- return false;
+ Info.setAllowsRegister();
+ break;
case 'R': // AIX TOC entry
case 'S': // Constant suitable as a 64-bit mask operand
case 'T': // Constant suitable as a 32-bit mask operand
diff --git a/clang/test/CodeGen/PowerPC/inline-asm-constraints-error.c b/clang/test/CodeGen/PowerPC/inline-asm-constraints-error.c
index 2f35e52fc0b77..c1bb59ee3c22a 100644
--- a/clang/test/CodeGen/PowerPC/inline-asm-constraints-error.c
+++ b/clang/test/CodeGen/PowerPC/inline-asm-constraints-error.c
@@ -1,9 +1,13 @@
// RUN: %clang_cc1 -emit-llvm-only -triple powerpc64-ibm-aix-xcoff -verify %s
// RUN: %clang_cc1 -emit-llvm-only -triple powerpc-ibm-aix-xcoff -verify %s
-// This test case exist to test marking the 'a' inline assembly constraint as
-// unsupported because powerpc previously marked it as supported.
-int foo(int arg){
- asm goto ("bc 12,2,%l[TEST_LABEL]" : : "a"(&&TEST_LABEL) : : TEST_LABEL); //expected-error {{invalid input constraint 'a' in asm}}
+
+ int labelConstraintError(int arg){
+ asm goto ("bc 12,2,%l[TEST_LABEL]" : : "s"(&&TEST_LABEL) : : TEST_LABEL); //expected-error {{invalid input constraint 's' in asm}}
return 0;
TEST_LABEL: return arg + 1;
}
+
+char wrongAddrConstraint(char* result) {
+ asm ("stb %1,%0" : "a"(result) : "r"('E') :); //expected-error {{invalid output constraint 'a' in asm}}
+ return *result;
+}
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..ca5a9ffcee0cc
--- /dev/null
+++ b/clang/test/CodeGen/PowerPC/inline-asm-constraints.c
@@ -0,0 +1,66 @@
+// RUN: %clang_cc1 -emit-llvm -triple powerpc64-ibm-aix-xcoff \
+// RUN: %s -o - | FileCheck %s
+
+char loadAddressAConstrained(char* ptr) {
+// CHECK-LABEL: define{{.*}} i8 @loadAddressAConstrained(ptr noundef %ptr)
+// CHECK: %1 = call ptr asm "addi $0,$1, 0", "=r,a"(ptr %0)
+ char* result;
+ asm ("addi %0,%1, 0" : "=r"(result) : "a"(ptr) :);
+ return *result;
+}
+
+char loadAddressZyConstrained(char* ptr) {
+// CHECK-LABEL: define{{.*}} i8 @loadAddressZyConstrained(ptr noundef %ptr)
+// CHECK: %1 = call ptr asm "add $0,${1:y}", "=r,*Z"(ptr elementtype(i8) %0)
+ char* result;
+ asm ("add %0,%y1" : "=r"(result) : "Z"(*ptr) :);
+ return *result;
+}
+
+char xFormRegImmLoadAConstrained(char* ptr) {
+// CHECK-LABEL: define{{.*}} i8 @xFormRegImmLoadAConstrained(ptr noundef %ptr)
+// CHECK: %1 = call ptr asm "addi $0,$1,$2", "=r,a,I"(ptr %0, i32 10000)
+ char* result;
+ asm ("addi %0,%1,%2" : "=r"(result) : "a"(ptr), "I"(10000) :);
+ return *result;
+}
+
+char loadIndirectAddressZConstrained(char* ptr) {
+// CHECK-LABEL: define{{.*}} i8 @loadIndirectAddressZConstrained(ptr noundef %ptr)
+// CHECK: %1 = call ptr asm "ld $0,$1", "=r,*Z"(ptr elementtype(i8) %arrayidx)
+ char* result;
+ asm ("ld %0,%1" : "=r"(result) : "Z"(ptr[100]) :);
+ return *result;
+}
+
+char loadIndirectAddressAConstrained(char** ptr, unsigned index) {
+// CHECK-LABEL: define{{.*}} i8 @loadIndirectAddressAConstrained(ptr noundef %ptr, i32 noundef zeroext %index)
+// CHECK: %2 = call ptr asm "ldx $0,$1,$2", "=r,a,r"(ptr %0, i32 %1)
+ char* result;
+ asm ("ldx %0,%1,%2" : "=r"(result) : "a"(ptr), "r"(index) :);
+ return *result;
+}
+
+char dFormLoadZConstrained(char* ptr) {
+// CHECK-LABEL: define{{.*}} i8 @dFormLoadZConstrained(ptr noundef %ptr)
+// CHECK: %1 = call i8 asm "lbz $0,$1", "=r,*Z"(ptr elementtype(i8) %arrayidx)
+ char result;
+ asm ("lbz %0,%1" : "=r"(result) : "Z"(ptr[8]) :);
+ return result;
+}
+
+char xFormRegRegLoadZyConstrained(char* ptr, unsigned index) {
+// CHECK-LABEL: define{{.*}} i8 @xFormRegRegLoadZyConstrained(ptr noundef %ptr, i32 noundef zeroext %index)
+// CHECK: %2 = call i8 asm "lbzx $0, ${1:y}", "=r,*Z"(ptr elementtype(i8) %arrayidx)
+ char result;
+ asm("lbzx %0, %y1" : "=r"(result) : "Z"(ptr[index]) :);
+ return result;
+}
+
+char xFormRegRegLoadAConstrained(char* ptr, unsigned index) {
+// CHECK-LABEL: define{{.*}} i8 @xFormRegRegLoadAConstrained(ptr noundef %ptr, i32 noundef zeroext %index)
+// CHECK: %2 = call i8 asm "lbzx $0,$1,$2", "=r,a,r"(ptr %0, i32 %1)
+ char result;
+ asm ("lbzx %0,%1,%2" : "=r"(result) : "a"(ptr), "r"(index) :);
+ return result;
+}
diff --git a/llvm/include/llvm/IR/InlineAsm.h b/llvm/include/llvm/IR/InlineAsm.h
index e5f506e5694da..87d68acde624b 100644
--- a/llvm/include/llvm/IR/InlineAsm.h
+++ b/llvm/include/llvm/IR/InlineAsm.h
@@ -264,6 +264,7 @@ class InlineAsm final : public Value {
// Address constraints
p,
+ a,
ZQ,
ZR,
ZS,
@@ -514,6 +515,8 @@ class InlineAsm final : public Value {
return "Zy";
case ConstraintCode::p:
return "p";
+ case ConstraintCode::a:
+ return "a";
case ConstraintCode::ZQ:
return "ZQ";
case ConstraintCode::ZR:
diff --git a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
index 79e52635a3675..0c02b90747806 100644
--- a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
+++ b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
@@ -442,6 +442,14 @@ bool PPCAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
}
assert(MI->getOperand(OpNo).isReg());
+ const MachineOperand &FlagsOP = MI->getOperand(OpNo - 1);
+ if (!FlagsOP.isImm())
+ return true;
+ const InlineAsm::Flag Flags(FlagsOP.getImm());
+ if (Flags.getMemoryConstraintID() == InlineAsm::ConstraintCode::a) {
+ printOperand(MI, OpNo, O);
+ return false;
+ }
O << "0(";
printOperand(MI, OpNo, O);
O << ")";
diff --git a/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp b/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp
index 0907239153226..e4029d3612b9f 100644
--- a/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp
+++ b/llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp
@@ -392,6 +392,7 @@ namespace {
errs() << "ConstraintID: "
<< InlineAsm::getMemConstraintName(ConstraintID) << "\n";
llvm_unreachable("Unexpected asm memory constraint");
+ case InlineAsm::ConstraintCode::a:
case InlineAsm::ConstraintCode::es:
case InlineAsm::ConstraintCode::m:
case InlineAsm::ConstraintCode::o:
diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
index ab78f33f5a630..843aec1ae4b99 100644
--- a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
+++ b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
@@ -17184,6 +17184,8 @@ PPCTargetLowering::getConstraintType(StringRef Constraint) const {
if (Constraint.size() == 1) {
switch (Constraint[0]) {
default: break;
+ case 'a':
+ return C_Address;
case 'b':
case 'r':
case 'f':
diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.h b/llvm/lib/Target/PowerPC/PPCISelLowering.h
index 1f22aa16a89be..0ecb54dcf2f39 100644
--- a/llvm/lib/Target/PowerPC/PPCISelLowering.h
+++ b/llvm/lib/Target/PowerPC/PPCISelLowering.h
@@ -997,15 +997,13 @@ namespace llvm {
InlineAsm::ConstraintCode
getInlineAsmMemConstraint(StringRef ConstraintCode) const override {
- if (ConstraintCode == "es")
- return InlineAsm::ConstraintCode::es;
- else if (ConstraintCode == "Q")
- return InlineAsm::ConstraintCode::Q;
- else if (ConstraintCode == "Z")
- return InlineAsm::ConstraintCode::Z;
- else if (ConstraintCode == "Zy")
- return InlineAsm::ConstraintCode::Zy;
- return TargetLowering::getInlineAsmMemConstraint(ConstraintCode);
+ return StringSwitch<InlineAsm::ConstraintCode>(ConstraintCode)
+ .Case("es", InlineAsm::ConstraintCode::es)
+ .Case("Q", InlineAsm::ConstraintCode::Q)
+ .Case("Z", InlineAsm::ConstraintCode::Z)
+ .Case("Zy", InlineAsm::ConstraintCode::Zy)
+ .Case("a", InlineAsm::ConstraintCode::a)
+ .Default(TargetLowering::getInlineAsmMemConstraint(ConstraintCode));
}
void CollectTargetIntrinsicOperands(const CallInst &I,
diff --git a/llvm/test/CodeGen/PowerPC/inline-asm-constraints-error.ll b/llvm/test/CodeGen/PowerPC/inline-asm-constraints-error.ll
new file mode 100644
index 0000000000000..d7fbdfed89ce3
--- /dev/null
+++ b/llvm/test/CodeGen/PowerPC/inline-asm-constraints-error.ll
@@ -0,0 +1,26 @@
+; RUN: not llc -mcpu=pwr8 -mtriple=powerpc64-ibm-aix-xcoff -filetype=null %s 2>&1 | FileCheck %s
+; XFAIL: *
+
+; CHECK: LLVM ERROR: Do not know how to promote this operator's operand!
+define i8 @charLoadAConstrained(i8 zeroext %ptr, i32 %index) {
+entry:
+ %0 = tail call i16 asm "lbzx $0,$1,$2", "=r,a,r"(i8 %ptr, i32 %index)
+ %conv = trunc i16 %0 to i8
+ ret i8 %conv
+}
+
+define i8 @shortLoadAConstrained(i16 zeroext %ptr, i32 %index) {
+; CHECK: LLVM ERROR: Do not know how to promote this operator's operand!
+entry:
+ %0 = tail call i16 asm "lbzx $0,$1,$2", "=r,a,r"(i16 %ptr, i32 %index)
+ %conv = trunc i16 %0 to i8
+ ret i8 %conv
+}
+
+define i8 @intLoadAConstrained(i32 zeroext %ptr, i32 %index) {
+; CHECK: LLVM ERROR: Do not know how to promote this operator's operand!
+entry:
+ %0 = tail call i16 asm "lbzx $0,$1,$2", "=r,a,r"(i32 %ptr, i32 %index)
+ %conv = trunc i16 %0 to i8
+ ret i8 %conv
+}
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..4781bd7d0b235
--- /dev/null
+++ b/llvm/test/CodeGen/PowerPC/inline-asm-constraints.ll
@@ -0,0 +1,127 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc -verify-machineinstrs < %s -mcpu=pwr8 -no-integrated-as \
+; RUN: -mtriple=powerpc64-ibm-aix-xcoff | FileCheck %s
+; RUN: llc -verify-machineinstrs < %s -mcpu=pwr8 -no-integrated-as \
+; RUN: -mtriple=powerpc-ibm-aix-xcoff | FileCheck %s
+
+define signext i8 @loadAddressAConstrained(ptr %ptr) {
+; CHECK-LABEL: loadAddressAConstrained:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: #APP
+; CHECK-NEXT: addi 3,3, 0
+; CHECK-NEXT: #NO_APP
+; CHECK-NEXT: lbz 3, 0(3)
+; CHECK-NEXT: extsb 3, 3
+; CHECK-NEXT: blr
+entry:
+ %0 = tail call ptr asm "addi $0,$1, 0", "=r,a"(ptr %ptr)
+ %1 = load i8, ptr %0, align 1
+ ret i8 %1
+}
+
+define signext i8 @xFormRegImmLoadAConstrained(ptr %ptr) {
+; CHECK-LABEL: xFormRegImmLoadAConstrained:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: #APP
+; CHECK-NEXT: addi 3,3,10000
+; CHECK-NEXT: #NO_APP
+; CHECK-NEXT: lbz 3, 0(3)
+; CHECK-NEXT: extsb 3, 3
+; CHECK-NEXT: blr
+entry:
+ %0 = tail call ptr asm "addi $0,$1,$2", "=r,a,I"(ptr %ptr, i32 10000)
+ %1 = load i8, ptr %0, align 1
+ ret i8 %1
+}
+
+define signext i8 @loadIndirectAddressZConstrained(ptr %ptr) {
+; CHECK-LABEL: loadIndirectAddressZConstrained:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: addi 3, 3, 800
+; CHECK-NEXT: #APP
+; CHECK-NEXT: ld 3,0(3)
+; CHECK-NEXT: #NO_APP
+; CHECK-NEXT: lbz 3, 0(3)
+; CHECK-NEXT: extsb 3, 3
+; CHECK-NEXT: blr
+entry:
+ %arrayidx = getelementptr inbounds nuw i8, ptr %ptr, i64 800
+ %0 = tail call ptr asm "ld $0,$1", "=r,*Z"(ptr nonnull elementtype(ptr) %arrayidx)
+ %1 = load i8, ptr %0, align 1
+ ret i8 %1
+}
+
+define signext i8 @loadIndirectAddressAConstrained(ptr %ptr, i32 zeroext %index) {
+; CHECK-LABEL: loadIndirectAddressAConstrained:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: #APP
+; CHECK-NEXT: ldx 3,3,4
+; CHECK-NEXT: #NO_APP
+; CHECK-NEXT: lbz 3, 0(3)
+; CHECK-NEXT: extsb 3, 3
+; CHECK-NEXT: blr
+entry:
+ %0 = tail call ptr asm "ldx $0,$1,$2", "=r,a,r"(ptr %ptr, i32 zeroext %index)
+ %1 = load i8, ptr %0, align 1
+ ret i8 %1
+}
+
+define signext i8 @dFormLoadZConstrained(ptr %ptr) {
+; CHECK-LABEL: dFormLoadZConstrained:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: addi 3, 3, 8
+; CHECK-NEXT: #APP
+; CHECK-NEXT: lbz 3,0(3)
+; CHECK-NEXT: #NO_APP
+; CHECK-NEXT: extsb 3, 3
+; CHECK-NEXT: blr
+entry:
+ %arrayidx = getelementptr inbounds nuw i8, ptr %ptr, i64 8
+ %0 = tail call i8 asm "lbz $0,$1", "=r,*Z"(ptr nonnull elementtype(i8) %arrayidx)
+ ret i8 %0
+}
+
+define signext i8 @xFormRegRegLoadZyConstrained(ptr %ptr, i32 zeroext %index) {
+; CHECK-LABEL: xFormRegRegLoadZyConstrained:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: add 3, 3, 4
+; CHECK-NEXT: #APP
+; CHECK-NEXT: lbzx 3, 0, 3
+; CHECK-NEXT: #NO_APP
+; CHECK-NEXT: extsb 3, 3
+; CHECK-NEXT: blr
+entry:
+ %idxprom = zext i32 %index to i64
+ %arrayidx = getelementptr inbounds nuw i8, ptr %ptr, i64 %idxprom
+ %0 = tail call i8 asm "lbzx $0, ${1:y}", "=r,*Z"(ptr elementtype(i8) %arrayidx)
+ ret i8 %0
+}
+
+define signext i8 @xFormRegRegLoadAConstrained(ptr %ptr, i32 zeroext %index) {
+; CHECK-LABEL: xFormRegRegLoadAConstrained:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: #APP
+; CHECK-NEXT: lbzx 3,3,4
+; CHECK-NEXT: #NO_APP
+; CHECK-NEXT: extsb 3, 3
+; CHECK-NEXT: blr
+entry:
+ %0 = tail call i8 asm "lbzx $0,$1,$2", "=r,a,r"(ptr %ptr, i32 %index)
+ ret i8 %0
+}
+
+define i8 @implicitRegImmToRegRegConversion(ptr readnone %ptr, i32 zeroext %index) {
+; CHECK-LABEL: implicitRegImmToRegRegConversion:
+; CHECK: # %bb.0: # %entry
+; CHECK-NEXT: add 3, 3, 4
+; CHECK-NEXT: #APP
+; CHECK-NEXT: lbzx 3, 0, 3
+; CHECK-NEXT: #NO_APP
+; CHECK-NEXT: blr
+entry:
+ %idx.ext = zext i32 %index to i64
+ %add.ptr = getelementptr inbounds nuw i8, ptr %ptr, i64 %idx.ext
+ %0 = tail call i8 asm "lbzx $0, ${1:y}", "=r,a"(ptr %add.ptr)
+ ret i8 %0
+}
+
>From a0357a963865beed4ed8af215e2dc99fbd941b59 Mon Sep 17 00:00:00 2001
From: Kamau Bridgeman <kamau.bridgeman at ibm.com>
Date: Wed, 28 May 2025 09:32:04 -0400
Subject: [PATCH 2/5] Removing the backend type promotion test case file
The backend test case file detailing type promotion errors when
using this constraint has been identified as a separate issue
that is exposed by this patch. A separate issue, and PR will
resolve this problem.
---
.../PowerPC/inline-asm-constraints-error.ll | 26 -------------------
1 file changed, 26 deletions(-)
delete mode 100644 llvm/test/CodeGen/PowerPC/inline-asm-constraints-error.ll
diff --git a/llvm/test/CodeGen/PowerPC/inline-asm-constraints-error.ll b/llvm/test/CodeGen/PowerPC/inline-asm-constraints-error.ll
deleted file mode 100644
index d7fbdfed89ce3..0000000000000
--- a/llvm/test/CodeGen/PowerPC/inline-asm-constraints-error.ll
+++ /dev/null
@@ -1,26 +0,0 @@
-; RUN: not llc -mcpu=pwr8 -mtriple=powerpc64-ibm-aix-xcoff -filetype=null %s 2>&1 | FileCheck %s
-; XFAIL: *
-
-; CHECK: LLVM ERROR: Do not know how to promote this operator's operand!
-define i8 @charLoadAConstrained(i8 zeroext %ptr, i32 %index) {
-entry:
- %0 = tail call i16 asm "lbzx $0,$1,$2", "=r,a,r"(i8 %ptr, i32 %index)
- %conv = trunc i16 %0 to i8
- ret i8 %conv
-}
-
-define i8 @shortLoadAConstrained(i16 zeroext %ptr, i32 %index) {
-; CHECK: LLVM ERROR: Do not know how to promote this operator's operand!
-entry:
- %0 = tail call i16 asm "lbzx $0,$1,$2", "=r,a,r"(i16 %ptr, i32 %index)
- %conv = trunc i16 %0 to i8
- ret i8 %conv
-}
-
-define i8 @intLoadAConstrained(i32 zeroext %ptr, i32 %index) {
-; CHECK: LLVM ERROR: Do not know how to promote this operator's operand!
-entry:
- %0 = tail call i16 asm "lbzx $0,$1,$2", "=r,a,r"(i32 %ptr, i32 %index)
- %conv = trunc i16 %0 to i8
- ret i8 %conv
-}
>From 9890270ec4e9e9b42f74a9204757cf63c625e870 Mon Sep 17 00:00:00 2001
From: Kamau Bridgeman <kamau.bridgeman at ibm.com>
Date: Wed, 28 May 2025 11:23:45 -0400
Subject: [PATCH 3/5] Applying git clang format NFC
---
llvm/lib/Target/PowerPC/PPCISelLowering.h | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.h b/llvm/lib/Target/PowerPC/PPCISelLowering.h
index 0ecb54dcf2f39..d0e272403c978 100644
--- a/llvm/lib/Target/PowerPC/PPCISelLowering.h
+++ b/llvm/lib/Target/PowerPC/PPCISelLowering.h
@@ -998,12 +998,12 @@ namespace llvm {
InlineAsm::ConstraintCode
getInlineAsmMemConstraint(StringRef ConstraintCode) const override {
return StringSwitch<InlineAsm::ConstraintCode>(ConstraintCode)
- .Case("es", InlineAsm::ConstraintCode::es)
- .Case("Q", InlineAsm::ConstraintCode::Q)
- .Case("Z", InlineAsm::ConstraintCode::Z)
- .Case("Zy", InlineAsm::ConstraintCode::Zy)
- .Case("a", InlineAsm::ConstraintCode::a)
- .Default(TargetLowering::getInlineAsmMemConstraint(ConstraintCode));
+ .Case("es", InlineAsm::ConstraintCode::es)
+ .Case("Q", InlineAsm::ConstraintCode::Q)
+ .Case("Z", InlineAsm::ConstraintCode::Z)
+ .Case("Zy", InlineAsm::ConstraintCode::Zy)
+ .Case("a", InlineAsm::ConstraintCode::a)
+ .Default(TargetLowering::getInlineAsmMemConstraint(ConstraintCode));
}
void CollectTargetIntrinsicOperands(const CallInst &I,
>From fa7236e77a2d52b07cdd9d91f01a88c01002b623 Mon Sep 17 00:00:00 2001
From: Kamau Bridgeman <kamau.a.bridgeman at gmail.com>
Date: Wed, 8 Oct 2025 14:11:27 -0400
Subject: [PATCH 4/5] Addressing Review comments
Adding comments and additional test case run lines to the change-set.
---
.../PowerPC/inline-asm-constraints-error.c | 2 ++
.../CodeGen/PowerPC/inline-asm-constraints.c | 11 ++++++++---
llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp | 6 ++++++
llvm/lib/Target/PowerPC/PPCISelLowering.cpp | 1 +
.../CodeGen/PowerPC/inline-asm-constraints.ll | 16 ++++++++--------
5 files changed, 25 insertions(+), 11 deletions(-)
diff --git a/clang/test/CodeGen/PowerPC/inline-asm-constraints-error.c b/clang/test/CodeGen/PowerPC/inline-asm-constraints-error.c
index c1bb59ee3c22a..6d1101dc81bee 100644
--- a/clang/test/CodeGen/PowerPC/inline-asm-constraints-error.c
+++ b/clang/test/CodeGen/PowerPC/inline-asm-constraints-error.c
@@ -1,5 +1,7 @@
// RUN: %clang_cc1 -emit-llvm-only -triple powerpc64-ibm-aix-xcoff -verify %s
// RUN: %clang_cc1 -emit-llvm-only -triple powerpc-ibm-aix-xcoff -verify %s
+// This test file validates that we diagnose inline assembly constraint error
+// in the clang front-end as expected.
int labelConstraintError(int arg){
asm goto ("bc 12,2,%l[TEST_LABEL]" : : "s"(&&TEST_LABEL) : : TEST_LABEL); //expected-error {{invalid input constraint 's' in asm}}
diff --git a/clang/test/CodeGen/PowerPC/inline-asm-constraints.c b/clang/test/CodeGen/PowerPC/inline-asm-constraints.c
index ca5a9ffcee0cc..365c2fb3a4dac 100644
--- a/clang/test/CodeGen/PowerPC/inline-asm-constraints.c
+++ b/clang/test/CodeGen/PowerPC/inline-asm-constraints.c
@@ -1,5 +1,10 @@
// RUN: %clang_cc1 -emit-llvm -triple powerpc64-ibm-aix-xcoff \
// RUN: %s -o - | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm -triple powerpc-ibm-aix-xcoff \
+// RUN: %s -o - | FileCheck %s
+// This test file checks that we represent common C inline assembly
+// PowerPC load address mode operations accureately in the platform
+// agnostic LLVM IR.
char loadAddressAConstrained(char* ptr) {
// CHECK-LABEL: define{{.*}} i8 @loadAddressAConstrained(ptr noundef %ptr)
@@ -34,7 +39,7 @@ char loadIndirectAddressZConstrained(char* ptr) {
}
char loadIndirectAddressAConstrained(char** ptr, unsigned index) {
-// CHECK-LABEL: define{{.*}} i8 @loadIndirectAddressAConstrained(ptr noundef %ptr, i32 noundef zeroext %index)
+// CHECK-LABEL: define{{.*}} i8 @loadIndirectAddressAConstrained(ptr noundef %ptr, i32 noundef{{[ zeroext]*}} %index)
// CHECK: %2 = call ptr asm "ldx $0,$1,$2", "=r,a,r"(ptr %0, i32 %1)
char* result;
asm ("ldx %0,%1,%2" : "=r"(result) : "a"(ptr), "r"(index) :);
@@ -50,7 +55,7 @@ char dFormLoadZConstrained(char* ptr) {
}
char xFormRegRegLoadZyConstrained(char* ptr, unsigned index) {
-// CHECK-LABEL: define{{.*}} i8 @xFormRegRegLoadZyConstrained(ptr noundef %ptr, i32 noundef zeroext %index)
+// CHECK-LABEL: define{{.*}} i8 @xFormRegRegLoadZyConstrained(ptr noundef %ptr, i32 noundef{{[ zeroext]*}} %index)
// CHECK: %2 = call i8 asm "lbzx $0, ${1:y}", "=r,*Z"(ptr elementtype(i8) %arrayidx)
char result;
asm("lbzx %0, %y1" : "=r"(result) : "Z"(ptr[index]) :);
@@ -58,7 +63,7 @@ char xFormRegRegLoadZyConstrained(char* ptr, unsigned index) {
}
char xFormRegRegLoadAConstrained(char* ptr, unsigned index) {
-// CHECK-LABEL: define{{.*}} i8 @xFormRegRegLoadAConstrained(ptr noundef %ptr, i32 noundef zeroext %index)
+// CHECK-LABEL: define{{.*}} i8 @xFormRegRegLoadAConstrained(ptr noundef %ptr, i32 noundef{{[ zeroext]*}} %index)
// CHECK: %2 = call i8 asm "lbzx $0,$1,$2", "=r,a,r"(ptr %0, i32 %1)
char result;
asm ("lbzx %0,%1,%2" : "=r"(result) : "a"(ptr), "r"(index) :);
diff --git a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
index 0c02b90747806..8dff8c4954a0b 100644
--- a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
+++ b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
@@ -441,11 +441,17 @@ bool PPCAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
}
}
+ // Assert that this an register input operand to an inline asm statement.
assert(MI->getOperand(OpNo).isReg());
+ // The ConstraintInfo for this Operand is encounted in Op - 1 operand
+ // as a part of the InlineAsm Flags.
const MachineOperand &FlagsOP = MI->getOperand(OpNo - 1);
if (!FlagsOP.isImm())
return true;
const InlineAsm::Flag Flags(FlagsOP.getImm());
+ // Address operand is a Register for an X-form instruction, similar to the
+ // 'y' Extra Code. Constraint 'a' allows reg+reg Addressing without using
+ // a 'y' input modifier in Extended GCC ASM.
if (Flags.getMemoryConstraintID() == InlineAsm::ConstraintCode::a) {
printOperand(MI, OpNo, O);
return false;
diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
index 843aec1ae4b99..c1ac8986fa982 100644
--- a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
+++ b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp
@@ -17185,6 +17185,7 @@ PPCTargetLowering::getConstraintType(StringRef Constraint) const {
switch (Constraint[0]) {
default: break;
case 'a':
+ // 'a' constraints inputs to address operands.
return C_Address;
case 'b':
case 'r':
diff --git a/llvm/test/CodeGen/PowerPC/inline-asm-constraints.ll b/llvm/test/CodeGen/PowerPC/inline-asm-constraints.ll
index 4781bd7d0b235..6d84bed509afd 100644
--- a/llvm/test/CodeGen/PowerPC/inline-asm-constraints.ll
+++ b/llvm/test/CodeGen/PowerPC/inline-asm-constraints.ll
@@ -1,14 +1,14 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
-; RUN: llc -verify-machineinstrs < %s -mcpu=pwr8 -no-integrated-as \
+; RUN: llc -verify-machineinstrs < %s -mcpu=pwr8 \
; RUN: -mtriple=powerpc64-ibm-aix-xcoff | FileCheck %s
-; RUN: llc -verify-machineinstrs < %s -mcpu=pwr8 -no-integrated-as \
+; RUN: llc -verify-machineinstrs < %s -mcpu=pwr8 \
; RUN: -mtriple=powerpc-ibm-aix-xcoff | FileCheck %s
define signext i8 @loadAddressAConstrained(ptr %ptr) {
; CHECK-LABEL: loadAddressAConstrained:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: #APP
-; CHECK-NEXT: addi 3,3, 0
+; CHECK-NEXT: addi 3, 3, 0
; CHECK-NEXT: #NO_APP
; CHECK-NEXT: lbz 3, 0(3)
; CHECK-NEXT: extsb 3, 3
@@ -23,7 +23,7 @@ define signext i8 @xFormRegImmLoadAConstrained(ptr %ptr) {
; CHECK-LABEL: xFormRegImmLoadAConstrained:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: #APP
-; CHECK-NEXT: addi 3,3,10000
+; CHECK-NEXT: addi 3, 3, 10000
; CHECK-NEXT: #NO_APP
; CHECK-NEXT: lbz 3, 0(3)
; CHECK-NEXT: extsb 3, 3
@@ -39,7 +39,7 @@ define signext i8 @loadIndirectAddressZConstrained(ptr %ptr) {
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: addi 3, 3, 800
; CHECK-NEXT: #APP
-; CHECK-NEXT: ld 3,0(3)
+; CHECK-NEXT: ld 3, 0(3)
; CHECK-NEXT: #NO_APP
; CHECK-NEXT: lbz 3, 0(3)
; CHECK-NEXT: extsb 3, 3
@@ -55,7 +55,7 @@ define signext i8 @loadIndirectAddressAConstrained(ptr %ptr, i32 zeroext %index)
; CHECK-LABEL: loadIndirectAddressAConstrained:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: #APP
-; CHECK-NEXT: ldx 3,3,4
+; CHECK-NEXT: ldx 3, 3, 4
; CHECK-NEXT: #NO_APP
; CHECK-NEXT: lbz 3, 0(3)
; CHECK-NEXT: extsb 3, 3
@@ -71,7 +71,7 @@ define signext i8 @dFormLoadZConstrained(ptr %ptr) {
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: addi 3, 3, 8
; CHECK-NEXT: #APP
-; CHECK-NEXT: lbz 3,0(3)
+; CHECK-NEXT: lbz 3, 0(3)
; CHECK-NEXT: #NO_APP
; CHECK-NEXT: extsb 3, 3
; CHECK-NEXT: blr
@@ -101,7 +101,7 @@ define signext i8 @xFormRegRegLoadAConstrained(ptr %ptr, i32 zeroext %index) {
; CHECK-LABEL: xFormRegRegLoadAConstrained:
; CHECK: # %bb.0: # %entry
; CHECK-NEXT: #APP
-; CHECK-NEXT: lbzx 3,3,4
+; CHECK-NEXT: lbzx 3, 3, 4
; CHECK-NEXT: #NO_APP
; CHECK-NEXT: extsb 3, 3
; CHECK-NEXT: blr
>From cc03557676e67887aa2f39270b82d5924c634476 Mon Sep 17 00:00:00 2001
From: Kamau Bridgeman <kamau.a.bridgeman at gmail.com>
Date: Wed, 8 Oct 2025 14:14:38 -0400
Subject: [PATCH 5/5] Apply suggestion from @kamaub
---
llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
index 8dff8c4954a0b..7649fb7d00cc7 100644
--- a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
+++ b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
@@ -443,7 +443,7 @@ bool PPCAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
// Assert that this an register input operand to an inline asm statement.
assert(MI->getOperand(OpNo).isReg());
- // The ConstraintInfo for this Operand is encounted in Op - 1 operand
+ // The ConstraintInfo for this Operand is encoded in Op - 1 operand
// as a part of the InlineAsm Flags.
const MachineOperand &FlagsOP = MI->getOperand(OpNo - 1);
if (!FlagsOP.isImm())
More information about the llvm-commits
mailing list