Skip to content

Support the inline asm 'a' constraint on PowerPC #141604

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions clang/lib/Basic/Targets/PPC.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
12 changes: 8 additions & 4 deletions clang/test/CodeGen/PowerPC/inline-asm-constraints-error.c
Original file line number Diff line number Diff line change
@@ -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;
}
66 changes: 66 additions & 0 deletions clang/test/CodeGen/PowerPC/inline-asm-constraints.c
Original file line number Diff line number Diff line change
@@ -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;
}
3 changes: 3 additions & 0 deletions llvm/include/llvm/IR/InlineAsm.h
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,7 @@ class InlineAsm final : public Value {

// Address constraints
p,
a,
ZQ,
ZR,
ZS,
Expand Down Expand Up @@ -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:
Expand Down
8 changes: 8 additions & 0 deletions llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 << ")";
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/Target/PowerPC/PPCISelDAGToDAG.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/Target/PowerPC/PPCISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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':
Expand Down
16 changes: 7 additions & 9 deletions llvm/lib/Target/PowerPC/PPCISelLowering.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
127 changes: 127 additions & 0 deletions llvm/test/CodeGen/PowerPC/inline-asm-constraints.ll
Original file line number Diff line number Diff line change
@@ -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
}