forked from OSchip/llvm-project
[SystemZ] Enable index register memory constraints for inline ASM
This enables use of the 'R' and 'T' memory constraints for inline ASM operands on SystemZ, which allow an index register as well as an immediate displacement. This patch includes corresponding documentation and test case updates. As with the last patch of this kind, I moved the 'm' constraint to the most general case, which is now 'T' (base + 20-bit signed displacement + index register). Author: colpell Differential Revision: http://reviews.llvm.org/D21239 llvm-svn: 272547
This commit is contained in:
parent
933e1aa39f
commit
daae87aa21
|
@ -3590,10 +3590,14 @@ SystemZ:
|
||||||
- ``K``: An immediate signed 16-bit integer.
|
- ``K``: An immediate signed 16-bit integer.
|
||||||
- ``L``: An immediate signed 20-bit integer.
|
- ``L``: An immediate signed 20-bit integer.
|
||||||
- ``M``: An immediate integer 0x7fffffff.
|
- ``M``: An immediate integer 0x7fffffff.
|
||||||
- ``Q``, ``R``: A memory address operand with a base address and a 12-bit
|
- ``Q``: A memory address operand with a base address and a 12-bit immediate
|
||||||
immediate unsigned displacement.
|
unsigned displacement.
|
||||||
- ``S``, ``T``: A memory address operand with a base address and a 20-bit
|
- ``R``: A memory address operand with a base address, a 12-bit immediate
|
||||||
immediate signed displacement.
|
unsigned displacement, and an index register.
|
||||||
|
- ``S``: A memory address operand with a base address and a 20-bit immediate
|
||||||
|
signed displacement.
|
||||||
|
- ``T``: A memory address operand with a base address, a 20-bit immediate
|
||||||
|
signed displacement, and an index register.
|
||||||
- ``r`` or ``d``: A 32, 64, or 128-bit integer register.
|
- ``r`` or ``d``: A 32, 64, or 128-bit integer register.
|
||||||
- ``a``: A 32, 64, or 128-bit integer address register (excludes R0, which in an
|
- ``a``: A 32, 64, or 128-bit integer address register (excludes R0, which in an
|
||||||
address context evaluates as zero).
|
address context evaluates as zero).
|
||||||
|
|
|
@ -7,12 +7,6 @@ for later architectures at some point.
|
||||||
|
|
||||||
--
|
--
|
||||||
|
|
||||||
SystemZDAGToDAGISel::SelectInlineAsmMemoryOperand() treats the Q and R
|
|
||||||
constraints the same, and the S and T constraints the same, because the optional
|
|
||||||
index is not used.
|
|
||||||
|
|
||||||
--
|
|
||||||
|
|
||||||
If an inline asm ties an i32 "r" result to an i64 input, the input
|
If an inline asm ties an i32 "r" result to an i64 input, the input
|
||||||
will be treated as an i32, leaving the upper bits uninitialised.
|
will be treated as an i32, leaving the upper bits uninitialised.
|
||||||
For example:
|
For example:
|
||||||
|
|
|
@ -1323,6 +1323,8 @@ bool SystemZDAGToDAGISel::
|
||||||
SelectInlineAsmMemoryOperand(const SDValue &Op,
|
SelectInlineAsmMemoryOperand(const SDValue &Op,
|
||||||
unsigned ConstraintID,
|
unsigned ConstraintID,
|
||||||
std::vector<SDValue> &OutOps) {
|
std::vector<SDValue> &OutOps) {
|
||||||
|
SystemZAddressingMode::AddrForm Form;
|
||||||
|
SystemZAddressingMode::DispRange DispRange;
|
||||||
SDValue Base, Disp, Index;
|
SDValue Base, Disp, Index;
|
||||||
|
|
||||||
switch(ConstraintID) {
|
switch(ConstraintID) {
|
||||||
|
@ -1330,33 +1332,35 @@ SelectInlineAsmMemoryOperand(const SDValue &Op,
|
||||||
llvm_unreachable("Unexpected asm memory constraint");
|
llvm_unreachable("Unexpected asm memory constraint");
|
||||||
case InlineAsm::Constraint_i:
|
case InlineAsm::Constraint_i:
|
||||||
case InlineAsm::Constraint_Q:
|
case InlineAsm::Constraint_Q:
|
||||||
|
// Accept an address with a short displacement, but no index.
|
||||||
|
Form = SystemZAddressingMode::FormBD;
|
||||||
|
DispRange = SystemZAddressingMode::Disp12Only;
|
||||||
|
break;
|
||||||
case InlineAsm::Constraint_R:
|
case InlineAsm::Constraint_R:
|
||||||
// Accept addresses with short displacements, which are compatible
|
// Accept an address with a short displacement and an index.
|
||||||
// with Q and R. But keep the index operand for future expansion (e.g. the
|
Form = SystemZAddressingMode::FormBDXNormal;
|
||||||
// index for R).
|
DispRange = SystemZAddressingMode::Disp12Only;
|
||||||
if (selectBDXAddr(SystemZAddressingMode::FormBD,
|
|
||||||
SystemZAddressingMode::Disp12Only,
|
|
||||||
Op, Base, Disp, Index)) {
|
|
||||||
OutOps.push_back(Base);
|
|
||||||
OutOps.push_back(Disp);
|
|
||||||
OutOps.push_back(Index);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case InlineAsm::Constraint_S:
|
case InlineAsm::Constraint_S:
|
||||||
|
// Accept an address with a long displacement, but no index.
|
||||||
|
Form = SystemZAddressingMode::FormBD;
|
||||||
|
DispRange = SystemZAddressingMode::Disp20Only;
|
||||||
|
break;
|
||||||
case InlineAsm::Constraint_T:
|
case InlineAsm::Constraint_T:
|
||||||
case InlineAsm::Constraint_m:
|
case InlineAsm::Constraint_m:
|
||||||
// Accept addresses with long displacements. As above, keep the index for
|
// Accept an address with a long displacement and an index.
|
||||||
// future implementation of index for the T constraint.
|
// m works the same as T, as this is the most general case.
|
||||||
if (selectBDXAddr(SystemZAddressingMode::FormBD,
|
Form = SystemZAddressingMode::FormBDXNormal;
|
||||||
SystemZAddressingMode::Disp20Only,
|
DispRange = SystemZAddressingMode::Disp20Only;
|
||||||
Op, Base, Disp, Index)) {
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectBDXAddr(Form, DispRange, Op, Base, Disp, Index)) {
|
||||||
OutOps.push_back(Base);
|
OutOps.push_back(Base);
|
||||||
OutOps.push_back(Disp);
|
OutOps.push_back(Disp);
|
||||||
OutOps.push_back(Index);
|
OutOps.push_back(Index);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,5 +48,38 @@ define void @f4(i64 %base) {
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
; FIXME: at the moment the precise constraint is not passed down to
|
; Check that indices are allowed
|
||||||
; target code, so we must conservatively treat "R" as "Q".
|
define void @f5(i64 %base, i64 %index) {
|
||||||
|
; CHECK-LABEL: f5:
|
||||||
|
; CHECK: blah 0(%r3,%r2)
|
||||||
|
; CHECK: br %r14
|
||||||
|
%add = add i64 %base, %index
|
||||||
|
%addr = inttoptr i64 %add to i64 *
|
||||||
|
call void asm "blah $0", "=*R" (i64 *%addr)
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
; Check that indices and displacements are allowed simultaneously
|
||||||
|
define void @f6(i64 %base, i64 %index) {
|
||||||
|
; CHECK-LABEL: f6:
|
||||||
|
; CHECK: blah 4095(%r3,%r2)
|
||||||
|
; CHECK: br %r14
|
||||||
|
%add = add i64 %base, 4095
|
||||||
|
%addi = add i64 %add, %index
|
||||||
|
%addr = inttoptr i64 %addi to i64 *
|
||||||
|
call void asm "blah $0", "=*R" (i64 *%addr)
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
; Check that LAY is used if there is an index but the displacement is too large
|
||||||
|
define void @f7(i64 %base, i64 %index) {
|
||||||
|
; CHECK-LABEL: f7:
|
||||||
|
; CHECK: lay %r0, 4096(%r3,%r2)
|
||||||
|
; CHECK: blah 0(%r0)
|
||||||
|
; CHECK: br %r14
|
||||||
|
%add = add i64 %base, 4096
|
||||||
|
%addi = add i64 %add, %index
|
||||||
|
%addr = inttoptr i64 %addi to i64 *
|
||||||
|
call void asm "blah $0", "=*R" (i64 *%addr)
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
|
@ -3,14 +3,71 @@
|
||||||
;
|
;
|
||||||
; RUN: llc < %s -mtriple=s390x-linux-gnu -no-integrated-as | FileCheck %s
|
; RUN: llc < %s -mtriple=s390x-linux-gnu -no-integrated-as | FileCheck %s
|
||||||
|
|
||||||
|
; Check the lowest range.
|
||||||
define void @f1(i64 %base) {
|
define void @f1(i64 %base) {
|
||||||
; CHECK-LABEL: f1:
|
; CHECK-LABEL: f1:
|
||||||
; CHECK: blah 0(%r2)
|
; CHECK: blah -524288(%r2)
|
||||||
; CHECK: br %r14
|
; CHECK: br %r14
|
||||||
%addr = inttoptr i64 %base to i64 *
|
%add = add i64 %base, -524288
|
||||||
|
%addr = inttoptr i64 %add to i64 *
|
||||||
call void asm "blah $0", "=*T" (i64 *%addr)
|
call void asm "blah $0", "=*T" (i64 *%addr)
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
; FIXME: at the moment the precise constraint is not passed down to
|
; Check the next lowest byte.
|
||||||
; target code, so we must conservatively treat "T" as "S".
|
define void @f2(i64 %base) {
|
||||||
|
; CHECK-LABEL: f2:
|
||||||
|
; CHECK: agfi %r2, -524289
|
||||||
|
; CHECK: blah 0(%r2)
|
||||||
|
; CHECK: br %r14
|
||||||
|
%add = add i64 %base, -524289
|
||||||
|
%addr = inttoptr i64 %add to i64 *
|
||||||
|
call void asm "blah $0", "=*T" (i64 *%addr)
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
; Check the highest range.
|
||||||
|
define void @f3(i64 %base) {
|
||||||
|
; CHECK-LABEL: f3:
|
||||||
|
; CHECK: blah 524287(%r2)
|
||||||
|
; CHECK: br %r14
|
||||||
|
%add = add i64 %base, 524287
|
||||||
|
%addr = inttoptr i64 %add to i64 *
|
||||||
|
call void asm "blah $0", "=*T" (i64 *%addr)
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
; Check the next highest byte.
|
||||||
|
define void @f4(i64 %base) {
|
||||||
|
; CHECK-LABEL: f4:
|
||||||
|
; CHECK: agfi %r2, 524288
|
||||||
|
; CHECK: blah 0(%r2)
|
||||||
|
; CHECK: br %r14
|
||||||
|
%add = add i64 %base, 524288
|
||||||
|
%addr = inttoptr i64 %add to i64 *
|
||||||
|
call void asm "blah $0", "=*T" (i64 *%addr)
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
; Check that indices are allowed
|
||||||
|
define void @f5(i64 %base, i64 %index) {
|
||||||
|
; CHECK-LABEL: f5:
|
||||||
|
; CHECK: blah 0(%r3,%r2)
|
||||||
|
; CHECK: br %r14
|
||||||
|
%add = add i64 %base, %index
|
||||||
|
%addr = inttoptr i64 %add to i64 *
|
||||||
|
call void asm "blah $0", "=*T" (i64 *%addr)
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
; Check that indices and displacements are allowed simultaneously
|
||||||
|
define void @f6(i64 %base, i64 %index) {
|
||||||
|
; CHECK-LABEL: f6:
|
||||||
|
; CHECK: blah 524287(%r3,%r2)
|
||||||
|
; CHECK: br %r14
|
||||||
|
%add = add i64 %base, 524287
|
||||||
|
%addi = add i64 %add, %index
|
||||||
|
%addr = inttoptr i64 %addi to i64 *
|
||||||
|
call void asm "blah $0", "=*T" (i64 *%addr)
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
|
@ -10,6 +10,3 @@ define void @f1(i64 %base) {
|
||||||
call void asm "blah $0", "=*m" (i64 *%addr)
|
call void asm "blah $0", "=*m" (i64 *%addr)
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
; FIXME: at the moment the precise constraint is not passed down to
|
|
||||||
; target code, so we must conservatively treat "m" as "S".
|
|
||||||
|
|
Loading…
Reference in New Issue