diff options
Diffstat (limited to 'llvm/lib/Target/AArch64/AArch64InstructionSelector.cpp')
-rw-r--r-- | llvm/lib/Target/AArch64/AArch64InstructionSelector.cpp | 49 |
1 files changed, 40 insertions, 9 deletions
diff --git a/llvm/lib/Target/AArch64/AArch64InstructionSelector.cpp b/llvm/lib/Target/AArch64/AArch64InstructionSelector.cpp index 3bce4df88da..851211d9a76 100644 --- a/llvm/lib/Target/AArch64/AArch64InstructionSelector.cpp +++ b/llvm/lib/Target/AArch64/AArch64InstructionSelector.cpp @@ -4125,21 +4125,52 @@ AArch64InstructionSelector::selectAddrModeShiftedExtendXReg( if (!Gep || !isWorthFoldingIntoExtendedReg(*Gep, MRI)) return None; - // Now try to match the G_SHL. - MachineInstr *Shl = - getOpcodeDef(TargetOpcode::G_SHL, Gep->getOperand(2).getReg(), MRI); - if (!Shl || !isWorthFoldingIntoExtendedReg(*Shl, MRI)) + // Now, try to match an opcode which will match our specific offset. + // We want a G_SHL or a G_MUL. + MachineInstr *OffsetInst = getDefIgnoringCopies(Gep->getOperand(2).getReg(), MRI); + if (!OffsetInst) return None; - // Now, try to find the specific G_CONSTANT. - auto ValAndVReg = - getConstantVRegValWithLookThrough(Shl->getOperand(2).getReg(), MRI); - if (!ValAndVReg) + unsigned OffsetOpc = OffsetInst->getOpcode(); + if (OffsetOpc != TargetOpcode::G_SHL && OffsetOpc != TargetOpcode::G_MUL) return None; + if (!isWorthFoldingIntoExtendedReg(*OffsetInst, MRI)) + return None; + + // Now, try to find the specific G_CONSTANT. Start by assuming that the + // register we will offset is the LHS, and the register containing the + // constant is the RHS. + Register OffsetReg = OffsetInst->getOperand(1).getReg(); + Register ConstantReg = OffsetInst->getOperand(2).getReg(); + auto ValAndVReg = getConstantVRegValWithLookThrough(ConstantReg, MRI); + if (!ValAndVReg) { + // We didn't get a constant on the RHS. If the opcode is a shift, then + // we're done. + if (OffsetOpc == TargetOpcode::G_SHL) + return None; + + // If we have a G_MUL, we can use either register. Try looking at the RHS. + std::swap(OffsetReg, ConstantReg); + ValAndVReg = getConstantVRegValWithLookThrough(ConstantReg, MRI); + if (!ValAndVReg) + return None; + } + // The value must fit into 3 bits, and must be positive. Make sure that is // true. int64_t ImmVal = ValAndVReg->Value; + + // Since we're going to pull this into a shift, the constant value must be + // a power of 2. If we got a multiply, then we need to check this. + if (OffsetOpc == TargetOpcode::G_MUL) { + if (!isPowerOf2_32(ImmVal)) + return None; + + // Got a power of 2. So, the amount we'll shift is the log base-2 of that. + ImmVal = Log2_32(ImmVal); + } + if ((ImmVal & 0x7) != ImmVal) return None; @@ -4152,7 +4183,7 @@ AArch64InstructionSelector::selectAddrModeShiftedExtendXReg( // offset. Signify that we are shifting by setting the shift flag to 1. return {{ [=](MachineInstrBuilder &MIB) { MIB.add(Gep->getOperand(1)); }, - [=](MachineInstrBuilder &MIB) { MIB.add(Shl->getOperand(1)); }, + [=](MachineInstrBuilder &MIB) { MIB.addUse(OffsetReg); }, [=](MachineInstrBuilder &MIB) { MIB.addImm(0); }, [=](MachineInstrBuilder &MIB) { MIB.addImm(1); }, }}; |