bool ARMInstructionSelector::selectGlobal(MachineInstrBuilder &MIB, MachineRegisterInfo &MRI) const { if ((STI.isROPI() || STI.isRWPI()) && !STI.isTargetELF()) { LLVM_DEBUG(dbgs() << "ROPI and RWPI only supported for ELF\n"); return false; } auto GV = MIB->getOperand(1).getGlobal(); if (GV->isThreadLocal()) { LLVM_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(0); 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.getProgramPointerSize(), 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 { LLVM_DEBUG(dbgs() << "Object format not supported yet\n"); return false; } return constrainSelectedInstRegOperands(*MIB, TII, TRI, RBI); }