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.bridge...@ibm.com> Date: Tue, 27 May 2025 09:39:07 -0400 Subject: [PATCH 1/2] [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.bridge...@ibm.com> Date: Wed, 28 May 2025 09:32:04 -0400 Subject: [PATCH 2/2] 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 -} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits