GlobalISel: support selection of extend operations.

Patch mostly by Ahmed Bougaca.

llvm-svn: 283937
This commit is contained in:
Tim Northover 2016-10-11 20:50:21 +00:00
parent 60cf6fc58f
commit 3d38b3a4d1
2 changed files with 203 additions and 0 deletions

View File

@ -394,6 +394,105 @@ bool AArch64InstructionSelector::select(MachineInstr &I) const {
// operands to use appropriate classes.
return constrainSelectedInstRegOperands(I, TII, TRI, RBI);
}
case TargetOpcode::G_ANYEXT: {
const unsigned DstReg = I.getOperand(0).getReg();
const unsigned SrcReg = I.getOperand(1).getReg();
const RegisterBank &RB = *RBI.getRegBank(DstReg, MRI, TRI);
if (RB.getID() != AArch64::GPRRegBankID) {
DEBUG(dbgs() << "G_ANYEXT on bank: " << RB << ", expected: GPR\n");
return false;
}
const unsigned DstSize = MRI.getType(DstReg).getSizeInBits();
if (DstSize == 0) {
DEBUG(dbgs() << "G_ANYEXT operand has no size, not a gvreg?\n");
return false;
}
const TargetRegisterClass *RC = nullptr;
if (DstSize <= 32) {
RC = &AArch64::GPR32RegClass;
} else if (DstSize == 64) {
RC = &AArch64::GPR64RegClass;
} else {
DEBUG(dbgs() << "G_ANYEXT to size: " << DstSize
<< ", expected: 32 or 64\n");
return false;
}
if (!RBI.constrainGenericRegister(SrcReg, *RC, MRI) ||
!RBI.constrainGenericRegister(DstReg, *RC, MRI)) {
DEBUG(dbgs() << "Failed to constrain G_ANYEXT\n");
return false;
}
BuildMI(MBB, I, I.getDebugLoc(), TII.get(AArch64::COPY))
.addDef(DstReg)
.addUse(SrcReg);
I.eraseFromParent();
return true;
}
case TargetOpcode::G_ZEXT:
case TargetOpcode::G_SEXT: {
unsigned Opcode = I.getOpcode();
const LLT DstTy = MRI.getType(I.getOperand(0).getReg()),
SrcTy = MRI.getType(I.getOperand(1).getReg());
const bool isSigned = Opcode == TargetOpcode::G_SEXT;
const unsigned DefReg = I.getOperand(0).getReg();
const unsigned SrcReg = I.getOperand(1).getReg();
const RegisterBank &RB = *RBI.getRegBank(DefReg, MRI, TRI);
if (RB.getID() != AArch64::GPRRegBankID) {
DEBUG(dbgs() << TII.getName(I.getOpcode()) << " on bank: " << RB
<< ", expected: GPR\n");
return false;
}
MachineInstr *ExtI;
if (DstTy == LLT::scalar(64)) {
// FIXME: Can we avoid manually doing this?
if (!RBI.constrainGenericRegister(SrcReg, AArch64::GPR32RegClass, MRI)) {
DEBUG(dbgs() << "Failed to constrain " << TII.getName(Opcode)
<< " operand\n");
return false;
}
const unsigned SrcXReg =
MRI.createVirtualRegister(&AArch64::GPR64RegClass);
BuildMI(MBB, I, I.getDebugLoc(), TII.get(AArch64::SUBREG_TO_REG))
.addDef(SrcXReg)
.addImm(0)
.addUse(SrcReg)
.addImm(AArch64::sub_32);
const unsigned NewOpc = isSigned ? AArch64::SBFMXri : AArch64::UBFMXri;
ExtI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(NewOpc))
.addDef(DefReg)
.addUse(SrcXReg)
.addImm(0)
.addImm(SrcTy.getSizeInBits() - 1);
} else if (DstTy == LLT::scalar(32)) {
const unsigned NewOpc = isSigned ? AArch64::SBFMWri : AArch64::UBFMWri;
ExtI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(NewOpc))
.addDef(DefReg)
.addUse(SrcReg)
.addImm(0)
.addImm(SrcTy.getSizeInBits() - 1);
} else {
return false;
}
constrainSelectedInstRegOperands(*ExtI, TII, TRI, RBI);
I.eraseFromParent();
return true;
}
}
return false;

View File

@ -82,6 +82,10 @@
@var_got = external global i8
define i8* @global_got() { ret i8* undef }
define void @anyext_gpr() { ret void }
define void @zext_gpr() { ret void }
define void @sext_gpr() { ret void }
...
---
@ -1319,3 +1323,103 @@ body: |
bb.0:
%0(p0) = G_GLOBAL_VALUE @var_got
...
---
# CHECK-LABEL: name: anyext_gpr
name: anyext_gpr
legalized: true
regBankSelected: true
# CHECK: registers:
# CHECK-NEXT: - { id: 0, class: gpr64 }
# CHECK-NEXT: - { id: 1, class: gpr64 }
# CHECK-NEXT: - { id: 2, class: gpr32 }
# CHECK-NEXT: - { id: 3, class: gpr32 }
registers:
- { id: 0, class: gpr }
- { id: 1, class: gpr }
- { id: 2, class: gpr }
- { id: 3, class: gpr }
# CHECK: body:
# CHECK: %0 = COPY %w0
# CHECK: %1 = COPY %0
# CHECK: %2 = COPY %w0
# CHECK: %3 = COPY %2
body: |
bb.0:
liveins: %x0
%0(s32) = COPY %w0
%1(s64) = G_ANYEXT %0
%2(s8) = COPY %w0
%3(s32) = G_ANYEXT %2
...
---
# CHECK-LABEL: name: zext_gpr
name: zext_gpr
legalized: true
regBankSelected: true
# CHECK: registers:
# CHECK-NEXT: - { id: 0, class: gpr32 }
# CHECK-NEXT: - { id: 1, class: gpr64 }
# CHECK-NEXT: - { id: 2, class: gpr32 }
# CHECK-NEXT: - { id: 3, class: gpr32 }
# CHECK-NEXT: - { id: 4, class: gpr64 }
registers:
- { id: 0, class: gpr }
- { id: 1, class: gpr }
- { id: 2, class: gpr }
- { id: 3, class: gpr }
# CHECK: body:
# CHECK: %0 = COPY %w0
# CHECK: %4 = SUBREG_TO_REG 0, %0, 15
# CHECK: %1 = UBFMXri %4, 0, 31
# CHECK: %2 = COPY %w0
# CHECK: %3 = UBFMWri %2, 0, 7
body: |
bb.0:
liveins: %x0
%0(s32) = COPY %w0
%1(s64) = G_ZEXT %0
%2(s8) = COPY %w0
%3(s32) = G_ZEXT %2
...
---
# CHECK-LABEL: name: sext_gpr
name: sext_gpr
legalized: true
regBankSelected: true
# CHECK: registers:
# CHECK-NEXT: - { id: 0, class: gpr32 }
# CHECK-NEXT: - { id: 1, class: gpr64 }
# CHECK-NEXT: - { id: 2, class: gpr32 }
# CHECK-NEXT: - { id: 3, class: gpr32 }
# CHECK-NEXT: - { id: 4, class: gpr64 }
registers:
- { id: 0, class: gpr }
- { id: 1, class: gpr }
- { id: 2, class: gpr }
- { id: 3, class: gpr }
# CHECK: body:
# CHECK: %0 = COPY %w0
# CHECK: %4 = SUBREG_TO_REG 0, %0, 15
# CHECK: %1 = SBFMXri %4, 0, 31
# CHECK: %2 = COPY %w0
# CHECK: %3 = SBFMWri %2, 0, 7
body: |
bb.0:
liveins: %x0
%0(s32) = COPY %w0
%1(s64) = G_SEXT %0
%2(s8) = COPY %w0
%3(s32) = G_SEXT %2
...