[SystemZ] Handle SystemZ specific inline assembly address operands.

Handle ZQ, ZR, ZS and ZT inline assembly operand constraints.

Review: Ulrich Weigand

Differential Revision: https://reviews.llvm.org/D110267
This commit is contained in:
Jonas Paulsson 2022-03-22 10:40:18 +01:00
parent 82f3ed9904
commit 4aa5dc15f0
8 changed files with 386 additions and 1 deletions

View file

@ -59,6 +59,17 @@ bool SystemZTargetInfo::validateAsmConstraint(
default:
return false;
case 'Z':
switch (Name[1]) {
default:
return false;
case 'Q': // Address with base and unsigned 12-bit displacement
case 'R': // Likewise, plus an index
case 'S': // Address with base and signed 20-bit displacement
case 'T': // Likewise, plus an index
break;
}
LLVM_FALLTHROUGH;
case 'a': // Address register
case 'd': // Data register (equivalent to 'r')
case 'f': // Floating-point register

View file

@ -86,6 +86,20 @@ public:
switch (Constraint[0]) {
case 'p': // Keep 'p' constraint.
return std::string("p");
case 'Z':
switch (Constraint[1]) {
case 'Q': // Address with base and unsigned 12-bit displacement
case 'R': // Likewise, plus an index
case 'S': // Address with base and signed 20-bit displacement
case 'T': // Likewise, plus an index
// "^" hints llvm that this is a 2 letter constraint.
// "Constraint++" is used to promote the string iterator
// to the next constraint.
return std::string("^") + std::string(Constraint++, 2);
default:
break;
}
break;
default:
break;
}

View file

@ -6,6 +6,34 @@ long *A;
long Idx;
unsigned long Addr;
unsigned long fun_BD12_Q() {
// CHECK-LABEL: define{{.*}} i64 @fun_BD12_Q()
// CHECK: call i64 asm "lay $0, $1", "=r,^ZQ"(i64* nonnull %arrayidx)
asm("lay %0, %1" : "=r" (Addr) : "ZQ" (&A[100]));
return Addr;
}
unsigned long fun_BD12_R() {
// CHECK-LABEL: define{{.*}} i64 @fun_BD12_R()
// CHECK: call i64 asm "lay $0, $1", "=r,^ZR"(i64* nonnull %arrayidx)
asm("lay %0, %1" : "=r" (Addr) : "ZR" (&A[100]));
return Addr;
}
unsigned long fun_BD12_S() {
// CHECK-LABEL: define{{.*}} i64 @fun_BD12_S()
// CHECK: call i64 asm "lay $0, $1", "=r,^ZS"(i64* nonnull %arrayidx)
asm("lay %0, %1" : "=r" (Addr) : "ZS" (&A[100]));
return Addr;
}
unsigned long fun_BD12_T() {
// CHECK-LABEL: define{{.*}} i64 @fun_BD12_T()
// CHECK: call i64 asm "lay $0, $1", "=r,^ZT"(i64* nonnull %arrayidx)
asm("lay %0, %1" : "=r" (Addr) : "ZT" (&A[100]));
return Addr;
}
unsigned long fun_BD12_p() {
// CHECK-LABEL: define{{.*}} i64 @fun_BD12_p()
// CHECK: call i64 asm "lay $0, $1", "=r,p"(i64* nonnull %arrayidx)
@ -13,6 +41,34 @@ unsigned long fun_BD12_p() {
return Addr;
}
unsigned long fun_BDX12_Q() {
// CHECK-LABEL: define{{.*}} i64 @fun_BDX12_Q()
// CHECK: call i64 asm "lay $0, $1", "=r,^ZQ"(i64* %arrayidx)
asm("lay %0, %1" : "=r" (Addr) : "ZQ" (&A[Idx + 100]));
return Addr;
}
unsigned long fun_BDX12_R() {
// CHECK-LABEL: define{{.*}} i64 @fun_BDX12_R()
// CHECK: call i64 asm "lay $0, $1", "=r,^ZR"(i64* %arrayidx)
asm("lay %0, %1" : "=r" (Addr) : "ZR" (&A[Idx + 100]));
return Addr;
}
unsigned long fun_BDX12_S() {
// CHECK-LABEL: define{{.*}} i64 @fun_BDX12_S()
// CHECK: call i64 asm "lay $0, $1", "=r,^ZS"(i64* %arrayidx)
asm("lay %0, %1" : "=r" (Addr) : "ZS" (&A[Idx + 100]));
return Addr;
}
unsigned long fun_BDX12_T() {
// CHECK-LABEL: define{{.*}} i64 @fun_BDX12_T()
// CHECK: call i64 asm "lay $0, $1", "=r,^ZT"(i64* %arrayidx)
asm("lay %0, %1" : "=r" (Addr) : "ZT" (&A[Idx + 100]));
return Addr;
}
unsigned long fun_BDX12_p() {
// CHECK-LABEL: define{{.*}} i64 @fun_BDX12_p()
// CHECK: call i64 asm "lay $0, $1", "=r,p"(i64* %arrayidx)
@ -20,6 +76,34 @@ unsigned long fun_BDX12_p() {
return Addr;
}
unsigned long fun_BD20_Q() {
// CHECK-LABEL: define{{.*}} i64 @fun_BD20_Q()
// CHECK: call i64 asm "lay $0, $1", "=r,^ZQ"(i64* nonnull %arrayidx)
asm("lay %0, %1" : "=r" (Addr) : "ZQ" (&A[1000]));
return Addr;
}
unsigned long fun_BD20_R() {
// CHECK-LABEL: define{{.*}} i64 @fun_BD20_R()
// CHECK: call i64 asm "lay $0, $1", "=r,^ZR"(i64* nonnull %arrayidx)
asm("lay %0, %1" : "=r" (Addr) : "ZR" (&A[1000]));
return Addr;
}
unsigned long fun_BD20_S() {
// CHECK-LABEL: define{{.*}} i64 @fun_BD20_S()
// CHECK: call i64 asm "lay $0, $1", "=r,^ZS"(i64* nonnull %arrayidx)
asm("lay %0, %1" : "=r" (Addr) : "ZS" (&A[1000]));
return Addr;
}
unsigned long fun_BD20_T() {
// CHECK-LABEL: define{{.*}} i64 @fun_BD20_T()
// CHECK: call i64 asm "lay $0, $1", "=r,^ZT"(i64* nonnull %arrayidx)
asm("lay %0, %1" : "=r" (Addr) : "ZT" (&A[1000]));
return Addr;
}
unsigned long fun_BD20_p() {
// CHECK-LABEL: define{{.*}} i64 @fun_BD20_p()
// CHECK: call i64 asm "lay $0, $1", "=r,p"(i64* nonnull %arrayidx)
@ -27,6 +111,34 @@ unsigned long fun_BD20_p() {
return Addr;
}
unsigned long fun_BDX20_Q() {
// CHECK-LABEL: define{{.*}} i64 @fun_BDX20_Q()
// CHECK: call i64 asm "lay $0, $1", "=r,^ZQ"(i64* %arrayidx)
asm("lay %0, %1" : "=r" (Addr) : "ZQ" (&A[Idx + 1000]));
return Addr;
}
unsigned long fun_BDX20_R() {
// CHECK-LABEL: define{{.*}} i64 @fun_BDX20_R()
// CHECK: call i64 asm "lay $0, $1", "=r,^ZR"(i64* %arrayidx)
asm("lay %0, %1" : "=r" (Addr) : "ZR" (&A[Idx + 1000]));
return Addr;
}
unsigned long fun_BDX20_S() {
// CHECK-LABEL: define{{.*}} i64 @fun_BDX20_S()
// CHECK: call i64 asm "lay $0, $1", "=r,^ZS"(i64* %arrayidx)
asm("lay %0, %1" : "=r" (Addr) : "ZS" (&A[Idx + 1000]));
return Addr;
}
unsigned long fun_BDX20_T() {
// CHECK-LABEL: define{{.*}} i64 @fun_BDX20_T()
// CHECK: call i64 asm "lay $0, $1", "=r,^ZT"(i64* %arrayidx)
asm("lay %0, %1" : "=r" (Addr) : "ZT" (&A[Idx + 1000]));
return Addr;
}
unsigned long fun_BDX20_p() {
// CHECK-LABEL: define{{.*}} i64 @fun_BDX20_p()
// CHECK: call i64 asm "lay $0, $1", "=r,p"(i64* %arrayidx)

View file

@ -274,8 +274,12 @@ public:
// Address constraints
Constraint_p,
Constraint_ZQ,
Constraint_ZR,
Constraint_ZS,
Constraint_ZT,
Constraints_Max = Constraint_p,
Constraints_Max = Constraint_ZT,
Constraints_ShiftAmount = 16,
Flag_MatchingOperand = 0x80000000
@ -462,6 +466,14 @@ public:
return "Zy";
case InlineAsm::Constraint_p:
return "p";
case InlineAsm::Constraint_ZQ:
return "ZQ";
case InlineAsm::Constraint_ZR:
return "ZR";
case InlineAsm::Constraint_ZS:
return "ZS";
case InlineAsm::Constraint_ZT:
return "ZT";
default:
llvm_unreachable("Unknown memory constraint");
}

View file

@ -1683,16 +1683,19 @@ SelectInlineAsmMemoryOperand(const SDValue &Op,
llvm_unreachable("Unexpected asm memory constraint");
case InlineAsm::Constraint_i:
case InlineAsm::Constraint_Q:
case InlineAsm::Constraint_ZQ:
// Accept an address with a short displacement, but no index.
Form = SystemZAddressingMode::FormBD;
DispRange = SystemZAddressingMode::Disp12Only;
break;
case InlineAsm::Constraint_R:
case InlineAsm::Constraint_ZR:
// Accept an address with a short displacement and an index.
Form = SystemZAddressingMode::FormBDXNormal;
DispRange = SystemZAddressingMode::Disp12Only;
break;
case InlineAsm::Constraint_S:
case InlineAsm::Constraint_ZS:
// Accept an address with a long displacement, but no index.
Form = SystemZAddressingMode::FormBD;
DispRange = SystemZAddressingMode::Disp20Only;
@ -1701,6 +1704,7 @@ SelectInlineAsmMemoryOperand(const SDValue &Op,
case InlineAsm::Constraint_m:
case InlineAsm::Constraint_o:
case InlineAsm::Constraint_p:
case InlineAsm::Constraint_ZT:
// Accept an address with a long displacement and an index.
// m works the same as T, as this is the most general case.
// We don't really have any special handling of "offsettable"

View file

@ -1034,6 +1034,17 @@ SystemZTargetLowering::getConstraintType(StringRef Constraint) const {
case 'M': // 0x7fffffff
return C_Immediate;
default:
break;
}
} else if (Constraint.size() == 2 && Constraint[0] == 'Z') {
switch (Constraint[1]) {
case 'Q': // Address with base and unsigned 12-bit displacement
case 'R': // Likewise, plus an index
case 'S': // Address with base and signed 20-bit displacement
case 'T': // Likewise, plus an index
return C_Address;
default:
break;
}

View file

@ -497,6 +497,19 @@ public:
case 'T':
return InlineAsm::Constraint_T;
}
} else if (ConstraintCode.size() == 2 && ConstraintCode[0] == 'Z') {
switch (ConstraintCode[1]) {
default:
break;
case 'Q':
return InlineAsm::Constraint_ZQ;
case 'R':
return InlineAsm::Constraint_ZR;
case 'S':
return InlineAsm::Constraint_ZS;
case 'T':
return InlineAsm::Constraint_ZT;
}
}
return TargetLowering::getInlineAsmMemConstraint(ConstraintCode);
}

View file

@ -4,6 +4,54 @@
@A = global i64* null, align 8
@Idx = global i64 0, align 8
define i64 @fun_BD12_Q() {
; CHECK-LABEL: fun_BD12_Q:
; CHECK: #APP
; CHECK: lay %r2, 800(%r1)
entry:
%0 = load i64*, i64** @A
%arrayidx = getelementptr inbounds i64, i64* %0, i64 100
%1 = tail call i64 asm "lay $0, $1", "=r,^ZQ"(i64* nonnull %arrayidx)
store i64 %1, i64* @Addr
ret i64 %1
}
define i64 @fun_BD12_R() {
; CHECK-LABEL: fun_BD12_R:
; CHECK: #APP
; CHECK: lay %r2, 800(%r1)
entry:
%0 = load i64*, i64** @A
%arrayidx = getelementptr inbounds i64, i64* %0, i64 100
%1 = tail call i64 asm "lay $0, $1", "=r,^ZR"(i64* nonnull %arrayidx)
store i64 %1, i64* @Addr
ret i64 %1
}
define i64 @fun_BD12_S() {
; CHECK-LABEL: fun_BD12_S:
; CHECK: #APP
; CHECK: lay %r2, 800(%r1)
entry:
%0 = load i64*, i64** @A
%arrayidx = getelementptr inbounds i64, i64* %0, i64 100
%1 = tail call i64 asm "lay $0, $1", "=r,^ZS"(i64* nonnull %arrayidx)
store i64 %1, i64* @Addr
ret i64 %1
}
define i64 @fun_BD12_T() {
; CHECK-LABEL: fun_BD12_T:
; CHECK: #APP
; CHECK: lay %r2, 800(%r1)
entry:
%0 = load i64*, i64** @A
%arrayidx = getelementptr inbounds i64, i64* %0, i64 100
%1 = tail call i64 asm "lay $0, $1", "=r,^ZT"(i64* nonnull %arrayidx)
store i64 %1, i64* @Addr
ret i64 %1
}
define i64 @fun_BD12_p() {
; CHECK-LABEL: fun_BD12_p:
; CHECK: #APP
@ -16,6 +64,62 @@ entry:
ret i64 %1
}
define i64 @fun_BDX12_Q() {
; CHECK-LABEL: fun_BDX12_Q:
; CHECK: #APP
; CHECK: lay %r2, 800(%r2)
entry:
%0 = load i64*, i64** @A
%1 = load i64, i64* @Idx
%add = add nsw i64 %1, 100
%arrayidx = getelementptr inbounds i64, i64* %0, i64 %add
%2 = tail call i64 asm "lay $0, $1", "=r,^ZQ"(i64* %arrayidx)
store i64 %2, i64* @Addr
ret i64 %2
}
define i64 @fun_BDX12_R() {
; CHECK-LABEL: fun_BDX12_R:
; CHECK: #APP
; CHECK: lay %r2, 800(%r1,%r2)
entry:
%0 = load i64*, i64** @A
%1 = load i64, i64* @Idx
%add = add nsw i64 %1, 100
%arrayidx = getelementptr inbounds i64, i64* %0, i64 %add
%2 = tail call i64 asm "lay $0, $1", "=r,^ZR"(i64* %arrayidx)
store i64 %2, i64* @Addr
ret i64 %2
}
define i64 @fun_BDX12_S() {
; CHECK-LABEL: fun_BDX12_S:
; CHECK: #APP
; CHECK: lay %r2, 800(%r2)
entry:
%0 = load i64*, i64** @A
%1 = load i64, i64* @Idx
%add = add nsw i64 %1, 100
%arrayidx = getelementptr inbounds i64, i64* %0, i64 %add
%2 = tail call i64 asm "lay $0, $1", "=r,^ZS"(i64* %arrayidx)
store i64 %2, i64* @Addr
ret i64 %2
}
define i64 @fun_BDX12_T() {
; CHECK-LABEL: fun_BDX12_T:
; CHECK: #APP
; CHECK: lay %r2, 800(%r1,%r2)
entry:
%0 = load i64*, i64** @A
%1 = load i64, i64* @Idx
%add = add nsw i64 %1, 100
%arrayidx = getelementptr inbounds i64, i64* %0, i64 %add
%2 = tail call i64 asm "lay $0, $1", "=r,^ZT"(i64* %arrayidx)
store i64 %2, i64* @Addr
ret i64 %2
}
define i64 @fun_BDX12_p() {
; CHECK-LABEL: fun_BDX12_p:
; CHECK: #APP
@ -30,6 +134,54 @@ entry:
ret i64 %2
}
define i64 @fun_BD20_Q() {
; CHECK-LABEL: fun_BD20_Q:
; CHECK: #APP
; CHECK: lay %r2, 0(%r2)
entry:
%0 = load i64*, i64** @A
%arrayidx = getelementptr inbounds i64, i64* %0, i64 1000
%1 = tail call i64 asm "lay $0, $1", "=r,^ZQ"(i64* nonnull %arrayidx)
store i64 %1, i64* @Addr
ret i64 %1
}
define i64 @fun_BD20_R() {
; CHECK-LABEL: fun_BD20_R:
; CHECK: #APP
; CHECK: lay %r2, 0(%r2)
entry:
%0 = load i64*, i64** @A
%arrayidx = getelementptr inbounds i64, i64* %0, i64 1000
%1 = tail call i64 asm "lay $0, $1", "=r,^ZR"(i64* nonnull %arrayidx)
store i64 %1, i64* @Addr
ret i64 %1
}
define i64 @fun_BD20_S() {
; CHECK-LABEL: fun_BD20_S:
; CHECK: #APP
; CHECK: lay %r2, 8000(%r1)
entry:
%0 = load i64*, i64** @A
%arrayidx = getelementptr inbounds i64, i64* %0, i64 1000
%1 = tail call i64 asm "lay $0, $1", "=r,^ZS"(i64* nonnull %arrayidx)
store i64 %1, i64* @Addr
ret i64 %1
}
define i64 @fun_BD20_T() {
; CHECK-LABEL: fun_BD20_T:
; CHECK: #APP
; CHECK: lay %r2, 8000(%r1)
entry:
%0 = load i64*, i64** @A
%arrayidx = getelementptr inbounds i64, i64* %0, i64 1000
%1 = tail call i64 asm "lay $0, $1", "=r,^ZT"(i64* nonnull %arrayidx)
store i64 %1, i64* @Addr
ret i64 %1
}
define i64 @fun_BD20_p() {
; CHECK-LABEL: fun_BD20_p:
; CHECK: #APP
@ -42,6 +194,62 @@ entry:
ret i64 %1
}
define i64 @fun_BDX20_Q() {
; CHECK-LABEL: fun_BDX20_Q:
; CHECK: #APP
; CHECK: lay %r2, 0(%r1)
entry:
%0 = load i64*, i64** @A
%1 = load i64, i64* @Idx
%add = add nsw i64 %1, 1000
%arrayidx = getelementptr inbounds i64, i64* %0, i64 %add
%2 = tail call i64 asm "lay $0, $1", "=r,^ZQ"(i64* %arrayidx)
store i64 %2, i64* @Addr
ret i64 %2
}
define i64 @fun_BDX20_R() {
; CHECK-LABEL: fun_BDX20_R:
; CHECK: #APP
; CHECK: lay %r2, 0(%r1)
entry:
%0 = load i64*, i64** @A
%1 = load i64, i64* @Idx
%add = add nsw i64 %1, 1000
%arrayidx = getelementptr inbounds i64, i64* %0, i64 %add
%2 = tail call i64 asm "lay $0, $1", "=r,^ZR"(i64* %arrayidx)
store i64 %2, i64* @Addr
ret i64 %2
}
define i64 @fun_BDX20_S() {
; CHECK-LABEL: fun_BDX20_S:
; CHECK: #APP
; CHECK: lay %r2, 8000(%r2)
entry:
%0 = load i64*, i64** @A
%1 = load i64, i64* @Idx
%add = add nsw i64 %1, 1000
%arrayidx = getelementptr inbounds i64, i64* %0, i64 %add
%2 = tail call i64 asm "lay $0, $1", "=r,^ZS"(i64* %arrayidx)
store i64 %2, i64* @Addr
ret i64 %2
}
define i64 @fun_BDX20_T() {
; CHECK-LABEL: fun_BDX20_T:
; CHECK: #APP
; CHECK: lay %r2, 8000(%r1,%r2)
entry:
%0 = load i64*, i64** @A
%1 = load i64, i64* @Idx
%add = add nsw i64 %1, 1000
%arrayidx = getelementptr inbounds i64, i64* %0, i64 %add
%2 = tail call i64 asm "lay $0, $1", "=r,^ZT"(i64* %arrayidx)
store i64 %2, i64* @Addr
ret i64 %2
}
define i64 @fun_BDX20_p() {
; CHECK-LABEL: fun_BDX20_p:
; CHECK: #APP