Path: blob/main/contrib/llvm-project/llvm/lib/Target/ARM/ARMInstructionSelector.cpp
35266 views
//===- ARMInstructionSelector.cpp ----------------------------*- C++ -*-==//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7/// \file8/// This file implements the targeting of the InstructionSelector class for ARM.9/// \todo This should be generated by TableGen.10//===----------------------------------------------------------------------===//1112#include "ARMRegisterBankInfo.h"13#include "ARMSubtarget.h"14#include "ARMTargetMachine.h"15#include "llvm/CodeGen/GlobalISel/GIMatchTableExecutorImpl.h"16#include "llvm/CodeGen/GlobalISel/InstructionSelector.h"17#include "llvm/CodeGen/MachineConstantPool.h"18#include "llvm/CodeGen/MachineRegisterInfo.h"19#include "llvm/IR/IntrinsicsARM.h"20#include "llvm/Support/Debug.h"2122#define DEBUG_TYPE "arm-isel"2324using namespace llvm;2526namespace {2728#define GET_GLOBALISEL_PREDICATE_BITSET29#include "ARMGenGlobalISel.inc"30#undef GET_GLOBALISEL_PREDICATE_BITSET3132class ARMInstructionSelector : public InstructionSelector {33public:34ARMInstructionSelector(const ARMBaseTargetMachine &TM, const ARMSubtarget &STI,35const ARMRegisterBankInfo &RBI);3637bool select(MachineInstr &I) override;38static const char *getName() { return DEBUG_TYPE; }3940private:41bool selectImpl(MachineInstr &I, CodeGenCoverage &CoverageInfo) const;4243struct CmpConstants;44struct InsertInfo;4546bool selectCmp(CmpConstants Helper, MachineInstrBuilder &MIB,47MachineRegisterInfo &MRI) const;4849// Helper for inserting a comparison sequence that sets \p ResReg to either 150// if \p LHSReg and \p RHSReg are in the relationship defined by \p Cond, or51// \p PrevRes otherwise. In essence, it computes PrevRes OR (LHS Cond RHS).52bool insertComparison(CmpConstants Helper, InsertInfo I, unsigned ResReg,53ARMCC::CondCodes Cond, unsigned LHSReg, unsigned RHSReg,54unsigned PrevRes) const;5556// Set \p DestReg to \p Constant.57void putConstant(InsertInfo I, unsigned DestReg, unsigned Constant) const;5859bool selectGlobal(MachineInstrBuilder &MIB, MachineRegisterInfo &MRI) const;60bool selectSelect(MachineInstrBuilder &MIB, MachineRegisterInfo &MRI) const;61bool selectShift(unsigned ShiftOpc, MachineInstrBuilder &MIB) const;6263// Check if the types match and both operands have the expected size and64// register bank.65bool validOpRegPair(MachineRegisterInfo &MRI, unsigned LHS, unsigned RHS,66unsigned ExpectedSize, unsigned ExpectedRegBankID) const;6768// Check if the register has the expected size and register bank.69bool validReg(MachineRegisterInfo &MRI, unsigned Reg, unsigned ExpectedSize,70unsigned ExpectedRegBankID) const;7172const ARMBaseInstrInfo &TII;73const ARMBaseRegisterInfo &TRI;74const ARMBaseTargetMachine &TM;75const ARMRegisterBankInfo &RBI;76const ARMSubtarget &STI;7778// FIXME: This is necessary because DAGISel uses "Subtarget->" and GlobalISel79// uses "STI." in the code generated by TableGen. If we want to reuse some of80// the custom C++ predicates written for DAGISel, we need to have both around.81const ARMSubtarget *Subtarget = &STI;8283// Store the opcodes that we might need, so we don't have to check what kind84// of subtarget (ARM vs Thumb) we have all the time.85struct OpcodeCache {86unsigned ZEXT16;87unsigned SEXT16;8889unsigned ZEXT8;90unsigned SEXT8;9192// Used for implementing ZEXT/SEXT from i193unsigned AND;94unsigned RSB;9596unsigned STORE32;97unsigned LOAD32;9899unsigned STORE16;100unsigned LOAD16;101102unsigned STORE8;103unsigned LOAD8;104105unsigned ADDrr;106unsigned ADDri;107108// Used for G_ICMP109unsigned CMPrr;110unsigned MOVi;111unsigned MOVCCi;112113// Used for G_SELECT114unsigned MOVCCr;115116unsigned TSTri;117unsigned Bcc;118119// Used for G_GLOBAL_VALUE120unsigned MOVi32imm;121unsigned ConstPoolLoad;122unsigned MOV_ga_pcrel;123unsigned LDRLIT_ga_pcrel;124unsigned LDRLIT_ga_abs;125126OpcodeCache(const ARMSubtarget &STI);127} const Opcodes;128129// Select the opcode for simple extensions (that translate to a single SXT/UXT130// instruction). Extension operations more complicated than that should not131// invoke this. Returns the original opcode if it doesn't know how to select a132// better one.133unsigned selectSimpleExtOpc(unsigned Opc, unsigned Size) const;134135// Select the opcode for simple loads and stores. Returns the original opcode136// if it doesn't know how to select a better one.137unsigned selectLoadStoreOpCode(unsigned Opc, unsigned RegBank,138unsigned Size) const;139140void renderVFPF32Imm(MachineInstrBuilder &New, const MachineInstr &Old,141int OpIdx = -1) const;142void renderVFPF64Imm(MachineInstrBuilder &New, const MachineInstr &Old,143int OpIdx = -1) const;144void renderInvertedImm(MachineInstrBuilder &MIB, const MachineInstr &MI,145int OpIdx = -1) const;146147#define GET_GLOBALISEL_PREDICATES_DECL148#include "ARMGenGlobalISel.inc"149#undef GET_GLOBALISEL_PREDICATES_DECL150151// We declare the temporaries used by selectImpl() in the class to minimize the152// cost of constructing placeholder values.153#define GET_GLOBALISEL_TEMPORARIES_DECL154#include "ARMGenGlobalISel.inc"155#undef GET_GLOBALISEL_TEMPORARIES_DECL156};157} // end anonymous namespace158159namespace llvm {160InstructionSelector *161createARMInstructionSelector(const ARMBaseTargetMachine &TM,162const ARMSubtarget &STI,163const ARMRegisterBankInfo &RBI) {164return new ARMInstructionSelector(TM, STI, RBI);165}166}167168#define GET_GLOBALISEL_IMPL169#include "ARMGenGlobalISel.inc"170#undef GET_GLOBALISEL_IMPL171172ARMInstructionSelector::ARMInstructionSelector(const ARMBaseTargetMachine &TM,173const ARMSubtarget &STI,174const ARMRegisterBankInfo &RBI)175: TII(*STI.getInstrInfo()), TRI(*STI.getRegisterInfo()), TM(TM), RBI(RBI),176STI(STI), Opcodes(STI),177#define GET_GLOBALISEL_PREDICATES_INIT178#include "ARMGenGlobalISel.inc"179#undef GET_GLOBALISEL_PREDICATES_INIT180#define GET_GLOBALISEL_TEMPORARIES_INIT181#include "ARMGenGlobalISel.inc"182#undef GET_GLOBALISEL_TEMPORARIES_INIT183{184}185186static const TargetRegisterClass *guessRegClass(unsigned Reg,187MachineRegisterInfo &MRI,188const TargetRegisterInfo &TRI,189const RegisterBankInfo &RBI) {190const RegisterBank *RegBank = RBI.getRegBank(Reg, MRI, TRI);191assert(RegBank && "Can't get reg bank for virtual register");192193const unsigned Size = MRI.getType(Reg).getSizeInBits();194assert((RegBank->getID() == ARM::GPRRegBankID ||195RegBank->getID() == ARM::FPRRegBankID) &&196"Unsupported reg bank");197198if (RegBank->getID() == ARM::FPRRegBankID) {199if (Size == 32)200return &ARM::SPRRegClass;201else if (Size == 64)202return &ARM::DPRRegClass;203else if (Size == 128)204return &ARM::QPRRegClass;205else206llvm_unreachable("Unsupported destination size");207}208209return &ARM::GPRRegClass;210}211212static bool selectCopy(MachineInstr &I, const TargetInstrInfo &TII,213MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI,214const RegisterBankInfo &RBI) {215Register DstReg = I.getOperand(0).getReg();216if (DstReg.isPhysical())217return true;218219const TargetRegisterClass *RC = guessRegClass(DstReg, MRI, TRI, RBI);220221// No need to constrain SrcReg. It will get constrained when222// we hit another of its uses or its defs.223// Copies do not have constraints.224if (!RBI.constrainGenericRegister(DstReg, *RC, MRI)) {225LLVM_DEBUG(dbgs() << "Failed to constrain " << TII.getName(I.getOpcode())226<< " operand\n");227return false;228}229return true;230}231232static bool selectMergeValues(MachineInstrBuilder &MIB,233const ARMBaseInstrInfo &TII,234MachineRegisterInfo &MRI,235const TargetRegisterInfo &TRI,236const RegisterBankInfo &RBI) {237assert(TII.getSubtarget().hasVFP2Base() && "Can't select merge without VFP");238239// We only support G_MERGE_VALUES as a way to stick together two scalar GPRs240// into one DPR.241Register VReg0 = MIB.getReg(0);242(void)VReg0;243assert(MRI.getType(VReg0).getSizeInBits() == 64 &&244RBI.getRegBank(VReg0, MRI, TRI)->getID() == ARM::FPRRegBankID &&245"Unsupported operand for G_MERGE_VALUES");246Register VReg1 = MIB.getReg(1);247(void)VReg1;248assert(MRI.getType(VReg1).getSizeInBits() == 32 &&249RBI.getRegBank(VReg1, MRI, TRI)->getID() == ARM::GPRRegBankID &&250"Unsupported operand for G_MERGE_VALUES");251Register VReg2 = MIB.getReg(2);252(void)VReg2;253assert(MRI.getType(VReg2).getSizeInBits() == 32 &&254RBI.getRegBank(VReg2, MRI, TRI)->getID() == ARM::GPRRegBankID &&255"Unsupported operand for G_MERGE_VALUES");256257MIB->setDesc(TII.get(ARM::VMOVDRR));258MIB.add(predOps(ARMCC::AL));259260return true;261}262263static bool selectUnmergeValues(MachineInstrBuilder &MIB,264const ARMBaseInstrInfo &TII,265MachineRegisterInfo &MRI,266const TargetRegisterInfo &TRI,267const RegisterBankInfo &RBI) {268assert(TII.getSubtarget().hasVFP2Base() &&269"Can't select unmerge without VFP");270271// We only support G_UNMERGE_VALUES as a way to break up one DPR into two272// GPRs.273Register VReg0 = MIB.getReg(0);274(void)VReg0;275assert(MRI.getType(VReg0).getSizeInBits() == 32 &&276RBI.getRegBank(VReg0, MRI, TRI)->getID() == ARM::GPRRegBankID &&277"Unsupported operand for G_UNMERGE_VALUES");278Register VReg1 = MIB.getReg(1);279(void)VReg1;280assert(MRI.getType(VReg1).getSizeInBits() == 32 &&281RBI.getRegBank(VReg1, MRI, TRI)->getID() == ARM::GPRRegBankID &&282"Unsupported operand for G_UNMERGE_VALUES");283Register VReg2 = MIB.getReg(2);284(void)VReg2;285assert(MRI.getType(VReg2).getSizeInBits() == 64 &&286RBI.getRegBank(VReg2, MRI, TRI)->getID() == ARM::FPRRegBankID &&287"Unsupported operand for G_UNMERGE_VALUES");288289MIB->setDesc(TII.get(ARM::VMOVRRD));290MIB.add(predOps(ARMCC::AL));291292return true;293}294295ARMInstructionSelector::OpcodeCache::OpcodeCache(const ARMSubtarget &STI) {296bool isThumb = STI.isThumb();297298using namespace TargetOpcode;299300#define STORE_OPCODE(VAR, OPC) VAR = isThumb ? ARM::t2##OPC : ARM::OPC301STORE_OPCODE(SEXT16, SXTH);302STORE_OPCODE(ZEXT16, UXTH);303304STORE_OPCODE(SEXT8, SXTB);305STORE_OPCODE(ZEXT8, UXTB);306307STORE_OPCODE(AND, ANDri);308STORE_OPCODE(RSB, RSBri);309310STORE_OPCODE(STORE32, STRi12);311STORE_OPCODE(LOAD32, LDRi12);312313// LDRH/STRH are special...314STORE16 = isThumb ? ARM::t2STRHi12 : ARM::STRH;315LOAD16 = isThumb ? ARM::t2LDRHi12 : ARM::LDRH;316317STORE_OPCODE(STORE8, STRBi12);318STORE_OPCODE(LOAD8, LDRBi12);319320STORE_OPCODE(ADDrr, ADDrr);321STORE_OPCODE(ADDri, ADDri);322323STORE_OPCODE(CMPrr, CMPrr);324STORE_OPCODE(MOVi, MOVi);325STORE_OPCODE(MOVCCi, MOVCCi);326327STORE_OPCODE(MOVCCr, MOVCCr);328329STORE_OPCODE(TSTri, TSTri);330STORE_OPCODE(Bcc, Bcc);331332STORE_OPCODE(MOVi32imm, MOVi32imm);333ConstPoolLoad = isThumb ? ARM::t2LDRpci : ARM::LDRi12;334STORE_OPCODE(MOV_ga_pcrel, MOV_ga_pcrel);335LDRLIT_ga_pcrel = isThumb ? ARM::tLDRLIT_ga_pcrel : ARM::LDRLIT_ga_pcrel;336LDRLIT_ga_abs = isThumb ? ARM::tLDRLIT_ga_abs : ARM::LDRLIT_ga_abs;337#undef MAP_OPCODE338}339340unsigned ARMInstructionSelector::selectSimpleExtOpc(unsigned Opc,341unsigned Size) const {342using namespace TargetOpcode;343344if (Size != 8 && Size != 16)345return Opc;346347if (Opc == G_SEXT)348return Size == 8 ? Opcodes.SEXT8 : Opcodes.SEXT16;349350if (Opc == G_ZEXT)351return Size == 8 ? Opcodes.ZEXT8 : Opcodes.ZEXT16;352353return Opc;354}355356unsigned ARMInstructionSelector::selectLoadStoreOpCode(unsigned Opc,357unsigned RegBank,358unsigned Size) const {359bool isStore = Opc == TargetOpcode::G_STORE;360361if (RegBank == ARM::GPRRegBankID) {362switch (Size) {363case 1:364case 8:365return isStore ? Opcodes.STORE8 : Opcodes.LOAD8;366case 16:367return isStore ? Opcodes.STORE16 : Opcodes.LOAD16;368case 32:369return isStore ? Opcodes.STORE32 : Opcodes.LOAD32;370default:371return Opc;372}373}374375if (RegBank == ARM::FPRRegBankID) {376switch (Size) {377case 32:378return isStore ? ARM::VSTRS : ARM::VLDRS;379case 64:380return isStore ? ARM::VSTRD : ARM::VLDRD;381default:382return Opc;383}384}385386return Opc;387}388389// When lowering comparisons, we sometimes need to perform two compares instead390// of just one. Get the condition codes for both comparisons. If only one is391// needed, the second member of the pair is ARMCC::AL.392static std::pair<ARMCC::CondCodes, ARMCC::CondCodes>393getComparePreds(CmpInst::Predicate Pred) {394std::pair<ARMCC::CondCodes, ARMCC::CondCodes> Preds = {ARMCC::AL, ARMCC::AL};395switch (Pred) {396case CmpInst::FCMP_ONE:397Preds = {ARMCC::GT, ARMCC::MI};398break;399case CmpInst::FCMP_UEQ:400Preds = {ARMCC::EQ, ARMCC::VS};401break;402case CmpInst::ICMP_EQ:403case CmpInst::FCMP_OEQ:404Preds.first = ARMCC::EQ;405break;406case CmpInst::ICMP_SGT:407case CmpInst::FCMP_OGT:408Preds.first = ARMCC::GT;409break;410case CmpInst::ICMP_SGE:411case CmpInst::FCMP_OGE:412Preds.first = ARMCC::GE;413break;414case CmpInst::ICMP_UGT:415case CmpInst::FCMP_UGT:416Preds.first = ARMCC::HI;417break;418case CmpInst::FCMP_OLT:419Preds.first = ARMCC::MI;420break;421case CmpInst::ICMP_ULE:422case CmpInst::FCMP_OLE:423Preds.first = ARMCC::LS;424break;425case CmpInst::FCMP_ORD:426Preds.first = ARMCC::VC;427break;428case CmpInst::FCMP_UNO:429Preds.first = ARMCC::VS;430break;431case CmpInst::FCMP_UGE:432Preds.first = ARMCC::PL;433break;434case CmpInst::ICMP_SLT:435case CmpInst::FCMP_ULT:436Preds.first = ARMCC::LT;437break;438case CmpInst::ICMP_SLE:439case CmpInst::FCMP_ULE:440Preds.first = ARMCC::LE;441break;442case CmpInst::FCMP_UNE:443case CmpInst::ICMP_NE:444Preds.first = ARMCC::NE;445break;446case CmpInst::ICMP_UGE:447Preds.first = ARMCC::HS;448break;449case CmpInst::ICMP_ULT:450Preds.first = ARMCC::LO;451break;452default:453break;454}455assert(Preds.first != ARMCC::AL && "No comparisons needed?");456return Preds;457}458459struct ARMInstructionSelector::CmpConstants {460CmpConstants(unsigned CmpOpcode, unsigned FlagsOpcode, unsigned SelectOpcode,461unsigned OpRegBank, unsigned OpSize)462: ComparisonOpcode(CmpOpcode), ReadFlagsOpcode(FlagsOpcode),463SelectResultOpcode(SelectOpcode), OperandRegBankID(OpRegBank),464OperandSize(OpSize) {}465466// The opcode used for performing the comparison.467const unsigned ComparisonOpcode;468469// The opcode used for reading the flags set by the comparison. May be470// ARM::INSTRUCTION_LIST_END if we don't need to read the flags.471const unsigned ReadFlagsOpcode;472473// The opcode used for materializing the result of the comparison.474const unsigned SelectResultOpcode;475476// The assumed register bank ID for the operands.477const unsigned OperandRegBankID;478479// The assumed size in bits for the operands.480const unsigned OperandSize;481};482483struct ARMInstructionSelector::InsertInfo {484InsertInfo(MachineInstrBuilder &MIB)485: MBB(*MIB->getParent()), InsertBefore(std::next(MIB->getIterator())),486DbgLoc(MIB->getDebugLoc()) {}487488MachineBasicBlock &MBB;489const MachineBasicBlock::instr_iterator InsertBefore;490const DebugLoc &DbgLoc;491};492493void ARMInstructionSelector::putConstant(InsertInfo I, unsigned DestReg,494unsigned Constant) const {495(void)BuildMI(I.MBB, I.InsertBefore, I.DbgLoc, TII.get(Opcodes.MOVi))496.addDef(DestReg)497.addImm(Constant)498.add(predOps(ARMCC::AL))499.add(condCodeOp());500}501502bool ARMInstructionSelector::validOpRegPair(MachineRegisterInfo &MRI,503unsigned LHSReg, unsigned RHSReg,504unsigned ExpectedSize,505unsigned ExpectedRegBankID) const {506return MRI.getType(LHSReg) == MRI.getType(RHSReg) &&507validReg(MRI, LHSReg, ExpectedSize, ExpectedRegBankID) &&508validReg(MRI, RHSReg, ExpectedSize, ExpectedRegBankID);509}510511bool ARMInstructionSelector::validReg(MachineRegisterInfo &MRI, unsigned Reg,512unsigned ExpectedSize,513unsigned ExpectedRegBankID) const {514if (MRI.getType(Reg).getSizeInBits() != ExpectedSize) {515LLVM_DEBUG(dbgs() << "Unexpected size for register");516return false;517}518519if (RBI.getRegBank(Reg, MRI, TRI)->getID() != ExpectedRegBankID) {520LLVM_DEBUG(dbgs() << "Unexpected register bank for register");521return false;522}523524return true;525}526527bool ARMInstructionSelector::selectCmp(CmpConstants Helper,528MachineInstrBuilder &MIB,529MachineRegisterInfo &MRI) const {530const InsertInfo I(MIB);531532auto ResReg = MIB.getReg(0);533if (!validReg(MRI, ResReg, 1, ARM::GPRRegBankID))534return false;535536auto Cond =537static_cast<CmpInst::Predicate>(MIB->getOperand(1).getPredicate());538if (Cond == CmpInst::FCMP_TRUE || Cond == CmpInst::FCMP_FALSE) {539putConstant(I, ResReg, Cond == CmpInst::FCMP_TRUE ? 1 : 0);540MIB->eraseFromParent();541return true;542}543544auto LHSReg = MIB.getReg(2);545auto RHSReg = MIB.getReg(3);546if (!validOpRegPair(MRI, LHSReg, RHSReg, Helper.OperandSize,547Helper.OperandRegBankID))548return false;549550auto ARMConds = getComparePreds(Cond);551auto ZeroReg = MRI.createVirtualRegister(&ARM::GPRRegClass);552putConstant(I, ZeroReg, 0);553554if (ARMConds.second == ARMCC::AL) {555// Simple case, we only need one comparison and we're done.556if (!insertComparison(Helper, I, ResReg, ARMConds.first, LHSReg, RHSReg,557ZeroReg))558return false;559} else {560// Not so simple, we need two successive comparisons.561auto IntermediateRes = MRI.createVirtualRegister(&ARM::GPRRegClass);562if (!insertComparison(Helper, I, IntermediateRes, ARMConds.first, LHSReg,563RHSReg, ZeroReg))564return false;565if (!insertComparison(Helper, I, ResReg, ARMConds.second, LHSReg, RHSReg,566IntermediateRes))567return false;568}569570MIB->eraseFromParent();571return true;572}573574bool ARMInstructionSelector::insertComparison(CmpConstants Helper, InsertInfo I,575unsigned ResReg,576ARMCC::CondCodes Cond,577unsigned LHSReg, unsigned RHSReg,578unsigned PrevRes) const {579// Perform the comparison.580auto CmpI =581BuildMI(I.MBB, I.InsertBefore, I.DbgLoc, TII.get(Helper.ComparisonOpcode))582.addUse(LHSReg)583.addUse(RHSReg)584.add(predOps(ARMCC::AL));585if (!constrainSelectedInstRegOperands(*CmpI, TII, TRI, RBI))586return false;587588// Read the comparison flags (if necessary).589if (Helper.ReadFlagsOpcode != ARM::INSTRUCTION_LIST_END) {590auto ReadI = BuildMI(I.MBB, I.InsertBefore, I.DbgLoc,591TII.get(Helper.ReadFlagsOpcode))592.add(predOps(ARMCC::AL));593if (!constrainSelectedInstRegOperands(*ReadI, TII, TRI, RBI))594return false;595}596597// Select either 1 or the previous result based on the value of the flags.598auto Mov1I = BuildMI(I.MBB, I.InsertBefore, I.DbgLoc,599TII.get(Helper.SelectResultOpcode))600.addDef(ResReg)601.addUse(PrevRes)602.addImm(1)603.add(predOps(Cond, ARM::CPSR));604if (!constrainSelectedInstRegOperands(*Mov1I, TII, TRI, RBI))605return false;606607return true;608}609610bool ARMInstructionSelector::selectGlobal(MachineInstrBuilder &MIB,611MachineRegisterInfo &MRI) const {612if ((STI.isROPI() || STI.isRWPI()) && !STI.isTargetELF()) {613LLVM_DEBUG(dbgs() << "ROPI and RWPI only supported for ELF\n");614return false;615}616617auto GV = MIB->getOperand(1).getGlobal();618if (GV->isThreadLocal()) {619LLVM_DEBUG(dbgs() << "TLS variables not supported yet\n");620return false;621}622623auto &MBB = *MIB->getParent();624auto &MF = *MBB.getParent();625626bool UseMovt = STI.useMovt();627628LLT PtrTy = MRI.getType(MIB->getOperand(0).getReg());629const Align Alignment(4);630631auto addOpsForConstantPoolLoad = [&MF, Alignment, PtrTy](632MachineInstrBuilder &MIB,633const GlobalValue *GV, bool IsSBREL) {634assert((MIB->getOpcode() == ARM::LDRi12 ||635MIB->getOpcode() == ARM::t2LDRpci) &&636"Unsupported instruction");637auto ConstPool = MF.getConstantPool();638auto CPIndex =639// For SB relative entries we need a target-specific constant pool.640// Otherwise, just use a regular constant pool entry.641IsSBREL642? ConstPool->getConstantPoolIndex(643ARMConstantPoolConstant::Create(GV, ARMCP::SBREL), Alignment)644: ConstPool->getConstantPoolIndex(GV, Alignment);645MIB.addConstantPoolIndex(CPIndex, /*Offset*/ 0, /*TargetFlags*/ 0)646.addMemOperand(MF.getMachineMemOperand(647MachinePointerInfo::getConstantPool(MF), MachineMemOperand::MOLoad,648PtrTy, Alignment));649if (MIB->getOpcode() == ARM::LDRi12)650MIB.addImm(0);651MIB.add(predOps(ARMCC::AL));652};653654auto addGOTMemOperand = [this, &MF, Alignment](MachineInstrBuilder &MIB) {655MIB.addMemOperand(MF.getMachineMemOperand(656MachinePointerInfo::getGOT(MF), MachineMemOperand::MOLoad,657TM.getProgramPointerSize(), Alignment));658};659660if (TM.isPositionIndependent()) {661bool Indirect = STI.isGVIndirectSymbol(GV);662663// For ARM mode, we have different pseudoinstructions for direct accesses664// and indirect accesses, and the ones for indirect accesses include the665// load from GOT. For Thumb mode, we use the same pseudoinstruction for both666// direct and indirect accesses, and we need to manually generate the load667// from GOT.668bool UseOpcodeThatLoads = Indirect && !STI.isThumb();669670// FIXME: Taking advantage of MOVT for ELF is pretty involved, so we don't671// support it yet. See PR28229.672unsigned Opc =673UseMovt && !STI.isTargetELF()674? (UseOpcodeThatLoads ? (unsigned)ARM::MOV_ga_pcrel_ldr675: Opcodes.MOV_ga_pcrel)676: (UseOpcodeThatLoads ? (unsigned)ARM::LDRLIT_ga_pcrel_ldr677: Opcodes.LDRLIT_ga_pcrel);678MIB->setDesc(TII.get(Opc));679680int TargetFlags = ARMII::MO_NO_FLAG;681if (STI.isTargetDarwin())682TargetFlags |= ARMII::MO_NONLAZY;683if (STI.isGVInGOT(GV))684TargetFlags |= ARMII::MO_GOT;685MIB->getOperand(1).setTargetFlags(TargetFlags);686687if (Indirect) {688if (!UseOpcodeThatLoads) {689auto ResultReg = MIB.getReg(0);690auto AddressReg = MRI.createVirtualRegister(&ARM::GPRRegClass);691692MIB->getOperand(0).setReg(AddressReg);693694auto InsertBefore = std::next(MIB->getIterator());695auto MIBLoad = BuildMI(MBB, InsertBefore, MIB->getDebugLoc(),696TII.get(Opcodes.LOAD32))697.addDef(ResultReg)698.addReg(AddressReg)699.addImm(0)700.add(predOps(ARMCC::AL));701addGOTMemOperand(MIBLoad);702703if (!constrainSelectedInstRegOperands(*MIBLoad, TII, TRI, RBI))704return false;705} else {706addGOTMemOperand(MIB);707}708}709710return constrainSelectedInstRegOperands(*MIB, TII, TRI, RBI);711}712713bool isReadOnly = STI.getTargetLowering()->isReadOnly(GV);714if (STI.isROPI() && isReadOnly) {715unsigned Opc = UseMovt ? Opcodes.MOV_ga_pcrel : Opcodes.LDRLIT_ga_pcrel;716MIB->setDesc(TII.get(Opc));717return constrainSelectedInstRegOperands(*MIB, TII, TRI, RBI);718}719if (STI.isRWPI() && !isReadOnly) {720auto Offset = MRI.createVirtualRegister(&ARM::GPRRegClass);721MachineInstrBuilder OffsetMIB;722if (UseMovt) {723OffsetMIB = BuildMI(MBB, *MIB, MIB->getDebugLoc(),724TII.get(Opcodes.MOVi32imm), Offset);725OffsetMIB.addGlobalAddress(GV, /*Offset*/ 0, ARMII::MO_SBREL);726} else {727// Load the offset from the constant pool.728OffsetMIB = BuildMI(MBB, *MIB, MIB->getDebugLoc(),729TII.get(Opcodes.ConstPoolLoad), Offset);730addOpsForConstantPoolLoad(OffsetMIB, GV, /*IsSBREL*/ true);731}732if (!constrainSelectedInstRegOperands(*OffsetMIB, TII, TRI, RBI))733return false;734735// Add the offset to the SB register.736MIB->setDesc(TII.get(Opcodes.ADDrr));737MIB->removeOperand(1);738MIB.addReg(ARM::R9) // FIXME: don't hardcode R9739.addReg(Offset)740.add(predOps(ARMCC::AL))741.add(condCodeOp());742743return constrainSelectedInstRegOperands(*MIB, TII, TRI, RBI);744}745746if (STI.isTargetELF()) {747if (UseMovt) {748MIB->setDesc(TII.get(Opcodes.MOVi32imm));749} else {750// Load the global's address from the constant pool.751MIB->setDesc(TII.get(Opcodes.ConstPoolLoad));752MIB->removeOperand(1);753addOpsForConstantPoolLoad(MIB, GV, /*IsSBREL*/ false);754}755} else if (STI.isTargetMachO()) {756if (UseMovt)757MIB->setDesc(TII.get(Opcodes.MOVi32imm));758else759MIB->setDesc(TII.get(Opcodes.LDRLIT_ga_abs));760} else {761LLVM_DEBUG(dbgs() << "Object format not supported yet\n");762return false;763}764765return constrainSelectedInstRegOperands(*MIB, TII, TRI, RBI);766}767768bool ARMInstructionSelector::selectSelect(MachineInstrBuilder &MIB,769MachineRegisterInfo &MRI) const {770auto &MBB = *MIB->getParent();771auto InsertBefore = std::next(MIB->getIterator());772auto &DbgLoc = MIB->getDebugLoc();773774// Compare the condition to 1.775auto CondReg = MIB.getReg(1);776assert(validReg(MRI, CondReg, 1, ARM::GPRRegBankID) &&777"Unsupported types for select operation");778auto CmpI = BuildMI(MBB, InsertBefore, DbgLoc, TII.get(Opcodes.TSTri))779.addUse(CondReg)780.addImm(1)781.add(predOps(ARMCC::AL));782if (!constrainSelectedInstRegOperands(*CmpI, TII, TRI, RBI))783return false;784785// Move a value into the result register based on the result of the786// comparison.787auto ResReg = MIB.getReg(0);788auto TrueReg = MIB.getReg(2);789auto FalseReg = MIB.getReg(3);790assert(validOpRegPair(MRI, ResReg, TrueReg, 32, ARM::GPRRegBankID) &&791validOpRegPair(MRI, TrueReg, FalseReg, 32, ARM::GPRRegBankID) &&792"Unsupported types for select operation");793auto Mov1I = BuildMI(MBB, InsertBefore, DbgLoc, TII.get(Opcodes.MOVCCr))794.addDef(ResReg)795.addUse(TrueReg)796.addUse(FalseReg)797.add(predOps(ARMCC::EQ, ARM::CPSR));798if (!constrainSelectedInstRegOperands(*Mov1I, TII, TRI, RBI))799return false;800801MIB->eraseFromParent();802return true;803}804805bool ARMInstructionSelector::selectShift(unsigned ShiftOpc,806MachineInstrBuilder &MIB) const {807assert(!STI.isThumb() && "Unsupported subtarget");808MIB->setDesc(TII.get(ARM::MOVsr));809MIB.addImm(ShiftOpc);810MIB.add(predOps(ARMCC::AL)).add(condCodeOp());811return constrainSelectedInstRegOperands(*MIB, TII, TRI, RBI);812}813814void ARMInstructionSelector::renderVFPF32Imm(815MachineInstrBuilder &NewInstBuilder, const MachineInstr &OldInst,816int OpIdx) const {817assert(OldInst.getOpcode() == TargetOpcode::G_FCONSTANT &&818OpIdx == -1 && "Expected G_FCONSTANT");819820APFloat FPImmValue = OldInst.getOperand(1).getFPImm()->getValueAPF();821int FPImmEncoding = ARM_AM::getFP32Imm(FPImmValue);822assert(FPImmEncoding != -1 && "Invalid immediate value");823824NewInstBuilder.addImm(FPImmEncoding);825}826827void ARMInstructionSelector::renderVFPF64Imm(828MachineInstrBuilder &NewInstBuilder, const MachineInstr &OldInst, int OpIdx) const {829assert(OldInst.getOpcode() == TargetOpcode::G_FCONSTANT &&830OpIdx == -1 && "Expected G_FCONSTANT");831832APFloat FPImmValue = OldInst.getOperand(1).getFPImm()->getValueAPF();833int FPImmEncoding = ARM_AM::getFP64Imm(FPImmValue);834assert(FPImmEncoding != -1 && "Invalid immediate value");835836NewInstBuilder.addImm(FPImmEncoding);837}838839void ARMInstructionSelector::renderInvertedImm(MachineInstrBuilder &MIB,840const MachineInstr &MI,841int OpIdx) const {842assert(MI.getOpcode() == TargetOpcode::G_CONSTANT && OpIdx == -1 &&843"Expected G_CONSTANT");844int64_t CVal = MI.getOperand(1).getCImm()->getSExtValue();845MIB.addImm(~CVal);846}847848bool ARMInstructionSelector::select(MachineInstr &I) {849assert(I.getParent() && "Instruction should be in a basic block!");850assert(I.getParent()->getParent() && "Instruction should be in a function!");851852auto &MBB = *I.getParent();853auto &MF = *MBB.getParent();854auto &MRI = MF.getRegInfo();855856if (!isPreISelGenericOpcode(I.getOpcode())) {857if (I.isCopy())858return selectCopy(I, TII, MRI, TRI, RBI);859860return true;861}862863using namespace TargetOpcode;864865if (selectImpl(I, *CoverageInfo))866return true;867868MachineInstrBuilder MIB{MF, I};869bool isSExt = false;870871switch (I.getOpcode()) {872case G_SEXT:873isSExt = true;874[[fallthrough]];875case G_ZEXT: {876assert(MRI.getType(I.getOperand(0).getReg()).getSizeInBits() <= 32 &&877"Unsupported destination size for extension");878879LLT SrcTy = MRI.getType(I.getOperand(1).getReg());880unsigned SrcSize = SrcTy.getSizeInBits();881switch (SrcSize) {882case 1: {883// ZExt boils down to & 0x1; for SExt we also subtract that from 0884I.setDesc(TII.get(Opcodes.AND));885MIB.addImm(1).add(predOps(ARMCC::AL)).add(condCodeOp());886887if (isSExt) {888Register SExtResult = I.getOperand(0).getReg();889890// Use a new virtual register for the result of the AND891Register AndResult = MRI.createVirtualRegister(&ARM::GPRRegClass);892I.getOperand(0).setReg(AndResult);893894auto InsertBefore = std::next(I.getIterator());895auto SubI =896BuildMI(MBB, InsertBefore, I.getDebugLoc(), TII.get(Opcodes.RSB))897.addDef(SExtResult)898.addUse(AndResult)899.addImm(0)900.add(predOps(ARMCC::AL))901.add(condCodeOp());902if (!constrainSelectedInstRegOperands(*SubI, TII, TRI, RBI))903return false;904}905break;906}907case 8:908case 16: {909unsigned NewOpc = selectSimpleExtOpc(I.getOpcode(), SrcSize);910if (NewOpc == I.getOpcode())911return false;912I.setDesc(TII.get(NewOpc));913MIB.addImm(0).add(predOps(ARMCC::AL));914break;915}916default:917LLVM_DEBUG(dbgs() << "Unsupported source size for extension");918return false;919}920break;921}922case G_ANYEXT:923case G_TRUNC: {924// The high bits are undefined, so there's nothing special to do, just925// treat it as a copy.926auto SrcReg = I.getOperand(1).getReg();927auto DstReg = I.getOperand(0).getReg();928929const auto &SrcRegBank = *RBI.getRegBank(SrcReg, MRI, TRI);930const auto &DstRegBank = *RBI.getRegBank(DstReg, MRI, TRI);931932if (SrcRegBank.getID() == ARM::FPRRegBankID) {933// This should only happen in the obscure case where we have put a 64-bit934// integer into a D register. Get it out of there and keep only the935// interesting part.936assert(I.getOpcode() == G_TRUNC && "Unsupported operand for G_ANYEXT");937assert(DstRegBank.getID() == ARM::GPRRegBankID &&938"Unsupported combination of register banks");939assert(MRI.getType(SrcReg).getSizeInBits() == 64 && "Unsupported size");940assert(MRI.getType(DstReg).getSizeInBits() <= 32 && "Unsupported size");941942Register IgnoredBits = MRI.createVirtualRegister(&ARM::GPRRegClass);943auto InsertBefore = std::next(I.getIterator());944auto MovI =945BuildMI(MBB, InsertBefore, I.getDebugLoc(), TII.get(ARM::VMOVRRD))946.addDef(DstReg)947.addDef(IgnoredBits)948.addUse(SrcReg)949.add(predOps(ARMCC::AL));950if (!constrainSelectedInstRegOperands(*MovI, TII, TRI, RBI))951return false;952953MIB->eraseFromParent();954return true;955}956957if (SrcRegBank.getID() != DstRegBank.getID()) {958LLVM_DEBUG(959dbgs() << "G_TRUNC/G_ANYEXT operands on different register banks\n");960return false;961}962963if (SrcRegBank.getID() != ARM::GPRRegBankID) {964LLVM_DEBUG(dbgs() << "G_TRUNC/G_ANYEXT on non-GPR not supported yet\n");965return false;966}967968I.setDesc(TII.get(COPY));969return selectCopy(I, TII, MRI, TRI, RBI);970}971case G_CONSTANT: {972if (!MRI.getType(I.getOperand(0).getReg()).isPointer()) {973// Non-pointer constants should be handled by TableGen.974LLVM_DEBUG(dbgs() << "Unsupported constant type\n");975return false;976}977978auto &Val = I.getOperand(1);979if (Val.isCImm()) {980if (!Val.getCImm()->isZero()) {981LLVM_DEBUG(dbgs() << "Unsupported pointer constant value\n");982return false;983}984Val.ChangeToImmediate(0);985} else {986assert(Val.isImm() && "Unexpected operand for G_CONSTANT");987if (Val.getImm() != 0) {988LLVM_DEBUG(dbgs() << "Unsupported pointer constant value\n");989return false;990}991}992993assert(!STI.isThumb() && "Unsupported subtarget");994I.setDesc(TII.get(ARM::MOVi));995MIB.add(predOps(ARMCC::AL)).add(condCodeOp());996break;997}998case G_FCONSTANT: {999// Load from constant pool1000unsigned Size = MRI.getType(I.getOperand(0).getReg()).getSizeInBits() / 8;1001Align Alignment(Size);10021003assert((Size == 4 || Size == 8) && "Unsupported FP constant type");1004auto LoadOpcode = Size == 4 ? ARM::VLDRS : ARM::VLDRD;10051006auto ConstPool = MF.getConstantPool();1007auto CPIndex =1008ConstPool->getConstantPoolIndex(I.getOperand(1).getFPImm(), Alignment);1009MIB->setDesc(TII.get(LoadOpcode));1010MIB->removeOperand(1);1011MIB.addConstantPoolIndex(CPIndex, /*Offset*/ 0, /*TargetFlags*/ 0)1012.addMemOperand(1013MF.getMachineMemOperand(MachinePointerInfo::getConstantPool(MF),1014MachineMemOperand::MOLoad, Size, Alignment))1015.addImm(0)1016.add(predOps(ARMCC::AL));1017break;1018}1019case G_INTTOPTR:1020case G_PTRTOINT: {1021auto SrcReg = I.getOperand(1).getReg();1022auto DstReg = I.getOperand(0).getReg();10231024const auto &SrcRegBank = *RBI.getRegBank(SrcReg, MRI, TRI);1025const auto &DstRegBank = *RBI.getRegBank(DstReg, MRI, TRI);10261027if (SrcRegBank.getID() != DstRegBank.getID()) {1028LLVM_DEBUG(1029dbgs()1030<< "G_INTTOPTR/G_PTRTOINT operands on different register banks\n");1031return false;1032}10331034if (SrcRegBank.getID() != ARM::GPRRegBankID) {1035LLVM_DEBUG(1036dbgs() << "G_INTTOPTR/G_PTRTOINT on non-GPR not supported yet\n");1037return false;1038}10391040I.setDesc(TII.get(COPY));1041return selectCopy(I, TII, MRI, TRI, RBI);1042}1043case G_SELECT:1044return selectSelect(MIB, MRI);1045case G_ICMP: {1046CmpConstants Helper(Opcodes.CMPrr, ARM::INSTRUCTION_LIST_END,1047Opcodes.MOVCCi, ARM::GPRRegBankID, 32);1048return selectCmp(Helper, MIB, MRI);1049}1050case G_FCMP: {1051assert(STI.hasVFP2Base() && "Can't select fcmp without VFP");10521053Register OpReg = I.getOperand(2).getReg();1054unsigned Size = MRI.getType(OpReg).getSizeInBits();10551056if (Size == 64 && !STI.hasFP64()) {1057LLVM_DEBUG(dbgs() << "Subtarget only supports single precision");1058return false;1059}1060if (Size != 32 && Size != 64) {1061LLVM_DEBUG(dbgs() << "Unsupported size for G_FCMP operand");1062return false;1063}10641065CmpConstants Helper(Size == 32 ? ARM::VCMPS : ARM::VCMPD, ARM::FMSTAT,1066Opcodes.MOVCCi, ARM::FPRRegBankID, Size);1067return selectCmp(Helper, MIB, MRI);1068}1069case G_LSHR:1070return selectShift(ARM_AM::ShiftOpc::lsr, MIB);1071case G_ASHR:1072return selectShift(ARM_AM::ShiftOpc::asr, MIB);1073case G_SHL: {1074return selectShift(ARM_AM::ShiftOpc::lsl, MIB);1075}1076case G_PTR_ADD:1077I.setDesc(TII.get(Opcodes.ADDrr));1078MIB.add(predOps(ARMCC::AL)).add(condCodeOp());1079break;1080case G_FRAME_INDEX:1081// Add 0 to the given frame index and hope it will eventually be folded into1082// the user(s).1083I.setDesc(TII.get(Opcodes.ADDri));1084MIB.addImm(0).add(predOps(ARMCC::AL)).add(condCodeOp());1085break;1086case G_GLOBAL_VALUE:1087return selectGlobal(MIB, MRI);1088case G_STORE:1089case G_LOAD: {1090const auto &MemOp = **I.memoperands_begin();1091if (MemOp.isAtomic()) {1092LLVM_DEBUG(dbgs() << "Atomic load/store not supported yet\n");1093return false;1094}10951096Register Reg = I.getOperand(0).getReg();1097unsigned RegBank = RBI.getRegBank(Reg, MRI, TRI)->getID();10981099LLT ValTy = MRI.getType(Reg);1100const auto ValSize = ValTy.getSizeInBits();11011102assert((ValSize != 64 || STI.hasVFP2Base()) &&1103"Don't know how to load/store 64-bit value without VFP");11041105const auto NewOpc = selectLoadStoreOpCode(I.getOpcode(), RegBank, ValSize);1106if (NewOpc == G_LOAD || NewOpc == G_STORE)1107return false;11081109I.setDesc(TII.get(NewOpc));11101111if (NewOpc == ARM::LDRH || NewOpc == ARM::STRH)1112// LDRH has a funny addressing mode (there's already a FIXME for it).1113MIB.addReg(0);1114MIB.addImm(0).add(predOps(ARMCC::AL));1115break;1116}1117case G_MERGE_VALUES: {1118if (!selectMergeValues(MIB, TII, MRI, TRI, RBI))1119return false;1120break;1121}1122case G_UNMERGE_VALUES: {1123if (!selectUnmergeValues(MIB, TII, MRI, TRI, RBI))1124return false;1125break;1126}1127case G_BRCOND: {1128if (!validReg(MRI, I.getOperand(0).getReg(), 1, ARM::GPRRegBankID)) {1129LLVM_DEBUG(dbgs() << "Unsupported condition register for G_BRCOND");1130return false;1131}11321133// Set the flags.1134auto Test =1135BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(Opcodes.TSTri))1136.addReg(I.getOperand(0).getReg())1137.addImm(1)1138.add(predOps(ARMCC::AL));1139if (!constrainSelectedInstRegOperands(*Test, TII, TRI, RBI))1140return false;11411142// Branch conditionally.1143auto Branch =1144BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(Opcodes.Bcc))1145.add(I.getOperand(1))1146.add(predOps(ARMCC::NE, ARM::CPSR));1147if (!constrainSelectedInstRegOperands(*Branch, TII, TRI, RBI))1148return false;1149I.eraseFromParent();1150return true;1151}1152case G_PHI: {1153I.setDesc(TII.get(PHI));11541155Register DstReg = I.getOperand(0).getReg();1156const TargetRegisterClass *RC = guessRegClass(DstReg, MRI, TRI, RBI);1157if (!RBI.constrainGenericRegister(DstReg, *RC, MRI)) {1158break;1159}11601161return true;1162}1163default:1164return false;1165}11661167return constrainSelectedInstRegOperands(I, TII, TRI, RBI);1168}116911701171