diff options
| author | Jessica Paquette <jpaquette@apple.com> | 2019-08-20 22:18:06 +0000 |
|---|---|---|
| committer | Jessica Paquette <jpaquette@apple.com> | 2019-08-20 22:18:06 +0000 |
| commit | 9a95e79b1b141cf8bb26e77c88b3eb2de35c32bf (patch) | |
| tree | 5ece2e5f44306f1564a2fe655ad1348927a7e360 /llvm/lib/Target | |
| parent | ba375263e868583b709f5b3193d3286648d2f2ab (diff) | |
| download | bcm5719-llvm-9a95e79b1b141cf8bb26e77c88b3eb2de35c32bf.tar.gz bcm5719-llvm-9a95e79b1b141cf8bb26e77c88b3eb2de35c32bf.zip | |
[AArch64][GlobalISel] Select patterns which use shifted register operands
This adds GlobalISel equivalents for the following from AArch64InstrFormats:
- arith_shifted_reg32
- arith_shifted_reg64
And partial support for
- logical_shifted_reg32
- logical_shifted_reg32
The only thing missing for the logical cases is support for rotates. Other than
the missing support, the transformation is identical for the arithmetic shifted
register and the logical shifted register.
Lots of tests here:
- Add select-arith-shifted-reg.mir to show that we correctly select add and
sub instructions which use this pattern.
- Add select-logical-shifted-reg.mir to cover patterns which are not shared
between the arithmetic and logical cases.
- Update addsub-shifted.ll to show that we correctly fold shifts into
adds/subs.
- Update eon.ll to show that we can select the eon instruction by folding xors.
Differential Revision: https://reviews.llvm.org/D66163
llvm-svn: 369460
Diffstat (limited to 'llvm/lib/Target')
| -rw-r--r-- | llvm/lib/Target/AArch64/AArch64InstrFormats.td | 16 | ||||
| -rw-r--r-- | llvm/lib/Target/AArch64/AArch64InstructionSelector.cpp | 73 |
2 files changed, 89 insertions, 0 deletions
diff --git a/llvm/lib/Target/AArch64/AArch64InstrFormats.td b/llvm/lib/Target/AArch64/AArch64InstrFormats.td index 778b4d2cf55..a00c9abd3f9 100644 --- a/llvm/lib/Target/AArch64/AArch64InstrFormats.td +++ b/llvm/lib/Target/AArch64/AArch64InstrFormats.td @@ -782,6 +782,14 @@ class arith_shifted_reg<ValueType Ty, RegisterClass regclass, int width> def arith_shifted_reg32 : arith_shifted_reg<i32, GPR32, 32>; def arith_shifted_reg64 : arith_shifted_reg<i64, GPR64, 64>; +def gi_arith_shifted_reg32 : + GIComplexOperandMatcher<s32, "selectArithShiftedRegister">, + GIComplexPatternEquiv<arith_shifted_reg32>; + +def gi_arith_shifted_reg64 : + GIComplexOperandMatcher<s64, "selectArithShiftedRegister">, + GIComplexPatternEquiv<arith_shifted_reg64>; + // An arithmetic shifter operand: // {7-6} - shift type: 00 = lsl, 01 = lsr, 10 = asr, 11 = ror // {5-0} - imm6 @@ -804,6 +812,14 @@ class logical_shifted_reg<ValueType Ty, RegisterClass regclass, Operand shiftop> def logical_shifted_reg32 : logical_shifted_reg<i32, GPR32, logical_shift32>; def logical_shifted_reg64 : logical_shifted_reg<i64, GPR64, logical_shift64>; +def gi_logical_shifted_reg32 : + GIComplexOperandMatcher<s32, "selectLogicalShiftedRegister">, + GIComplexPatternEquiv<logical_shifted_reg32>; + +def gi_logical_shifted_reg64 : + GIComplexOperandMatcher<s64, "selectLogicalShiftedRegister">, + GIComplexPatternEquiv<logical_shifted_reg64>; + // A logical vector shifter operand: // {7-6} - shift type: 00 = lsl // {5-0} - imm6: #0, #8, #16, or #24 diff --git a/llvm/lib/Target/AArch64/AArch64InstructionSelector.cpp b/llvm/lib/Target/AArch64/AArch64InstructionSelector.cpp index 59db0da1874..99186f08da2 100644 --- a/llvm/lib/Target/AArch64/AArch64InstructionSelector.cpp +++ b/llvm/lib/Target/AArch64/AArch64InstructionSelector.cpp @@ -209,6 +209,20 @@ private: ComplexRendererFns selectAddrModeXRO(MachineOperand &Root, unsigned SizeInBytes) const; + ComplexRendererFns selectShiftedRegister(MachineOperand &Root) const; + + ComplexRendererFns selectArithShiftedRegister(MachineOperand &Root) const { + return selectShiftedRegister(Root); + } + + ComplexRendererFns selectLogicalShiftedRegister(MachineOperand &Root) const { + // TODO: selectShiftedRegister should allow for rotates on logical shifts. + // For now, make them the same. The only difference between the two is that + // logical shifts are allowed to fold in rotates. Otherwise, these are + // functionally the same. + return selectShiftedRegister(Root); + } + void renderTruncImm(MachineInstrBuilder &MIB, const MachineInstr &MI) const; // Materialize a GlobalValue or BlockAddress using a movz+movk sequence. @@ -4492,6 +4506,65 @@ AArch64InstructionSelector::selectAddrModeIndexed(MachineOperand &Root, }}; } +/// Given a shift instruction, return the correct shift type for that +/// instruction. +static AArch64_AM::ShiftExtendType getShiftTypeForInst(MachineInstr &MI) { + // TODO: Handle AArch64_AM::ROR + switch (MI.getOpcode()) { + default: + return AArch64_AM::InvalidShiftExtend; + case TargetOpcode::G_SHL: + return AArch64_AM::LSL; + case TargetOpcode::G_LSHR: + return AArch64_AM::LSR; + case TargetOpcode::G_ASHR: + return AArch64_AM::ASR; + } +} + +/// Select a "shifted register" operand. If the value is not shifted, set the +/// shift operand to a default value of "lsl 0". +/// +/// TODO: Allow shifted register to be rotated in logical instructions. +InstructionSelector::ComplexRendererFns +AArch64InstructionSelector::selectShiftedRegister(MachineOperand &Root) const { + if (!Root.isReg()) + return None; + MachineRegisterInfo &MRI = + Root.getParent()->getParent()->getParent()->getRegInfo(); + + // Check if the operand is defined by an instruction which corresponds to + // a ShiftExtendType. E.g. a G_SHL, G_LSHR, etc. + // + // TODO: Handle AArch64_AM::ROR for logical instructions. + MachineInstr *ShiftInst = MRI.getVRegDef(Root.getReg()); + if (!ShiftInst) + return None; + AArch64_AM::ShiftExtendType ShType = getShiftTypeForInst(*ShiftInst); + if (ShType == AArch64_AM::InvalidShiftExtend) + return None; + if (!isWorthFoldingIntoExtendedReg(*ShiftInst, MRI)) + return None; + + // Need an immediate on the RHS. + MachineOperand &ShiftRHS = ShiftInst->getOperand(2); + auto Immed = getImmedFromMO(ShiftRHS); + if (!Immed) + return None; + + // We have something that we can fold. Fold in the shift's LHS and RHS into + // the instruction. + MachineOperand &ShiftLHS = ShiftInst->getOperand(1); + Register ShiftReg = ShiftLHS.getReg(); + + unsigned NumBits = MRI.getType(ShiftReg).getSizeInBits(); + unsigned Val = *Immed & (NumBits - 1); + unsigned ShiftVal = AArch64_AM::getShifterImm(ShType, Val); + + return {{[=](MachineInstrBuilder &MIB) { MIB.addUse(ShiftReg); }, + [=](MachineInstrBuilder &MIB) { MIB.addImm(ShiftVal); }}}; +} + void AArch64InstructionSelector::renderTruncImm(MachineInstrBuilder &MIB, const MachineInstr &MI) const { const MachineRegisterInfo &MRI = MI.getParent()->getParent()->getRegInfo(); |

