[clang] [llvm] Support the inline asm 'a' constraint on PowerPC (PR #141604)
via cfe-commits
cfe-commits at lists.llvm.org
Wed May 28 08:24:55 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-powerpc
Author: Kamau Bridgeman (kamaub)
<details>
<summary>Changes</summary>
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.
---
Full diff: https://github.com/llvm/llvm-project/pull/141604.diff
9 Files Affected:
- (modified) clang/lib/Basic/Targets/PPC.h (+2-2)
- (modified) clang/test/CodeGen/PowerPC/inline-asm-constraints-error.c (+8-4)
- (added) clang/test/CodeGen/PowerPC/inline-asm-constraints.c (+66)
- (modified) llvm/include/llvm/IR/InlineAsm.h (+3)
- (modified) llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp (+8)
- (modified) llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp (+1)
- (modified) llvm/lib/Target/PowerPC/PPCISelLowering.cpp (+2)
- (modified) llvm/lib/Target/PowerPC/PPCISelLowering.h (+7-9)
- (added) llvm/test/CodeGen/PowerPC/inline-asm-constraints.ll (+127)
``````````diff
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..d0e272403c978 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.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
+}
+
``````````
</details>
https://github.com/llvm/llvm-project/pull/141604
More information about the cfe-commits
mailing list