diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2017-12-18 20:10:56 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2017-12-18 20:10:56 +0000 |
commit | 044eb2f6afba375a914ac9d8024f8f5142bb912e (patch) | |
tree | 1475247dc9f9fe5be155ebd4c9069c75aadf8c20 /lib/Target/ARM/ARMInstructionSelector.cpp | |
parent | eb70dddbd77e120e5d490bd8fbe7ff3f8fa81c6b (diff) | |
download | src-test2-044eb2f6afba375a914ac9d8024f8f5142bb912e.tar.gz src-test2-044eb2f6afba375a914ac9d8024f8f5142bb912e.zip |
Notes
Diffstat (limited to 'lib/Target/ARM/ARMInstructionSelector.cpp')
-rw-r--r-- | lib/Target/ARM/ARMInstructionSelector.cpp | 190 |
1 files changed, 153 insertions, 37 deletions
diff --git a/lib/Target/ARM/ARMInstructionSelector.cpp b/lib/Target/ARM/ARMInstructionSelector.cpp index faed6b867e2b..6bbeae2e1151 100644 --- a/lib/Target/ARM/ARMInstructionSelector.cpp +++ b/lib/Target/ARM/ARMInstructionSelector.cpp @@ -15,19 +15,15 @@ #include "ARMSubtarget.h" #include "ARMTargetMachine.h" #include "llvm/CodeGen/GlobalISel/InstructionSelector.h" +#include "llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h" +#include "llvm/CodeGen/MachineConstantPool.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/Support/Debug.h" #define DEBUG_TYPE "arm-isel" -#include "llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h" - using namespace llvm; -#ifndef LLVM_BUILD_GLOBAL_ISEL -#error "You shouldn't build this" -#endif - namespace { #define GET_GLOBALISEL_PREDICATE_BITSET @@ -39,10 +35,11 @@ public: ARMInstructionSelector(const ARMBaseTargetMachine &TM, const ARMSubtarget &STI, const ARMRegisterBankInfo &RBI); - bool select(MachineInstr &I) const override; + bool select(MachineInstr &I, CodeGenCoverage &CoverageInfo) const override; + static const char *getName() { return DEBUG_TYPE; } private: - bool selectImpl(MachineInstr &I) const; + bool selectImpl(MachineInstr &I, CodeGenCoverage &CoverageInfo) const; struct CmpConstants; struct InsertInfo; @@ -60,7 +57,9 @@ private: // Set \p DestReg to \p Constant. void putConstant(InsertInfo I, unsigned DestReg, unsigned Constant) const; + bool selectGlobal(MachineInstrBuilder &MIB, MachineRegisterInfo &MRI) const; bool selectSelect(MachineInstrBuilder &MIB, MachineRegisterInfo &MRI) const; + bool selectShift(unsigned ShiftOpc, MachineInstrBuilder &MIB) const; // Check if the types match and both operands have the expected size and // register bank. @@ -98,7 +97,7 @@ createARMInstructionSelector(const ARMBaseTargetMachine &TM, } } -unsigned zero_reg = 0; +const unsigned zero_reg = 0; #define GET_GLOBALISEL_IMPL #include "ARMGenGlobalISel.inc" @@ -488,6 +487,127 @@ bool ARMInstructionSelector::insertComparison(CmpConstants Helper, InsertInfo I, return true; } +bool ARMInstructionSelector::selectGlobal(MachineInstrBuilder &MIB, + MachineRegisterInfo &MRI) const { + if ((STI.isROPI() || STI.isRWPI()) && !STI.isTargetELF()) { + DEBUG(dbgs() << "ROPI and RWPI only supported for ELF\n"); + return false; + } + + auto GV = MIB->getOperand(1).getGlobal(); + if (GV->isThreadLocal()) { + DEBUG(dbgs() << "TLS variables not supported yet\n"); + return false; + } + + auto &MBB = *MIB->getParent(); + auto &MF = *MBB.getParent(); + + bool UseMovt = STI.useMovt(MF); + + unsigned Size = TM.getPointerSize(); + unsigned Alignment = 4; + + auto addOpsForConstantPoolLoad = [&MF, Alignment, + Size](MachineInstrBuilder &MIB, + const GlobalValue *GV, bool IsSBREL) { + assert(MIB->getOpcode() == ARM::LDRi12 && "Unsupported instruction"); + auto ConstPool = MF.getConstantPool(); + auto CPIndex = + // For SB relative entries we need a target-specific constant pool. + // Otherwise, just use a regular constant pool entry. + IsSBREL + ? ConstPool->getConstantPoolIndex( + ARMConstantPoolConstant::Create(GV, ARMCP::SBREL), Alignment) + : ConstPool->getConstantPoolIndex(GV, Alignment); + MIB.addConstantPoolIndex(CPIndex, /*Offset*/ 0, /*TargetFlags*/ 0) + .addMemOperand( + MF.getMachineMemOperand(MachinePointerInfo::getConstantPool(MF), + MachineMemOperand::MOLoad, Size, Alignment)) + .addImm(0) + .add(predOps(ARMCC::AL)); + }; + + if (TM.isPositionIndependent()) { + bool Indirect = STI.isGVIndirectSymbol(GV); + // FIXME: Taking advantage of MOVT for ELF is pretty involved, so we don't + // support it yet. See PR28229. + unsigned Opc = + UseMovt && !STI.isTargetELF() + ? (Indirect ? ARM::MOV_ga_pcrel_ldr : ARM::MOV_ga_pcrel) + : (Indirect ? ARM::LDRLIT_ga_pcrel_ldr : ARM::LDRLIT_ga_pcrel); + MIB->setDesc(TII.get(Opc)); + + int TargetFlags = ARMII::MO_NO_FLAG; + if (STI.isTargetDarwin()) + TargetFlags |= ARMII::MO_NONLAZY; + if (STI.isGVInGOT(GV)) + TargetFlags |= ARMII::MO_GOT; + MIB->getOperand(1).setTargetFlags(TargetFlags); + + if (Indirect) + MIB.addMemOperand(MF.getMachineMemOperand( + MachinePointerInfo::getGOT(MF), MachineMemOperand::MOLoad, + TM.getPointerSize(), Alignment)); + + return constrainSelectedInstRegOperands(*MIB, TII, TRI, RBI); + } + + bool isReadOnly = STI.getTargetLowering()->isReadOnly(GV); + if (STI.isROPI() && isReadOnly) { + unsigned Opc = UseMovt ? ARM::MOV_ga_pcrel : ARM::LDRLIT_ga_pcrel; + MIB->setDesc(TII.get(Opc)); + return constrainSelectedInstRegOperands(*MIB, TII, TRI, RBI); + } + if (STI.isRWPI() && !isReadOnly) { + auto Offset = MRI.createVirtualRegister(&ARM::GPRRegClass); + MachineInstrBuilder OffsetMIB; + if (UseMovt) { + OffsetMIB = BuildMI(MBB, *MIB, MIB->getDebugLoc(), + TII.get(ARM::MOVi32imm), Offset); + OffsetMIB.addGlobalAddress(GV, /*Offset*/ 0, ARMII::MO_SBREL); + } else { + // Load the offset from the constant pool. + OffsetMIB = + BuildMI(MBB, *MIB, MIB->getDebugLoc(), TII.get(ARM::LDRi12), Offset); + addOpsForConstantPoolLoad(OffsetMIB, GV, /*IsSBREL*/ true); + } + if (!constrainSelectedInstRegOperands(*OffsetMIB, TII, TRI, RBI)) + return false; + + // Add the offset to the SB register. + MIB->setDesc(TII.get(ARM::ADDrr)); + MIB->RemoveOperand(1); + MIB.addReg(ARM::R9) // FIXME: don't hardcode R9 + .addReg(Offset) + .add(predOps(ARMCC::AL)) + .add(condCodeOp()); + + return constrainSelectedInstRegOperands(*MIB, TII, TRI, RBI); + } + + if (STI.isTargetELF()) { + if (UseMovt) { + MIB->setDesc(TII.get(ARM::MOVi32imm)); + } else { + // Load the global's address from the constant pool. + MIB->setDesc(TII.get(ARM::LDRi12)); + MIB->RemoveOperand(1); + addOpsForConstantPoolLoad(MIB, GV, /*IsSBREL*/ false); + } + } else if (STI.isTargetMachO()) { + if (UseMovt) + MIB->setDesc(TII.get(ARM::MOVi32imm)); + else + MIB->setDesc(TII.get(ARM::LDRLIT_ga_abs)); + } else { + DEBUG(dbgs() << "Object format not supported yet\n"); + return false; + } + + return constrainSelectedInstRegOperands(*MIB, TII, TRI, RBI); +} + bool ARMInstructionSelector::selectSelect(MachineInstrBuilder &MIB, MachineRegisterInfo &MRI) const { auto &MBB = *MIB->getParent(); @@ -525,7 +645,16 @@ bool ARMInstructionSelector::selectSelect(MachineInstrBuilder &MIB, return true; } -bool ARMInstructionSelector::select(MachineInstr &I) const { +bool ARMInstructionSelector::selectShift(unsigned ShiftOpc, + MachineInstrBuilder &MIB) const { + MIB->setDesc(TII.get(ARM::MOVsr)); + MIB.addImm(ShiftOpc); + MIB.add(predOps(ARMCC::AL)).add(condCodeOp()); + return constrainSelectedInstRegOperands(*MIB, TII, TRI, RBI); +} + +bool ARMInstructionSelector::select(MachineInstr &I, + CodeGenCoverage &CoverageInfo) const { assert(I.getParent() && "Instruction should be in a basic block!"); assert(I.getParent()->getParent() && "Instruction should be in a function!"); @@ -540,7 +669,7 @@ bool ARMInstructionSelector::select(MachineInstr &I) const { return true; } - if (selectImpl(I)) + if (selectImpl(I, CoverageInfo)) return true; MachineInstrBuilder MIB{MF, I}; @@ -633,12 +762,12 @@ bool ARMInstructionSelector::select(MachineInstr &I) const { return selectCmp(Helper, MIB, MRI); } case G_FCMP: { - assert(TII.getSubtarget().hasVFP2() && "Can't select fcmp without VFP"); + assert(STI.hasVFP2() && "Can't select fcmp without VFP"); unsigned OpReg = I.getOperand(2).getReg(); unsigned Size = MRI.getType(OpReg).getSizeInBits(); - if (Size == 64 && TII.getSubtarget().isFPOnlySP()) { + if (Size == 64 && STI.isFPOnlySP()) { DEBUG(dbgs() << "Subtarget only supports single precision"); return false; } @@ -651,6 +780,13 @@ bool ARMInstructionSelector::select(MachineInstr &I) const { ARM::FPRRegBankID, Size); return selectCmp(Helper, MIB, MRI); } + case G_LSHR: + return selectShift(ARM_AM::ShiftOpc::lsr, MIB); + case G_ASHR: + return selectShift(ARM_AM::ShiftOpc::asr, MIB); + case G_SHL: { + return selectShift(ARM_AM::ShiftOpc::lsl, MIB); + } case G_GEP: I.setDesc(TII.get(ARM::ADDrr)); MIB.add(predOps(ARMCC::AL)).add(condCodeOp()); @@ -661,28 +797,8 @@ bool ARMInstructionSelector::select(MachineInstr &I) const { I.setDesc(TII.get(ARM::ADDri)); MIB.addImm(0).add(predOps(ARMCC::AL)).add(condCodeOp()); break; - case G_CONSTANT: { - unsigned Reg = I.getOperand(0).getReg(); - - if (!validReg(MRI, Reg, 32, ARM::GPRRegBankID)) - return false; - - I.setDesc(TII.get(ARM::MOVi)); - MIB.add(predOps(ARMCC::AL)).add(condCodeOp()); - - auto &Val = I.getOperand(1); - if (Val.isCImm()) { - if (Val.getCImm()->getBitWidth() > 32) - return false; - Val.ChangeToImmediate(Val.getCImm()->getZExtValue()); - } - - if (!Val.isImm()) { - return false; - } - - break; - } + case G_GLOBAL_VALUE: + return selectGlobal(MIB, MRI); case G_STORE: case G_LOAD: { const auto &MemOp = **I.memoperands_begin(); @@ -697,7 +813,7 @@ bool ARMInstructionSelector::select(MachineInstr &I) const { LLT ValTy = MRI.getType(Reg); const auto ValSize = ValTy.getSizeInBits(); - assert((ValSize != 64 || TII.getSubtarget().hasVFP2()) && + assert((ValSize != 64 || STI.hasVFP2()) && "Don't know how to load/store 64-bit value without VFP"); const auto NewOpc = selectLoadStoreOpCode(I.getOpcode(), RegBank, ValSize); @@ -739,7 +855,7 @@ bool ARMInstructionSelector::select(MachineInstr &I) const { // Branch conditionally. auto Branch = BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(ARM::Bcc)) .add(I.getOperand(1)) - .add(predOps(ARMCC::EQ, ARM::CPSR)); + .add(predOps(ARMCC::NE, ARM::CPSR)); if (!constrainSelectedInstRegOperands(*Branch, TII, TRI, RBI)) return false; I.eraseFromParent(); |