10b57cec5SDimitry Andric //===- ARMInstructionSelector.cpp ----------------------------*- C++ -*-==// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric /// \file 90b57cec5SDimitry Andric /// This file implements the targeting of the InstructionSelector class for ARM. 100b57cec5SDimitry Andric /// \todo This should be generated by TableGen. 110b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 120b57cec5SDimitry Andric 130b57cec5SDimitry Andric #include "ARMRegisterBankInfo.h" 140b57cec5SDimitry Andric #include "ARMSubtarget.h" 150b57cec5SDimitry Andric #include "ARMTargetMachine.h" 1606c3fb27SDimitry Andric #include "llvm/CodeGen/GlobalISel/GIMatchTableExecutorImpl.h" 170b57cec5SDimitry Andric #include "llvm/CodeGen/GlobalISel/InstructionSelector.h" 180b57cec5SDimitry Andric #include "llvm/CodeGen/MachineConstantPool.h" 190b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h" 20480093f4SDimitry Andric #include "llvm/IR/IntrinsicsARM.h" 210b57cec5SDimitry Andric #include "llvm/Support/Debug.h" 220b57cec5SDimitry Andric 230b57cec5SDimitry Andric #define DEBUG_TYPE "arm-isel" 240b57cec5SDimitry Andric 250b57cec5SDimitry Andric using namespace llvm; 260b57cec5SDimitry Andric 270b57cec5SDimitry Andric namespace { 280b57cec5SDimitry Andric 290b57cec5SDimitry Andric #define GET_GLOBALISEL_PREDICATE_BITSET 300b57cec5SDimitry Andric #include "ARMGenGlobalISel.inc" 310b57cec5SDimitry Andric #undef GET_GLOBALISEL_PREDICATE_BITSET 320b57cec5SDimitry Andric 330b57cec5SDimitry Andric class ARMInstructionSelector : public InstructionSelector { 340b57cec5SDimitry Andric public: 350b57cec5SDimitry Andric ARMInstructionSelector(const ARMBaseTargetMachine &TM, const ARMSubtarget &STI, 360b57cec5SDimitry Andric const ARMRegisterBankInfo &RBI); 370b57cec5SDimitry Andric 388bcb0991SDimitry Andric bool select(MachineInstr &I) override; 390b57cec5SDimitry Andric static const char *getName() { return DEBUG_TYPE; } 400b57cec5SDimitry Andric 410b57cec5SDimitry Andric private: 420b57cec5SDimitry Andric bool selectImpl(MachineInstr &I, CodeGenCoverage &CoverageInfo) const; 430b57cec5SDimitry Andric 440b57cec5SDimitry Andric struct CmpConstants; 450b57cec5SDimitry Andric struct InsertInfo; 460b57cec5SDimitry Andric 470b57cec5SDimitry Andric bool selectCmp(CmpConstants Helper, MachineInstrBuilder &MIB, 480b57cec5SDimitry Andric MachineRegisterInfo &MRI) const; 490b57cec5SDimitry Andric 500b57cec5SDimitry Andric // Helper for inserting a comparison sequence that sets \p ResReg to either 1 510b57cec5SDimitry Andric // if \p LHSReg and \p RHSReg are in the relationship defined by \p Cond, or 520b57cec5SDimitry Andric // \p PrevRes otherwise. In essence, it computes PrevRes OR (LHS Cond RHS). 530b57cec5SDimitry Andric bool insertComparison(CmpConstants Helper, InsertInfo I, unsigned ResReg, 540b57cec5SDimitry Andric ARMCC::CondCodes Cond, unsigned LHSReg, unsigned RHSReg, 550b57cec5SDimitry Andric unsigned PrevRes) const; 560b57cec5SDimitry Andric 570b57cec5SDimitry Andric // Set \p DestReg to \p Constant. 580b57cec5SDimitry Andric void putConstant(InsertInfo I, unsigned DestReg, unsigned Constant) const; 590b57cec5SDimitry Andric 600b57cec5SDimitry Andric bool selectGlobal(MachineInstrBuilder &MIB, MachineRegisterInfo &MRI) const; 610b57cec5SDimitry Andric bool selectSelect(MachineInstrBuilder &MIB, MachineRegisterInfo &MRI) const; 620b57cec5SDimitry Andric bool selectShift(unsigned ShiftOpc, MachineInstrBuilder &MIB) const; 630b57cec5SDimitry Andric 640b57cec5SDimitry Andric // Check if the types match and both operands have the expected size and 650b57cec5SDimitry Andric // register bank. 660b57cec5SDimitry Andric bool validOpRegPair(MachineRegisterInfo &MRI, unsigned LHS, unsigned RHS, 670b57cec5SDimitry Andric unsigned ExpectedSize, unsigned ExpectedRegBankID) const; 680b57cec5SDimitry Andric 690b57cec5SDimitry Andric // Check if the register has the expected size and register bank. 700b57cec5SDimitry Andric bool validReg(MachineRegisterInfo &MRI, unsigned Reg, unsigned ExpectedSize, 710b57cec5SDimitry Andric unsigned ExpectedRegBankID) const; 720b57cec5SDimitry Andric 730b57cec5SDimitry Andric const ARMBaseInstrInfo &TII; 740b57cec5SDimitry Andric const ARMBaseRegisterInfo &TRI; 750b57cec5SDimitry Andric const ARMBaseTargetMachine &TM; 760b57cec5SDimitry Andric const ARMRegisterBankInfo &RBI; 770b57cec5SDimitry Andric const ARMSubtarget &STI; 780b57cec5SDimitry Andric 790b57cec5SDimitry Andric // FIXME: This is necessary because DAGISel uses "Subtarget->" and GlobalISel 800b57cec5SDimitry Andric // uses "STI." in the code generated by TableGen. If we want to reuse some of 810b57cec5SDimitry Andric // the custom C++ predicates written for DAGISel, we need to have both around. 820b57cec5SDimitry Andric const ARMSubtarget *Subtarget = &STI; 830b57cec5SDimitry Andric 840b57cec5SDimitry Andric // Store the opcodes that we might need, so we don't have to check what kind 850b57cec5SDimitry Andric // of subtarget (ARM vs Thumb) we have all the time. 860b57cec5SDimitry Andric struct OpcodeCache { 870b57cec5SDimitry Andric unsigned ZEXT16; 880b57cec5SDimitry Andric unsigned SEXT16; 890b57cec5SDimitry Andric 900b57cec5SDimitry Andric unsigned ZEXT8; 910b57cec5SDimitry Andric unsigned SEXT8; 920b57cec5SDimitry Andric 930b57cec5SDimitry Andric // Used for implementing ZEXT/SEXT from i1 940b57cec5SDimitry Andric unsigned AND; 950b57cec5SDimitry Andric unsigned RSB; 960b57cec5SDimitry Andric 970b57cec5SDimitry Andric unsigned STORE32; 980b57cec5SDimitry Andric unsigned LOAD32; 990b57cec5SDimitry Andric 1000b57cec5SDimitry Andric unsigned STORE16; 1010b57cec5SDimitry Andric unsigned LOAD16; 1020b57cec5SDimitry Andric 1030b57cec5SDimitry Andric unsigned STORE8; 1040b57cec5SDimitry Andric unsigned LOAD8; 1050b57cec5SDimitry Andric 1060b57cec5SDimitry Andric unsigned ADDrr; 1070b57cec5SDimitry Andric unsigned ADDri; 1080b57cec5SDimitry Andric 1090b57cec5SDimitry Andric // Used for G_ICMP 1100b57cec5SDimitry Andric unsigned CMPrr; 1110b57cec5SDimitry Andric unsigned MOVi; 1120b57cec5SDimitry Andric unsigned MOVCCi; 1130b57cec5SDimitry Andric 1140b57cec5SDimitry Andric // Used for G_SELECT 1150b57cec5SDimitry Andric unsigned MOVCCr; 1160b57cec5SDimitry Andric 1170b57cec5SDimitry Andric unsigned TSTri; 1180b57cec5SDimitry Andric unsigned Bcc; 1190b57cec5SDimitry Andric 1200b57cec5SDimitry Andric // Used for G_GLOBAL_VALUE 1210b57cec5SDimitry Andric unsigned MOVi32imm; 1220b57cec5SDimitry Andric unsigned ConstPoolLoad; 1230b57cec5SDimitry Andric unsigned MOV_ga_pcrel; 1240b57cec5SDimitry Andric unsigned LDRLIT_ga_pcrel; 1250b57cec5SDimitry Andric unsigned LDRLIT_ga_abs; 1260b57cec5SDimitry Andric 1270b57cec5SDimitry Andric OpcodeCache(const ARMSubtarget &STI); 1280b57cec5SDimitry Andric } const Opcodes; 1290b57cec5SDimitry Andric 1300b57cec5SDimitry Andric // Select the opcode for simple extensions (that translate to a single SXT/UXT 1310b57cec5SDimitry Andric // instruction). Extension operations more complicated than that should not 1320b57cec5SDimitry Andric // invoke this. Returns the original opcode if it doesn't know how to select a 1330b57cec5SDimitry Andric // better one. 1340b57cec5SDimitry Andric unsigned selectSimpleExtOpc(unsigned Opc, unsigned Size) const; 1350b57cec5SDimitry Andric 1360b57cec5SDimitry Andric // Select the opcode for simple loads and stores. Returns the original opcode 1370b57cec5SDimitry Andric // if it doesn't know how to select a better one. 1380b57cec5SDimitry Andric unsigned selectLoadStoreOpCode(unsigned Opc, unsigned RegBank, 1390b57cec5SDimitry Andric unsigned Size) const; 1400b57cec5SDimitry Andric 141480093f4SDimitry Andric void renderVFPF32Imm(MachineInstrBuilder &New, const MachineInstr &Old, 142480093f4SDimitry Andric int OpIdx = -1) const; 143480093f4SDimitry Andric void renderVFPF64Imm(MachineInstrBuilder &New, const MachineInstr &Old, 144480093f4SDimitry Andric int OpIdx = -1) const; 145*0fca6ea1SDimitry Andric void renderInvertedImm(MachineInstrBuilder &MIB, const MachineInstr &MI, 146*0fca6ea1SDimitry Andric int OpIdx = -1) const; 1470b57cec5SDimitry Andric 1480b57cec5SDimitry Andric #define GET_GLOBALISEL_PREDICATES_DECL 1490b57cec5SDimitry Andric #include "ARMGenGlobalISel.inc" 1500b57cec5SDimitry Andric #undef GET_GLOBALISEL_PREDICATES_DECL 1510b57cec5SDimitry Andric 1520b57cec5SDimitry Andric // We declare the temporaries used by selectImpl() in the class to minimize the 1530b57cec5SDimitry Andric // cost of constructing placeholder values. 1540b57cec5SDimitry Andric #define GET_GLOBALISEL_TEMPORARIES_DECL 1550b57cec5SDimitry Andric #include "ARMGenGlobalISel.inc" 1560b57cec5SDimitry Andric #undef GET_GLOBALISEL_TEMPORARIES_DECL 1570b57cec5SDimitry Andric }; 1580b57cec5SDimitry Andric } // end anonymous namespace 1590b57cec5SDimitry Andric 1600b57cec5SDimitry Andric namespace llvm { 1610b57cec5SDimitry Andric InstructionSelector * 1620b57cec5SDimitry Andric createARMInstructionSelector(const ARMBaseTargetMachine &TM, 1630b57cec5SDimitry Andric const ARMSubtarget &STI, 1640b57cec5SDimitry Andric const ARMRegisterBankInfo &RBI) { 1650b57cec5SDimitry Andric return new ARMInstructionSelector(TM, STI, RBI); 1660b57cec5SDimitry Andric } 1670b57cec5SDimitry Andric } 1680b57cec5SDimitry Andric 1690b57cec5SDimitry Andric #define GET_GLOBALISEL_IMPL 1700b57cec5SDimitry Andric #include "ARMGenGlobalISel.inc" 1710b57cec5SDimitry Andric #undef GET_GLOBALISEL_IMPL 1720b57cec5SDimitry Andric 1730b57cec5SDimitry Andric ARMInstructionSelector::ARMInstructionSelector(const ARMBaseTargetMachine &TM, 1740b57cec5SDimitry Andric const ARMSubtarget &STI, 1750b57cec5SDimitry Andric const ARMRegisterBankInfo &RBI) 17604eeddc0SDimitry Andric : TII(*STI.getInstrInfo()), TRI(*STI.getRegisterInfo()), TM(TM), RBI(RBI), 17704eeddc0SDimitry Andric STI(STI), Opcodes(STI), 1780b57cec5SDimitry Andric #define GET_GLOBALISEL_PREDICATES_INIT 1790b57cec5SDimitry Andric #include "ARMGenGlobalISel.inc" 1800b57cec5SDimitry Andric #undef GET_GLOBALISEL_PREDICATES_INIT 1810b57cec5SDimitry Andric #define GET_GLOBALISEL_TEMPORARIES_INIT 1820b57cec5SDimitry Andric #include "ARMGenGlobalISel.inc" 1830b57cec5SDimitry Andric #undef GET_GLOBALISEL_TEMPORARIES_INIT 1840b57cec5SDimitry Andric { 1850b57cec5SDimitry Andric } 1860b57cec5SDimitry Andric 1870b57cec5SDimitry Andric static const TargetRegisterClass *guessRegClass(unsigned Reg, 1880b57cec5SDimitry Andric MachineRegisterInfo &MRI, 1890b57cec5SDimitry Andric const TargetRegisterInfo &TRI, 1900b57cec5SDimitry Andric const RegisterBankInfo &RBI) { 1910b57cec5SDimitry Andric const RegisterBank *RegBank = RBI.getRegBank(Reg, MRI, TRI); 1920b57cec5SDimitry Andric assert(RegBank && "Can't get reg bank for virtual register"); 1930b57cec5SDimitry Andric 1940b57cec5SDimitry Andric const unsigned Size = MRI.getType(Reg).getSizeInBits(); 1950b57cec5SDimitry Andric assert((RegBank->getID() == ARM::GPRRegBankID || 1960b57cec5SDimitry Andric RegBank->getID() == ARM::FPRRegBankID) && 1970b57cec5SDimitry Andric "Unsupported reg bank"); 1980b57cec5SDimitry Andric 1990b57cec5SDimitry Andric if (RegBank->getID() == ARM::FPRRegBankID) { 2000b57cec5SDimitry Andric if (Size == 32) 2010b57cec5SDimitry Andric return &ARM::SPRRegClass; 2020b57cec5SDimitry Andric else if (Size == 64) 2030b57cec5SDimitry Andric return &ARM::DPRRegClass; 2040b57cec5SDimitry Andric else if (Size == 128) 2050b57cec5SDimitry Andric return &ARM::QPRRegClass; 2060b57cec5SDimitry Andric else 2070b57cec5SDimitry Andric llvm_unreachable("Unsupported destination size"); 2080b57cec5SDimitry Andric } 2090b57cec5SDimitry Andric 2100b57cec5SDimitry Andric return &ARM::GPRRegClass; 2110b57cec5SDimitry Andric } 2120b57cec5SDimitry Andric 2130b57cec5SDimitry Andric static bool selectCopy(MachineInstr &I, const TargetInstrInfo &TII, 2140b57cec5SDimitry Andric MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI, 2150b57cec5SDimitry Andric const RegisterBankInfo &RBI) { 2168bcb0991SDimitry Andric Register DstReg = I.getOperand(0).getReg(); 217bdd1243dSDimitry Andric if (DstReg.isPhysical()) 2180b57cec5SDimitry Andric return true; 2190b57cec5SDimitry Andric 2200b57cec5SDimitry Andric const TargetRegisterClass *RC = guessRegClass(DstReg, MRI, TRI, RBI); 2210b57cec5SDimitry Andric 2220b57cec5SDimitry Andric // No need to constrain SrcReg. It will get constrained when 2230b57cec5SDimitry Andric // we hit another of its uses or its defs. 2240b57cec5SDimitry Andric // Copies do not have constraints. 2250b57cec5SDimitry Andric if (!RBI.constrainGenericRegister(DstReg, *RC, MRI)) { 2260b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Failed to constrain " << TII.getName(I.getOpcode()) 2270b57cec5SDimitry Andric << " operand\n"); 2280b57cec5SDimitry Andric return false; 2290b57cec5SDimitry Andric } 2300b57cec5SDimitry Andric return true; 2310b57cec5SDimitry Andric } 2320b57cec5SDimitry Andric 2330b57cec5SDimitry Andric static bool selectMergeValues(MachineInstrBuilder &MIB, 2340b57cec5SDimitry Andric const ARMBaseInstrInfo &TII, 2350b57cec5SDimitry Andric MachineRegisterInfo &MRI, 2360b57cec5SDimitry Andric const TargetRegisterInfo &TRI, 2370b57cec5SDimitry Andric const RegisterBankInfo &RBI) { 2380b57cec5SDimitry Andric assert(TII.getSubtarget().hasVFP2Base() && "Can't select merge without VFP"); 2390b57cec5SDimitry Andric 2400b57cec5SDimitry Andric // We only support G_MERGE_VALUES as a way to stick together two scalar GPRs 2410b57cec5SDimitry Andric // into one DPR. 2425ffd83dbSDimitry Andric Register VReg0 = MIB.getReg(0); 2430b57cec5SDimitry Andric (void)VReg0; 2440b57cec5SDimitry Andric assert(MRI.getType(VReg0).getSizeInBits() == 64 && 2450b57cec5SDimitry Andric RBI.getRegBank(VReg0, MRI, TRI)->getID() == ARM::FPRRegBankID && 2460b57cec5SDimitry Andric "Unsupported operand for G_MERGE_VALUES"); 2475ffd83dbSDimitry Andric Register VReg1 = MIB.getReg(1); 2480b57cec5SDimitry Andric (void)VReg1; 2490b57cec5SDimitry Andric assert(MRI.getType(VReg1).getSizeInBits() == 32 && 2500b57cec5SDimitry Andric RBI.getRegBank(VReg1, MRI, TRI)->getID() == ARM::GPRRegBankID && 2510b57cec5SDimitry Andric "Unsupported operand for G_MERGE_VALUES"); 2525ffd83dbSDimitry Andric Register VReg2 = MIB.getReg(2); 2530b57cec5SDimitry Andric (void)VReg2; 2540b57cec5SDimitry Andric assert(MRI.getType(VReg2).getSizeInBits() == 32 && 2550b57cec5SDimitry Andric RBI.getRegBank(VReg2, MRI, TRI)->getID() == ARM::GPRRegBankID && 2560b57cec5SDimitry Andric "Unsupported operand for G_MERGE_VALUES"); 2570b57cec5SDimitry Andric 2580b57cec5SDimitry Andric MIB->setDesc(TII.get(ARM::VMOVDRR)); 2590b57cec5SDimitry Andric MIB.add(predOps(ARMCC::AL)); 2600b57cec5SDimitry Andric 2610b57cec5SDimitry Andric return true; 2620b57cec5SDimitry Andric } 2630b57cec5SDimitry Andric 2640b57cec5SDimitry Andric static bool selectUnmergeValues(MachineInstrBuilder &MIB, 2650b57cec5SDimitry Andric const ARMBaseInstrInfo &TII, 2660b57cec5SDimitry Andric MachineRegisterInfo &MRI, 2670b57cec5SDimitry Andric const TargetRegisterInfo &TRI, 2680b57cec5SDimitry Andric const RegisterBankInfo &RBI) { 2690b57cec5SDimitry Andric assert(TII.getSubtarget().hasVFP2Base() && 2700b57cec5SDimitry Andric "Can't select unmerge without VFP"); 2710b57cec5SDimitry Andric 2720b57cec5SDimitry Andric // We only support G_UNMERGE_VALUES as a way to break up one DPR into two 2730b57cec5SDimitry Andric // GPRs. 2745ffd83dbSDimitry Andric Register VReg0 = MIB.getReg(0); 2750b57cec5SDimitry Andric (void)VReg0; 2760b57cec5SDimitry Andric assert(MRI.getType(VReg0).getSizeInBits() == 32 && 2770b57cec5SDimitry Andric RBI.getRegBank(VReg0, MRI, TRI)->getID() == ARM::GPRRegBankID && 2780b57cec5SDimitry Andric "Unsupported operand for G_UNMERGE_VALUES"); 2795ffd83dbSDimitry Andric Register VReg1 = MIB.getReg(1); 2800b57cec5SDimitry Andric (void)VReg1; 2810b57cec5SDimitry Andric assert(MRI.getType(VReg1).getSizeInBits() == 32 && 2820b57cec5SDimitry Andric RBI.getRegBank(VReg1, MRI, TRI)->getID() == ARM::GPRRegBankID && 2830b57cec5SDimitry Andric "Unsupported operand for G_UNMERGE_VALUES"); 2845ffd83dbSDimitry Andric Register VReg2 = MIB.getReg(2); 2850b57cec5SDimitry Andric (void)VReg2; 2860b57cec5SDimitry Andric assert(MRI.getType(VReg2).getSizeInBits() == 64 && 2870b57cec5SDimitry Andric RBI.getRegBank(VReg2, MRI, TRI)->getID() == ARM::FPRRegBankID && 2880b57cec5SDimitry Andric "Unsupported operand for G_UNMERGE_VALUES"); 2890b57cec5SDimitry Andric 2900b57cec5SDimitry Andric MIB->setDesc(TII.get(ARM::VMOVRRD)); 2910b57cec5SDimitry Andric MIB.add(predOps(ARMCC::AL)); 2920b57cec5SDimitry Andric 2930b57cec5SDimitry Andric return true; 2940b57cec5SDimitry Andric } 2950b57cec5SDimitry Andric 2960b57cec5SDimitry Andric ARMInstructionSelector::OpcodeCache::OpcodeCache(const ARMSubtarget &STI) { 2970b57cec5SDimitry Andric bool isThumb = STI.isThumb(); 2980b57cec5SDimitry Andric 2990b57cec5SDimitry Andric using namespace TargetOpcode; 3000b57cec5SDimitry Andric 3010b57cec5SDimitry Andric #define STORE_OPCODE(VAR, OPC) VAR = isThumb ? ARM::t2##OPC : ARM::OPC 3020b57cec5SDimitry Andric STORE_OPCODE(SEXT16, SXTH); 3030b57cec5SDimitry Andric STORE_OPCODE(ZEXT16, UXTH); 3040b57cec5SDimitry Andric 3050b57cec5SDimitry Andric STORE_OPCODE(SEXT8, SXTB); 3060b57cec5SDimitry Andric STORE_OPCODE(ZEXT8, UXTB); 3070b57cec5SDimitry Andric 3080b57cec5SDimitry Andric STORE_OPCODE(AND, ANDri); 3090b57cec5SDimitry Andric STORE_OPCODE(RSB, RSBri); 3100b57cec5SDimitry Andric 3110b57cec5SDimitry Andric STORE_OPCODE(STORE32, STRi12); 3120b57cec5SDimitry Andric STORE_OPCODE(LOAD32, LDRi12); 3130b57cec5SDimitry Andric 3140b57cec5SDimitry Andric // LDRH/STRH are special... 3150b57cec5SDimitry Andric STORE16 = isThumb ? ARM::t2STRHi12 : ARM::STRH; 3160b57cec5SDimitry Andric LOAD16 = isThumb ? ARM::t2LDRHi12 : ARM::LDRH; 3170b57cec5SDimitry Andric 3180b57cec5SDimitry Andric STORE_OPCODE(STORE8, STRBi12); 3190b57cec5SDimitry Andric STORE_OPCODE(LOAD8, LDRBi12); 3200b57cec5SDimitry Andric 3210b57cec5SDimitry Andric STORE_OPCODE(ADDrr, ADDrr); 3220b57cec5SDimitry Andric STORE_OPCODE(ADDri, ADDri); 3230b57cec5SDimitry Andric 3240b57cec5SDimitry Andric STORE_OPCODE(CMPrr, CMPrr); 3250b57cec5SDimitry Andric STORE_OPCODE(MOVi, MOVi); 3260b57cec5SDimitry Andric STORE_OPCODE(MOVCCi, MOVCCi); 3270b57cec5SDimitry Andric 3280b57cec5SDimitry Andric STORE_OPCODE(MOVCCr, MOVCCr); 3290b57cec5SDimitry Andric 3300b57cec5SDimitry Andric STORE_OPCODE(TSTri, TSTri); 3310b57cec5SDimitry Andric STORE_OPCODE(Bcc, Bcc); 3320b57cec5SDimitry Andric 3330b57cec5SDimitry Andric STORE_OPCODE(MOVi32imm, MOVi32imm); 3340b57cec5SDimitry Andric ConstPoolLoad = isThumb ? ARM::t2LDRpci : ARM::LDRi12; 3350b57cec5SDimitry Andric STORE_OPCODE(MOV_ga_pcrel, MOV_ga_pcrel); 3360b57cec5SDimitry Andric LDRLIT_ga_pcrel = isThumb ? ARM::tLDRLIT_ga_pcrel : ARM::LDRLIT_ga_pcrel; 3370b57cec5SDimitry Andric LDRLIT_ga_abs = isThumb ? ARM::tLDRLIT_ga_abs : ARM::LDRLIT_ga_abs; 3380b57cec5SDimitry Andric #undef MAP_OPCODE 3390b57cec5SDimitry Andric } 3400b57cec5SDimitry Andric 3410b57cec5SDimitry Andric unsigned ARMInstructionSelector::selectSimpleExtOpc(unsigned Opc, 3420b57cec5SDimitry Andric unsigned Size) const { 3430b57cec5SDimitry Andric using namespace TargetOpcode; 3440b57cec5SDimitry Andric 3450b57cec5SDimitry Andric if (Size != 8 && Size != 16) 3460b57cec5SDimitry Andric return Opc; 3470b57cec5SDimitry Andric 3480b57cec5SDimitry Andric if (Opc == G_SEXT) 3490b57cec5SDimitry Andric return Size == 8 ? Opcodes.SEXT8 : Opcodes.SEXT16; 3500b57cec5SDimitry Andric 3510b57cec5SDimitry Andric if (Opc == G_ZEXT) 3520b57cec5SDimitry Andric return Size == 8 ? Opcodes.ZEXT8 : Opcodes.ZEXT16; 3530b57cec5SDimitry Andric 3540b57cec5SDimitry Andric return Opc; 3550b57cec5SDimitry Andric } 3560b57cec5SDimitry Andric 3570b57cec5SDimitry Andric unsigned ARMInstructionSelector::selectLoadStoreOpCode(unsigned Opc, 3580b57cec5SDimitry Andric unsigned RegBank, 3590b57cec5SDimitry Andric unsigned Size) const { 3600b57cec5SDimitry Andric bool isStore = Opc == TargetOpcode::G_STORE; 3610b57cec5SDimitry Andric 3620b57cec5SDimitry Andric if (RegBank == ARM::GPRRegBankID) { 3630b57cec5SDimitry Andric switch (Size) { 3640b57cec5SDimitry Andric case 1: 3650b57cec5SDimitry Andric case 8: 3660b57cec5SDimitry Andric return isStore ? Opcodes.STORE8 : Opcodes.LOAD8; 3670b57cec5SDimitry Andric case 16: 3680b57cec5SDimitry Andric return isStore ? Opcodes.STORE16 : Opcodes.LOAD16; 3690b57cec5SDimitry Andric case 32: 3700b57cec5SDimitry Andric return isStore ? Opcodes.STORE32 : Opcodes.LOAD32; 3710b57cec5SDimitry Andric default: 3720b57cec5SDimitry Andric return Opc; 3730b57cec5SDimitry Andric } 3740b57cec5SDimitry Andric } 3750b57cec5SDimitry Andric 3760b57cec5SDimitry Andric if (RegBank == ARM::FPRRegBankID) { 3770b57cec5SDimitry Andric switch (Size) { 3780b57cec5SDimitry Andric case 32: 3790b57cec5SDimitry Andric return isStore ? ARM::VSTRS : ARM::VLDRS; 3800b57cec5SDimitry Andric case 64: 3810b57cec5SDimitry Andric return isStore ? ARM::VSTRD : ARM::VLDRD; 3820b57cec5SDimitry Andric default: 3830b57cec5SDimitry Andric return Opc; 3840b57cec5SDimitry Andric } 3850b57cec5SDimitry Andric } 3860b57cec5SDimitry Andric 3870b57cec5SDimitry Andric return Opc; 3880b57cec5SDimitry Andric } 3890b57cec5SDimitry Andric 3900b57cec5SDimitry Andric // When lowering comparisons, we sometimes need to perform two compares instead 3910b57cec5SDimitry Andric // of just one. Get the condition codes for both comparisons. If only one is 3920b57cec5SDimitry Andric // needed, the second member of the pair is ARMCC::AL. 3930b57cec5SDimitry Andric static std::pair<ARMCC::CondCodes, ARMCC::CondCodes> 3940b57cec5SDimitry Andric getComparePreds(CmpInst::Predicate Pred) { 3950b57cec5SDimitry Andric std::pair<ARMCC::CondCodes, ARMCC::CondCodes> Preds = {ARMCC::AL, ARMCC::AL}; 3960b57cec5SDimitry Andric switch (Pred) { 3970b57cec5SDimitry Andric case CmpInst::FCMP_ONE: 3980b57cec5SDimitry Andric Preds = {ARMCC::GT, ARMCC::MI}; 3990b57cec5SDimitry Andric break; 4000b57cec5SDimitry Andric case CmpInst::FCMP_UEQ: 4010b57cec5SDimitry Andric Preds = {ARMCC::EQ, ARMCC::VS}; 4020b57cec5SDimitry Andric break; 4030b57cec5SDimitry Andric case CmpInst::ICMP_EQ: 4040b57cec5SDimitry Andric case CmpInst::FCMP_OEQ: 4050b57cec5SDimitry Andric Preds.first = ARMCC::EQ; 4060b57cec5SDimitry Andric break; 4070b57cec5SDimitry Andric case CmpInst::ICMP_SGT: 4080b57cec5SDimitry Andric case CmpInst::FCMP_OGT: 4090b57cec5SDimitry Andric Preds.first = ARMCC::GT; 4100b57cec5SDimitry Andric break; 4110b57cec5SDimitry Andric case CmpInst::ICMP_SGE: 4120b57cec5SDimitry Andric case CmpInst::FCMP_OGE: 4130b57cec5SDimitry Andric Preds.first = ARMCC::GE; 4140b57cec5SDimitry Andric break; 4150b57cec5SDimitry Andric case CmpInst::ICMP_UGT: 4160b57cec5SDimitry Andric case CmpInst::FCMP_UGT: 4170b57cec5SDimitry Andric Preds.first = ARMCC::HI; 4180b57cec5SDimitry Andric break; 4190b57cec5SDimitry Andric case CmpInst::FCMP_OLT: 4200b57cec5SDimitry Andric Preds.first = ARMCC::MI; 4210b57cec5SDimitry Andric break; 4220b57cec5SDimitry Andric case CmpInst::ICMP_ULE: 4230b57cec5SDimitry Andric case CmpInst::FCMP_OLE: 4240b57cec5SDimitry Andric Preds.first = ARMCC::LS; 4250b57cec5SDimitry Andric break; 4260b57cec5SDimitry Andric case CmpInst::FCMP_ORD: 4270b57cec5SDimitry Andric Preds.first = ARMCC::VC; 4280b57cec5SDimitry Andric break; 4290b57cec5SDimitry Andric case CmpInst::FCMP_UNO: 4300b57cec5SDimitry Andric Preds.first = ARMCC::VS; 4310b57cec5SDimitry Andric break; 4320b57cec5SDimitry Andric case CmpInst::FCMP_UGE: 4330b57cec5SDimitry Andric Preds.first = ARMCC::PL; 4340b57cec5SDimitry Andric break; 4350b57cec5SDimitry Andric case CmpInst::ICMP_SLT: 4360b57cec5SDimitry Andric case CmpInst::FCMP_ULT: 4370b57cec5SDimitry Andric Preds.first = ARMCC::LT; 4380b57cec5SDimitry Andric break; 4390b57cec5SDimitry Andric case CmpInst::ICMP_SLE: 4400b57cec5SDimitry Andric case CmpInst::FCMP_ULE: 4410b57cec5SDimitry Andric Preds.first = ARMCC::LE; 4420b57cec5SDimitry Andric break; 4430b57cec5SDimitry Andric case CmpInst::FCMP_UNE: 4440b57cec5SDimitry Andric case CmpInst::ICMP_NE: 4450b57cec5SDimitry Andric Preds.first = ARMCC::NE; 4460b57cec5SDimitry Andric break; 4470b57cec5SDimitry Andric case CmpInst::ICMP_UGE: 4480b57cec5SDimitry Andric Preds.first = ARMCC::HS; 4490b57cec5SDimitry Andric break; 4500b57cec5SDimitry Andric case CmpInst::ICMP_ULT: 4510b57cec5SDimitry Andric Preds.first = ARMCC::LO; 4520b57cec5SDimitry Andric break; 4530b57cec5SDimitry Andric default: 4540b57cec5SDimitry Andric break; 4550b57cec5SDimitry Andric } 4560b57cec5SDimitry Andric assert(Preds.first != ARMCC::AL && "No comparisons needed?"); 4570b57cec5SDimitry Andric return Preds; 4580b57cec5SDimitry Andric } 4590b57cec5SDimitry Andric 4600b57cec5SDimitry Andric struct ARMInstructionSelector::CmpConstants { 4610b57cec5SDimitry Andric CmpConstants(unsigned CmpOpcode, unsigned FlagsOpcode, unsigned SelectOpcode, 4620b57cec5SDimitry Andric unsigned OpRegBank, unsigned OpSize) 4630b57cec5SDimitry Andric : ComparisonOpcode(CmpOpcode), ReadFlagsOpcode(FlagsOpcode), 4640b57cec5SDimitry Andric SelectResultOpcode(SelectOpcode), OperandRegBankID(OpRegBank), 4650b57cec5SDimitry Andric OperandSize(OpSize) {} 4660b57cec5SDimitry Andric 4670b57cec5SDimitry Andric // The opcode used for performing the comparison. 4680b57cec5SDimitry Andric const unsigned ComparisonOpcode; 4690b57cec5SDimitry Andric 4700b57cec5SDimitry Andric // The opcode used for reading the flags set by the comparison. May be 4710b57cec5SDimitry Andric // ARM::INSTRUCTION_LIST_END if we don't need to read the flags. 4720b57cec5SDimitry Andric const unsigned ReadFlagsOpcode; 4730b57cec5SDimitry Andric 4740b57cec5SDimitry Andric // The opcode used for materializing the result of the comparison. 4750b57cec5SDimitry Andric const unsigned SelectResultOpcode; 4760b57cec5SDimitry Andric 4770b57cec5SDimitry Andric // The assumed register bank ID for the operands. 4780b57cec5SDimitry Andric const unsigned OperandRegBankID; 4790b57cec5SDimitry Andric 4800b57cec5SDimitry Andric // The assumed size in bits for the operands. 4810b57cec5SDimitry Andric const unsigned OperandSize; 4820b57cec5SDimitry Andric }; 4830b57cec5SDimitry Andric 4840b57cec5SDimitry Andric struct ARMInstructionSelector::InsertInfo { 4850b57cec5SDimitry Andric InsertInfo(MachineInstrBuilder &MIB) 4860b57cec5SDimitry Andric : MBB(*MIB->getParent()), InsertBefore(std::next(MIB->getIterator())), 4870b57cec5SDimitry Andric DbgLoc(MIB->getDebugLoc()) {} 4880b57cec5SDimitry Andric 4890b57cec5SDimitry Andric MachineBasicBlock &MBB; 4900b57cec5SDimitry Andric const MachineBasicBlock::instr_iterator InsertBefore; 4910b57cec5SDimitry Andric const DebugLoc &DbgLoc; 4920b57cec5SDimitry Andric }; 4930b57cec5SDimitry Andric 4940b57cec5SDimitry Andric void ARMInstructionSelector::putConstant(InsertInfo I, unsigned DestReg, 4950b57cec5SDimitry Andric unsigned Constant) const { 4960b57cec5SDimitry Andric (void)BuildMI(I.MBB, I.InsertBefore, I.DbgLoc, TII.get(Opcodes.MOVi)) 4970b57cec5SDimitry Andric .addDef(DestReg) 4980b57cec5SDimitry Andric .addImm(Constant) 4990b57cec5SDimitry Andric .add(predOps(ARMCC::AL)) 5000b57cec5SDimitry Andric .add(condCodeOp()); 5010b57cec5SDimitry Andric } 5020b57cec5SDimitry Andric 5030b57cec5SDimitry Andric bool ARMInstructionSelector::validOpRegPair(MachineRegisterInfo &MRI, 5040b57cec5SDimitry Andric unsigned LHSReg, unsigned RHSReg, 5050b57cec5SDimitry Andric unsigned ExpectedSize, 5060b57cec5SDimitry Andric unsigned ExpectedRegBankID) const { 5070b57cec5SDimitry Andric return MRI.getType(LHSReg) == MRI.getType(RHSReg) && 5080b57cec5SDimitry Andric validReg(MRI, LHSReg, ExpectedSize, ExpectedRegBankID) && 5090b57cec5SDimitry Andric validReg(MRI, RHSReg, ExpectedSize, ExpectedRegBankID); 5100b57cec5SDimitry Andric } 5110b57cec5SDimitry Andric 5120b57cec5SDimitry Andric bool ARMInstructionSelector::validReg(MachineRegisterInfo &MRI, unsigned Reg, 5130b57cec5SDimitry Andric unsigned ExpectedSize, 5140b57cec5SDimitry Andric unsigned ExpectedRegBankID) const { 5150b57cec5SDimitry Andric if (MRI.getType(Reg).getSizeInBits() != ExpectedSize) { 5160b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Unexpected size for register"); 5170b57cec5SDimitry Andric return false; 5180b57cec5SDimitry Andric } 5190b57cec5SDimitry Andric 5200b57cec5SDimitry Andric if (RBI.getRegBank(Reg, MRI, TRI)->getID() != ExpectedRegBankID) { 5210b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Unexpected register bank for register"); 5220b57cec5SDimitry Andric return false; 5230b57cec5SDimitry Andric } 5240b57cec5SDimitry Andric 5250b57cec5SDimitry Andric return true; 5260b57cec5SDimitry Andric } 5270b57cec5SDimitry Andric 5280b57cec5SDimitry Andric bool ARMInstructionSelector::selectCmp(CmpConstants Helper, 5290b57cec5SDimitry Andric MachineInstrBuilder &MIB, 5300b57cec5SDimitry Andric MachineRegisterInfo &MRI) const { 5310b57cec5SDimitry Andric const InsertInfo I(MIB); 5320b57cec5SDimitry Andric 5335ffd83dbSDimitry Andric auto ResReg = MIB.getReg(0); 5340b57cec5SDimitry Andric if (!validReg(MRI, ResReg, 1, ARM::GPRRegBankID)) 5350b57cec5SDimitry Andric return false; 5360b57cec5SDimitry Andric 5370b57cec5SDimitry Andric auto Cond = 5380b57cec5SDimitry Andric static_cast<CmpInst::Predicate>(MIB->getOperand(1).getPredicate()); 5390b57cec5SDimitry Andric if (Cond == CmpInst::FCMP_TRUE || Cond == CmpInst::FCMP_FALSE) { 5400b57cec5SDimitry Andric putConstant(I, ResReg, Cond == CmpInst::FCMP_TRUE ? 1 : 0); 5410b57cec5SDimitry Andric MIB->eraseFromParent(); 5420b57cec5SDimitry Andric return true; 5430b57cec5SDimitry Andric } 5440b57cec5SDimitry Andric 5455ffd83dbSDimitry Andric auto LHSReg = MIB.getReg(2); 5465ffd83dbSDimitry Andric auto RHSReg = MIB.getReg(3); 5470b57cec5SDimitry Andric if (!validOpRegPair(MRI, LHSReg, RHSReg, Helper.OperandSize, 5480b57cec5SDimitry Andric Helper.OperandRegBankID)) 5490b57cec5SDimitry Andric return false; 5500b57cec5SDimitry Andric 5510b57cec5SDimitry Andric auto ARMConds = getComparePreds(Cond); 5520b57cec5SDimitry Andric auto ZeroReg = MRI.createVirtualRegister(&ARM::GPRRegClass); 5530b57cec5SDimitry Andric putConstant(I, ZeroReg, 0); 5540b57cec5SDimitry Andric 5550b57cec5SDimitry Andric if (ARMConds.second == ARMCC::AL) { 5560b57cec5SDimitry Andric // Simple case, we only need one comparison and we're done. 5570b57cec5SDimitry Andric if (!insertComparison(Helper, I, ResReg, ARMConds.first, LHSReg, RHSReg, 5580b57cec5SDimitry Andric ZeroReg)) 5590b57cec5SDimitry Andric return false; 5600b57cec5SDimitry Andric } else { 5610b57cec5SDimitry Andric // Not so simple, we need two successive comparisons. 5620b57cec5SDimitry Andric auto IntermediateRes = MRI.createVirtualRegister(&ARM::GPRRegClass); 5630b57cec5SDimitry Andric if (!insertComparison(Helper, I, IntermediateRes, ARMConds.first, LHSReg, 5640b57cec5SDimitry Andric RHSReg, ZeroReg)) 5650b57cec5SDimitry Andric return false; 5660b57cec5SDimitry Andric if (!insertComparison(Helper, I, ResReg, ARMConds.second, LHSReg, RHSReg, 5670b57cec5SDimitry Andric IntermediateRes)) 5680b57cec5SDimitry Andric return false; 5690b57cec5SDimitry Andric } 5700b57cec5SDimitry Andric 5710b57cec5SDimitry Andric MIB->eraseFromParent(); 5720b57cec5SDimitry Andric return true; 5730b57cec5SDimitry Andric } 5740b57cec5SDimitry Andric 5750b57cec5SDimitry Andric bool ARMInstructionSelector::insertComparison(CmpConstants Helper, InsertInfo I, 5760b57cec5SDimitry Andric unsigned ResReg, 5770b57cec5SDimitry Andric ARMCC::CondCodes Cond, 5780b57cec5SDimitry Andric unsigned LHSReg, unsigned RHSReg, 5790b57cec5SDimitry Andric unsigned PrevRes) const { 5800b57cec5SDimitry Andric // Perform the comparison. 5810b57cec5SDimitry Andric auto CmpI = 5820b57cec5SDimitry Andric BuildMI(I.MBB, I.InsertBefore, I.DbgLoc, TII.get(Helper.ComparisonOpcode)) 5830b57cec5SDimitry Andric .addUse(LHSReg) 5840b57cec5SDimitry Andric .addUse(RHSReg) 5850b57cec5SDimitry Andric .add(predOps(ARMCC::AL)); 5860b57cec5SDimitry Andric if (!constrainSelectedInstRegOperands(*CmpI, TII, TRI, RBI)) 5870b57cec5SDimitry Andric return false; 5880b57cec5SDimitry Andric 5890b57cec5SDimitry Andric // Read the comparison flags (if necessary). 5900b57cec5SDimitry Andric if (Helper.ReadFlagsOpcode != ARM::INSTRUCTION_LIST_END) { 5910b57cec5SDimitry Andric auto ReadI = BuildMI(I.MBB, I.InsertBefore, I.DbgLoc, 5920b57cec5SDimitry Andric TII.get(Helper.ReadFlagsOpcode)) 5930b57cec5SDimitry Andric .add(predOps(ARMCC::AL)); 5940b57cec5SDimitry Andric if (!constrainSelectedInstRegOperands(*ReadI, TII, TRI, RBI)) 5950b57cec5SDimitry Andric return false; 5960b57cec5SDimitry Andric } 5970b57cec5SDimitry Andric 5980b57cec5SDimitry Andric // Select either 1 or the previous result based on the value of the flags. 5990b57cec5SDimitry Andric auto Mov1I = BuildMI(I.MBB, I.InsertBefore, I.DbgLoc, 6000b57cec5SDimitry Andric TII.get(Helper.SelectResultOpcode)) 6010b57cec5SDimitry Andric .addDef(ResReg) 6020b57cec5SDimitry Andric .addUse(PrevRes) 6030b57cec5SDimitry Andric .addImm(1) 6040b57cec5SDimitry Andric .add(predOps(Cond, ARM::CPSR)); 6050b57cec5SDimitry Andric if (!constrainSelectedInstRegOperands(*Mov1I, TII, TRI, RBI)) 6060b57cec5SDimitry Andric return false; 6070b57cec5SDimitry Andric 6080b57cec5SDimitry Andric return true; 6090b57cec5SDimitry Andric } 6100b57cec5SDimitry Andric 6110b57cec5SDimitry Andric bool ARMInstructionSelector::selectGlobal(MachineInstrBuilder &MIB, 6120b57cec5SDimitry Andric MachineRegisterInfo &MRI) const { 6130b57cec5SDimitry Andric if ((STI.isROPI() || STI.isRWPI()) && !STI.isTargetELF()) { 6140b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "ROPI and RWPI only supported for ELF\n"); 6150b57cec5SDimitry Andric return false; 6160b57cec5SDimitry Andric } 6170b57cec5SDimitry Andric 6180b57cec5SDimitry Andric auto GV = MIB->getOperand(1).getGlobal(); 6190b57cec5SDimitry Andric if (GV->isThreadLocal()) { 6200b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "TLS variables not supported yet\n"); 6210b57cec5SDimitry Andric return false; 6220b57cec5SDimitry Andric } 6230b57cec5SDimitry Andric 6240b57cec5SDimitry Andric auto &MBB = *MIB->getParent(); 6250b57cec5SDimitry Andric auto &MF = *MBB.getParent(); 6260b57cec5SDimitry Andric 6270b57cec5SDimitry Andric bool UseMovt = STI.useMovt(); 6280b57cec5SDimitry Andric 62981ad6265SDimitry Andric LLT PtrTy = MRI.getType(MIB->getOperand(0).getReg()); 6305ffd83dbSDimitry Andric const Align Alignment(4); 6310b57cec5SDimitry Andric 63281ad6265SDimitry Andric auto addOpsForConstantPoolLoad = [&MF, Alignment, PtrTy]( 63381ad6265SDimitry Andric MachineInstrBuilder &MIB, 6340b57cec5SDimitry Andric const GlobalValue *GV, bool IsSBREL) { 6350b57cec5SDimitry Andric assert((MIB->getOpcode() == ARM::LDRi12 || 6360b57cec5SDimitry Andric MIB->getOpcode() == ARM::t2LDRpci) && 6370b57cec5SDimitry Andric "Unsupported instruction"); 6380b57cec5SDimitry Andric auto ConstPool = MF.getConstantPool(); 6390b57cec5SDimitry Andric auto CPIndex = 6400b57cec5SDimitry Andric // For SB relative entries we need a target-specific constant pool. 6410b57cec5SDimitry Andric // Otherwise, just use a regular constant pool entry. 6420b57cec5SDimitry Andric IsSBREL 6430b57cec5SDimitry Andric ? ConstPool->getConstantPoolIndex( 6440b57cec5SDimitry Andric ARMConstantPoolConstant::Create(GV, ARMCP::SBREL), Alignment) 6450b57cec5SDimitry Andric : ConstPool->getConstantPoolIndex(GV, Alignment); 6460b57cec5SDimitry Andric MIB.addConstantPoolIndex(CPIndex, /*Offset*/ 0, /*TargetFlags*/ 0) 6470b57cec5SDimitry Andric .addMemOperand(MF.getMachineMemOperand( 6480b57cec5SDimitry Andric MachinePointerInfo::getConstantPool(MF), MachineMemOperand::MOLoad, 64981ad6265SDimitry Andric PtrTy, Alignment)); 6500b57cec5SDimitry Andric if (MIB->getOpcode() == ARM::LDRi12) 6510b57cec5SDimitry Andric MIB.addImm(0); 6520b57cec5SDimitry Andric MIB.add(predOps(ARMCC::AL)); 6530b57cec5SDimitry Andric }; 6540b57cec5SDimitry Andric 6550b57cec5SDimitry Andric auto addGOTMemOperand = [this, &MF, Alignment](MachineInstrBuilder &MIB) { 6560b57cec5SDimitry Andric MIB.addMemOperand(MF.getMachineMemOperand( 6570b57cec5SDimitry Andric MachinePointerInfo::getGOT(MF), MachineMemOperand::MOLoad, 6580b57cec5SDimitry Andric TM.getProgramPointerSize(), Alignment)); 6590b57cec5SDimitry Andric }; 6600b57cec5SDimitry Andric 6610b57cec5SDimitry Andric if (TM.isPositionIndependent()) { 6620b57cec5SDimitry Andric bool Indirect = STI.isGVIndirectSymbol(GV); 6630b57cec5SDimitry Andric 6640b57cec5SDimitry Andric // For ARM mode, we have different pseudoinstructions for direct accesses 6650b57cec5SDimitry Andric // and indirect accesses, and the ones for indirect accesses include the 6660b57cec5SDimitry Andric // load from GOT. For Thumb mode, we use the same pseudoinstruction for both 6670b57cec5SDimitry Andric // direct and indirect accesses, and we need to manually generate the load 6680b57cec5SDimitry Andric // from GOT. 6690b57cec5SDimitry Andric bool UseOpcodeThatLoads = Indirect && !STI.isThumb(); 6700b57cec5SDimitry Andric 6710b57cec5SDimitry Andric // FIXME: Taking advantage of MOVT for ELF is pretty involved, so we don't 6720b57cec5SDimitry Andric // support it yet. See PR28229. 6730b57cec5SDimitry Andric unsigned Opc = 6740b57cec5SDimitry Andric UseMovt && !STI.isTargetELF() 6750b57cec5SDimitry Andric ? (UseOpcodeThatLoads ? (unsigned)ARM::MOV_ga_pcrel_ldr 6760b57cec5SDimitry Andric : Opcodes.MOV_ga_pcrel) 6770b57cec5SDimitry Andric : (UseOpcodeThatLoads ? (unsigned)ARM::LDRLIT_ga_pcrel_ldr 6780b57cec5SDimitry Andric : Opcodes.LDRLIT_ga_pcrel); 6790b57cec5SDimitry Andric MIB->setDesc(TII.get(Opc)); 6800b57cec5SDimitry Andric 6810b57cec5SDimitry Andric int TargetFlags = ARMII::MO_NO_FLAG; 6820b57cec5SDimitry Andric if (STI.isTargetDarwin()) 6830b57cec5SDimitry Andric TargetFlags |= ARMII::MO_NONLAZY; 6840b57cec5SDimitry Andric if (STI.isGVInGOT(GV)) 6850b57cec5SDimitry Andric TargetFlags |= ARMII::MO_GOT; 6860b57cec5SDimitry Andric MIB->getOperand(1).setTargetFlags(TargetFlags); 6870b57cec5SDimitry Andric 6880b57cec5SDimitry Andric if (Indirect) { 6890b57cec5SDimitry Andric if (!UseOpcodeThatLoads) { 6905ffd83dbSDimitry Andric auto ResultReg = MIB.getReg(0); 6910b57cec5SDimitry Andric auto AddressReg = MRI.createVirtualRegister(&ARM::GPRRegClass); 6920b57cec5SDimitry Andric 6930b57cec5SDimitry Andric MIB->getOperand(0).setReg(AddressReg); 6940b57cec5SDimitry Andric 6950b57cec5SDimitry Andric auto InsertBefore = std::next(MIB->getIterator()); 6960b57cec5SDimitry Andric auto MIBLoad = BuildMI(MBB, InsertBefore, MIB->getDebugLoc(), 6970b57cec5SDimitry Andric TII.get(Opcodes.LOAD32)) 6980b57cec5SDimitry Andric .addDef(ResultReg) 6990b57cec5SDimitry Andric .addReg(AddressReg) 7000b57cec5SDimitry Andric .addImm(0) 7010b57cec5SDimitry Andric .add(predOps(ARMCC::AL)); 7020b57cec5SDimitry Andric addGOTMemOperand(MIBLoad); 7030b57cec5SDimitry Andric 7040b57cec5SDimitry Andric if (!constrainSelectedInstRegOperands(*MIBLoad, TII, TRI, RBI)) 7050b57cec5SDimitry Andric return false; 7060b57cec5SDimitry Andric } else { 7070b57cec5SDimitry Andric addGOTMemOperand(MIB); 7080b57cec5SDimitry Andric } 7090b57cec5SDimitry Andric } 7100b57cec5SDimitry Andric 7110b57cec5SDimitry Andric return constrainSelectedInstRegOperands(*MIB, TII, TRI, RBI); 7120b57cec5SDimitry Andric } 7130b57cec5SDimitry Andric 7140b57cec5SDimitry Andric bool isReadOnly = STI.getTargetLowering()->isReadOnly(GV); 7150b57cec5SDimitry Andric if (STI.isROPI() && isReadOnly) { 7160b57cec5SDimitry Andric unsigned Opc = UseMovt ? Opcodes.MOV_ga_pcrel : Opcodes.LDRLIT_ga_pcrel; 7170b57cec5SDimitry Andric MIB->setDesc(TII.get(Opc)); 7180b57cec5SDimitry Andric return constrainSelectedInstRegOperands(*MIB, TII, TRI, RBI); 7190b57cec5SDimitry Andric } 7200b57cec5SDimitry Andric if (STI.isRWPI() && !isReadOnly) { 7210b57cec5SDimitry Andric auto Offset = MRI.createVirtualRegister(&ARM::GPRRegClass); 7220b57cec5SDimitry Andric MachineInstrBuilder OffsetMIB; 7230b57cec5SDimitry Andric if (UseMovt) { 7240b57cec5SDimitry Andric OffsetMIB = BuildMI(MBB, *MIB, MIB->getDebugLoc(), 7250b57cec5SDimitry Andric TII.get(Opcodes.MOVi32imm), Offset); 7260b57cec5SDimitry Andric OffsetMIB.addGlobalAddress(GV, /*Offset*/ 0, ARMII::MO_SBREL); 7270b57cec5SDimitry Andric } else { 7280b57cec5SDimitry Andric // Load the offset from the constant pool. 7290b57cec5SDimitry Andric OffsetMIB = BuildMI(MBB, *MIB, MIB->getDebugLoc(), 7300b57cec5SDimitry Andric TII.get(Opcodes.ConstPoolLoad), Offset); 7310b57cec5SDimitry Andric addOpsForConstantPoolLoad(OffsetMIB, GV, /*IsSBREL*/ true); 7320b57cec5SDimitry Andric } 7330b57cec5SDimitry Andric if (!constrainSelectedInstRegOperands(*OffsetMIB, TII, TRI, RBI)) 7340b57cec5SDimitry Andric return false; 7350b57cec5SDimitry Andric 7360b57cec5SDimitry Andric // Add the offset to the SB register. 7370b57cec5SDimitry Andric MIB->setDesc(TII.get(Opcodes.ADDrr)); 73881ad6265SDimitry Andric MIB->removeOperand(1); 7390b57cec5SDimitry Andric MIB.addReg(ARM::R9) // FIXME: don't hardcode R9 7400b57cec5SDimitry Andric .addReg(Offset) 7410b57cec5SDimitry Andric .add(predOps(ARMCC::AL)) 7420b57cec5SDimitry Andric .add(condCodeOp()); 7430b57cec5SDimitry Andric 7440b57cec5SDimitry Andric return constrainSelectedInstRegOperands(*MIB, TII, TRI, RBI); 7450b57cec5SDimitry Andric } 7460b57cec5SDimitry Andric 7470b57cec5SDimitry Andric if (STI.isTargetELF()) { 7480b57cec5SDimitry Andric if (UseMovt) { 7490b57cec5SDimitry Andric MIB->setDesc(TII.get(Opcodes.MOVi32imm)); 7500b57cec5SDimitry Andric } else { 7510b57cec5SDimitry Andric // Load the global's address from the constant pool. 7520b57cec5SDimitry Andric MIB->setDesc(TII.get(Opcodes.ConstPoolLoad)); 75381ad6265SDimitry Andric MIB->removeOperand(1); 7540b57cec5SDimitry Andric addOpsForConstantPoolLoad(MIB, GV, /*IsSBREL*/ false); 7550b57cec5SDimitry Andric } 7560b57cec5SDimitry Andric } else if (STI.isTargetMachO()) { 7570b57cec5SDimitry Andric if (UseMovt) 7580b57cec5SDimitry Andric MIB->setDesc(TII.get(Opcodes.MOVi32imm)); 7590b57cec5SDimitry Andric else 7600b57cec5SDimitry Andric MIB->setDesc(TII.get(Opcodes.LDRLIT_ga_abs)); 7610b57cec5SDimitry Andric } else { 7620b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Object format not supported yet\n"); 7630b57cec5SDimitry Andric return false; 7640b57cec5SDimitry Andric } 7650b57cec5SDimitry Andric 7660b57cec5SDimitry Andric return constrainSelectedInstRegOperands(*MIB, TII, TRI, RBI); 7670b57cec5SDimitry Andric } 7680b57cec5SDimitry Andric 7690b57cec5SDimitry Andric bool ARMInstructionSelector::selectSelect(MachineInstrBuilder &MIB, 7700b57cec5SDimitry Andric MachineRegisterInfo &MRI) const { 7710b57cec5SDimitry Andric auto &MBB = *MIB->getParent(); 7720b57cec5SDimitry Andric auto InsertBefore = std::next(MIB->getIterator()); 7730b57cec5SDimitry Andric auto &DbgLoc = MIB->getDebugLoc(); 7740b57cec5SDimitry Andric 7750b57cec5SDimitry Andric // Compare the condition to 1. 7765ffd83dbSDimitry Andric auto CondReg = MIB.getReg(1); 7770b57cec5SDimitry Andric assert(validReg(MRI, CondReg, 1, ARM::GPRRegBankID) && 7780b57cec5SDimitry Andric "Unsupported types for select operation"); 7790b57cec5SDimitry Andric auto CmpI = BuildMI(MBB, InsertBefore, DbgLoc, TII.get(Opcodes.TSTri)) 7800b57cec5SDimitry Andric .addUse(CondReg) 7810b57cec5SDimitry Andric .addImm(1) 7820b57cec5SDimitry Andric .add(predOps(ARMCC::AL)); 7830b57cec5SDimitry Andric if (!constrainSelectedInstRegOperands(*CmpI, TII, TRI, RBI)) 7840b57cec5SDimitry Andric return false; 7850b57cec5SDimitry Andric 7860b57cec5SDimitry Andric // Move a value into the result register based on the result of the 7870b57cec5SDimitry Andric // comparison. 7885ffd83dbSDimitry Andric auto ResReg = MIB.getReg(0); 7895ffd83dbSDimitry Andric auto TrueReg = MIB.getReg(2); 7905ffd83dbSDimitry Andric auto FalseReg = MIB.getReg(3); 7910b57cec5SDimitry Andric assert(validOpRegPair(MRI, ResReg, TrueReg, 32, ARM::GPRRegBankID) && 7920b57cec5SDimitry Andric validOpRegPair(MRI, TrueReg, FalseReg, 32, ARM::GPRRegBankID) && 7930b57cec5SDimitry Andric "Unsupported types for select operation"); 7940b57cec5SDimitry Andric auto Mov1I = BuildMI(MBB, InsertBefore, DbgLoc, TII.get(Opcodes.MOVCCr)) 7950b57cec5SDimitry Andric .addDef(ResReg) 7960b57cec5SDimitry Andric .addUse(TrueReg) 7970b57cec5SDimitry Andric .addUse(FalseReg) 7980b57cec5SDimitry Andric .add(predOps(ARMCC::EQ, ARM::CPSR)); 7990b57cec5SDimitry Andric if (!constrainSelectedInstRegOperands(*Mov1I, TII, TRI, RBI)) 8000b57cec5SDimitry Andric return false; 8010b57cec5SDimitry Andric 8020b57cec5SDimitry Andric MIB->eraseFromParent(); 8030b57cec5SDimitry Andric return true; 8040b57cec5SDimitry Andric } 8050b57cec5SDimitry Andric 8060b57cec5SDimitry Andric bool ARMInstructionSelector::selectShift(unsigned ShiftOpc, 8070b57cec5SDimitry Andric MachineInstrBuilder &MIB) const { 8080b57cec5SDimitry Andric assert(!STI.isThumb() && "Unsupported subtarget"); 8090b57cec5SDimitry Andric MIB->setDesc(TII.get(ARM::MOVsr)); 8100b57cec5SDimitry Andric MIB.addImm(ShiftOpc); 8110b57cec5SDimitry Andric MIB.add(predOps(ARMCC::AL)).add(condCodeOp()); 8120b57cec5SDimitry Andric return constrainSelectedInstRegOperands(*MIB, TII, TRI, RBI); 8130b57cec5SDimitry Andric } 8140b57cec5SDimitry Andric 8150b57cec5SDimitry Andric void ARMInstructionSelector::renderVFPF32Imm( 816480093f4SDimitry Andric MachineInstrBuilder &NewInstBuilder, const MachineInstr &OldInst, 817480093f4SDimitry Andric int OpIdx) const { 8180b57cec5SDimitry Andric assert(OldInst.getOpcode() == TargetOpcode::G_FCONSTANT && 819480093f4SDimitry Andric OpIdx == -1 && "Expected G_FCONSTANT"); 8200b57cec5SDimitry Andric 8210b57cec5SDimitry Andric APFloat FPImmValue = OldInst.getOperand(1).getFPImm()->getValueAPF(); 8220b57cec5SDimitry Andric int FPImmEncoding = ARM_AM::getFP32Imm(FPImmValue); 8230b57cec5SDimitry Andric assert(FPImmEncoding != -1 && "Invalid immediate value"); 8240b57cec5SDimitry Andric 8250b57cec5SDimitry Andric NewInstBuilder.addImm(FPImmEncoding); 8260b57cec5SDimitry Andric } 8270b57cec5SDimitry Andric 8280b57cec5SDimitry Andric void ARMInstructionSelector::renderVFPF64Imm( 829480093f4SDimitry Andric MachineInstrBuilder &NewInstBuilder, const MachineInstr &OldInst, int OpIdx) const { 8300b57cec5SDimitry Andric assert(OldInst.getOpcode() == TargetOpcode::G_FCONSTANT && 831480093f4SDimitry Andric OpIdx == -1 && "Expected G_FCONSTANT"); 8320b57cec5SDimitry Andric 8330b57cec5SDimitry Andric APFloat FPImmValue = OldInst.getOperand(1).getFPImm()->getValueAPF(); 8340b57cec5SDimitry Andric int FPImmEncoding = ARM_AM::getFP64Imm(FPImmValue); 8350b57cec5SDimitry Andric assert(FPImmEncoding != -1 && "Invalid immediate value"); 8360b57cec5SDimitry Andric 8370b57cec5SDimitry Andric NewInstBuilder.addImm(FPImmEncoding); 8380b57cec5SDimitry Andric } 8390b57cec5SDimitry Andric 840*0fca6ea1SDimitry Andric void ARMInstructionSelector::renderInvertedImm(MachineInstrBuilder &MIB, 841*0fca6ea1SDimitry Andric const MachineInstr &MI, 842*0fca6ea1SDimitry Andric int OpIdx) const { 843*0fca6ea1SDimitry Andric assert(MI.getOpcode() == TargetOpcode::G_CONSTANT && OpIdx == -1 && 844*0fca6ea1SDimitry Andric "Expected G_CONSTANT"); 845*0fca6ea1SDimitry Andric int64_t CVal = MI.getOperand(1).getCImm()->getSExtValue(); 846*0fca6ea1SDimitry Andric MIB.addImm(~CVal); 847*0fca6ea1SDimitry Andric } 848*0fca6ea1SDimitry Andric 8498bcb0991SDimitry Andric bool ARMInstructionSelector::select(MachineInstr &I) { 8500b57cec5SDimitry Andric assert(I.getParent() && "Instruction should be in a basic block!"); 8510b57cec5SDimitry Andric assert(I.getParent()->getParent() && "Instruction should be in a function!"); 8520b57cec5SDimitry Andric 8530b57cec5SDimitry Andric auto &MBB = *I.getParent(); 8540b57cec5SDimitry Andric auto &MF = *MBB.getParent(); 8550b57cec5SDimitry Andric auto &MRI = MF.getRegInfo(); 8560b57cec5SDimitry Andric 8570b57cec5SDimitry Andric if (!isPreISelGenericOpcode(I.getOpcode())) { 8580b57cec5SDimitry Andric if (I.isCopy()) 8590b57cec5SDimitry Andric return selectCopy(I, TII, MRI, TRI, RBI); 8600b57cec5SDimitry Andric 8610b57cec5SDimitry Andric return true; 8620b57cec5SDimitry Andric } 8630b57cec5SDimitry Andric 8640b57cec5SDimitry Andric using namespace TargetOpcode; 8650b57cec5SDimitry Andric 8668bcb0991SDimitry Andric if (selectImpl(I, *CoverageInfo)) 8670b57cec5SDimitry Andric return true; 8680b57cec5SDimitry Andric 8690b57cec5SDimitry Andric MachineInstrBuilder MIB{MF, I}; 8700b57cec5SDimitry Andric bool isSExt = false; 8710b57cec5SDimitry Andric 8720b57cec5SDimitry Andric switch (I.getOpcode()) { 8730b57cec5SDimitry Andric case G_SEXT: 8740b57cec5SDimitry Andric isSExt = true; 875bdd1243dSDimitry Andric [[fallthrough]]; 8760b57cec5SDimitry Andric case G_ZEXT: { 8770b57cec5SDimitry Andric assert(MRI.getType(I.getOperand(0).getReg()).getSizeInBits() <= 32 && 8780b57cec5SDimitry Andric "Unsupported destination size for extension"); 8790b57cec5SDimitry Andric 8800b57cec5SDimitry Andric LLT SrcTy = MRI.getType(I.getOperand(1).getReg()); 8810b57cec5SDimitry Andric unsigned SrcSize = SrcTy.getSizeInBits(); 8820b57cec5SDimitry Andric switch (SrcSize) { 8830b57cec5SDimitry Andric case 1: { 8840b57cec5SDimitry Andric // ZExt boils down to & 0x1; for SExt we also subtract that from 0 8850b57cec5SDimitry Andric I.setDesc(TII.get(Opcodes.AND)); 8860b57cec5SDimitry Andric MIB.addImm(1).add(predOps(ARMCC::AL)).add(condCodeOp()); 8870b57cec5SDimitry Andric 8880b57cec5SDimitry Andric if (isSExt) { 8898bcb0991SDimitry Andric Register SExtResult = I.getOperand(0).getReg(); 8900b57cec5SDimitry Andric 8910b57cec5SDimitry Andric // Use a new virtual register for the result of the AND 8928bcb0991SDimitry Andric Register AndResult = MRI.createVirtualRegister(&ARM::GPRRegClass); 8930b57cec5SDimitry Andric I.getOperand(0).setReg(AndResult); 8940b57cec5SDimitry Andric 8950b57cec5SDimitry Andric auto InsertBefore = std::next(I.getIterator()); 8960b57cec5SDimitry Andric auto SubI = 8970b57cec5SDimitry Andric BuildMI(MBB, InsertBefore, I.getDebugLoc(), TII.get(Opcodes.RSB)) 8980b57cec5SDimitry Andric .addDef(SExtResult) 8990b57cec5SDimitry Andric .addUse(AndResult) 9000b57cec5SDimitry Andric .addImm(0) 9010b57cec5SDimitry Andric .add(predOps(ARMCC::AL)) 9020b57cec5SDimitry Andric .add(condCodeOp()); 9030b57cec5SDimitry Andric if (!constrainSelectedInstRegOperands(*SubI, TII, TRI, RBI)) 9040b57cec5SDimitry Andric return false; 9050b57cec5SDimitry Andric } 9060b57cec5SDimitry Andric break; 9070b57cec5SDimitry Andric } 9080b57cec5SDimitry Andric case 8: 9090b57cec5SDimitry Andric case 16: { 9100b57cec5SDimitry Andric unsigned NewOpc = selectSimpleExtOpc(I.getOpcode(), SrcSize); 9110b57cec5SDimitry Andric if (NewOpc == I.getOpcode()) 9120b57cec5SDimitry Andric return false; 9130b57cec5SDimitry Andric I.setDesc(TII.get(NewOpc)); 9140b57cec5SDimitry Andric MIB.addImm(0).add(predOps(ARMCC::AL)); 9150b57cec5SDimitry Andric break; 9160b57cec5SDimitry Andric } 9170b57cec5SDimitry Andric default: 9180b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Unsupported source size for extension"); 9190b57cec5SDimitry Andric return false; 9200b57cec5SDimitry Andric } 9210b57cec5SDimitry Andric break; 9220b57cec5SDimitry Andric } 9230b57cec5SDimitry Andric case G_ANYEXT: 9240b57cec5SDimitry Andric case G_TRUNC: { 9250b57cec5SDimitry Andric // The high bits are undefined, so there's nothing special to do, just 9260b57cec5SDimitry Andric // treat it as a copy. 9270b57cec5SDimitry Andric auto SrcReg = I.getOperand(1).getReg(); 9280b57cec5SDimitry Andric auto DstReg = I.getOperand(0).getReg(); 9290b57cec5SDimitry Andric 9300b57cec5SDimitry Andric const auto &SrcRegBank = *RBI.getRegBank(SrcReg, MRI, TRI); 9310b57cec5SDimitry Andric const auto &DstRegBank = *RBI.getRegBank(DstReg, MRI, TRI); 9320b57cec5SDimitry Andric 9330b57cec5SDimitry Andric if (SrcRegBank.getID() == ARM::FPRRegBankID) { 9340b57cec5SDimitry Andric // This should only happen in the obscure case where we have put a 64-bit 9350b57cec5SDimitry Andric // integer into a D register. Get it out of there and keep only the 9360b57cec5SDimitry Andric // interesting part. 9370b57cec5SDimitry Andric assert(I.getOpcode() == G_TRUNC && "Unsupported operand for G_ANYEXT"); 9380b57cec5SDimitry Andric assert(DstRegBank.getID() == ARM::GPRRegBankID && 9390b57cec5SDimitry Andric "Unsupported combination of register banks"); 9400b57cec5SDimitry Andric assert(MRI.getType(SrcReg).getSizeInBits() == 64 && "Unsupported size"); 9410b57cec5SDimitry Andric assert(MRI.getType(DstReg).getSizeInBits() <= 32 && "Unsupported size"); 9420b57cec5SDimitry Andric 9438bcb0991SDimitry Andric Register IgnoredBits = MRI.createVirtualRegister(&ARM::GPRRegClass); 9440b57cec5SDimitry Andric auto InsertBefore = std::next(I.getIterator()); 9450b57cec5SDimitry Andric auto MovI = 9460b57cec5SDimitry Andric BuildMI(MBB, InsertBefore, I.getDebugLoc(), TII.get(ARM::VMOVRRD)) 9470b57cec5SDimitry Andric .addDef(DstReg) 9480b57cec5SDimitry Andric .addDef(IgnoredBits) 9490b57cec5SDimitry Andric .addUse(SrcReg) 9500b57cec5SDimitry Andric .add(predOps(ARMCC::AL)); 9510b57cec5SDimitry Andric if (!constrainSelectedInstRegOperands(*MovI, TII, TRI, RBI)) 9520b57cec5SDimitry Andric return false; 9530b57cec5SDimitry Andric 9540b57cec5SDimitry Andric MIB->eraseFromParent(); 9550b57cec5SDimitry Andric return true; 9560b57cec5SDimitry Andric } 9570b57cec5SDimitry Andric 9580b57cec5SDimitry Andric if (SrcRegBank.getID() != DstRegBank.getID()) { 9590b57cec5SDimitry Andric LLVM_DEBUG( 9600b57cec5SDimitry Andric dbgs() << "G_TRUNC/G_ANYEXT operands on different register banks\n"); 9610b57cec5SDimitry Andric return false; 9620b57cec5SDimitry Andric } 9630b57cec5SDimitry Andric 9640b57cec5SDimitry Andric if (SrcRegBank.getID() != ARM::GPRRegBankID) { 9650b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "G_TRUNC/G_ANYEXT on non-GPR not supported yet\n"); 9660b57cec5SDimitry Andric return false; 9670b57cec5SDimitry Andric } 9680b57cec5SDimitry Andric 9690b57cec5SDimitry Andric I.setDesc(TII.get(COPY)); 9700b57cec5SDimitry Andric return selectCopy(I, TII, MRI, TRI, RBI); 9710b57cec5SDimitry Andric } 9720b57cec5SDimitry Andric case G_CONSTANT: { 9730b57cec5SDimitry Andric if (!MRI.getType(I.getOperand(0).getReg()).isPointer()) { 9740b57cec5SDimitry Andric // Non-pointer constants should be handled by TableGen. 9750b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Unsupported constant type\n"); 9760b57cec5SDimitry Andric return false; 9770b57cec5SDimitry Andric } 9780b57cec5SDimitry Andric 9790b57cec5SDimitry Andric auto &Val = I.getOperand(1); 9800b57cec5SDimitry Andric if (Val.isCImm()) { 9810b57cec5SDimitry Andric if (!Val.getCImm()->isZero()) { 9820b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Unsupported pointer constant value\n"); 9830b57cec5SDimitry Andric return false; 9840b57cec5SDimitry Andric } 9850b57cec5SDimitry Andric Val.ChangeToImmediate(0); 9860b57cec5SDimitry Andric } else { 9870b57cec5SDimitry Andric assert(Val.isImm() && "Unexpected operand for G_CONSTANT"); 9880b57cec5SDimitry Andric if (Val.getImm() != 0) { 9890b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Unsupported pointer constant value\n"); 9900b57cec5SDimitry Andric return false; 9910b57cec5SDimitry Andric } 9920b57cec5SDimitry Andric } 9930b57cec5SDimitry Andric 9940b57cec5SDimitry Andric assert(!STI.isThumb() && "Unsupported subtarget"); 9950b57cec5SDimitry Andric I.setDesc(TII.get(ARM::MOVi)); 9960b57cec5SDimitry Andric MIB.add(predOps(ARMCC::AL)).add(condCodeOp()); 9970b57cec5SDimitry Andric break; 9980b57cec5SDimitry Andric } 9990b57cec5SDimitry Andric case G_FCONSTANT: { 10000b57cec5SDimitry Andric // Load from constant pool 10010b57cec5SDimitry Andric unsigned Size = MRI.getType(I.getOperand(0).getReg()).getSizeInBits() / 8; 10025ffd83dbSDimitry Andric Align Alignment(Size); 10030b57cec5SDimitry Andric 10040b57cec5SDimitry Andric assert((Size == 4 || Size == 8) && "Unsupported FP constant type"); 10050b57cec5SDimitry Andric auto LoadOpcode = Size == 4 ? ARM::VLDRS : ARM::VLDRD; 10060b57cec5SDimitry Andric 10070b57cec5SDimitry Andric auto ConstPool = MF.getConstantPool(); 10080b57cec5SDimitry Andric auto CPIndex = 10090b57cec5SDimitry Andric ConstPool->getConstantPoolIndex(I.getOperand(1).getFPImm(), Alignment); 10100b57cec5SDimitry Andric MIB->setDesc(TII.get(LoadOpcode)); 101181ad6265SDimitry Andric MIB->removeOperand(1); 10120b57cec5SDimitry Andric MIB.addConstantPoolIndex(CPIndex, /*Offset*/ 0, /*TargetFlags*/ 0) 10130b57cec5SDimitry Andric .addMemOperand( 10140b57cec5SDimitry Andric MF.getMachineMemOperand(MachinePointerInfo::getConstantPool(MF), 10150b57cec5SDimitry Andric MachineMemOperand::MOLoad, Size, Alignment)) 10160b57cec5SDimitry Andric .addImm(0) 10170b57cec5SDimitry Andric .add(predOps(ARMCC::AL)); 10180b57cec5SDimitry Andric break; 10190b57cec5SDimitry Andric } 10200b57cec5SDimitry Andric case G_INTTOPTR: 10210b57cec5SDimitry Andric case G_PTRTOINT: { 10220b57cec5SDimitry Andric auto SrcReg = I.getOperand(1).getReg(); 10230b57cec5SDimitry Andric auto DstReg = I.getOperand(0).getReg(); 10240b57cec5SDimitry Andric 10250b57cec5SDimitry Andric const auto &SrcRegBank = *RBI.getRegBank(SrcReg, MRI, TRI); 10260b57cec5SDimitry Andric const auto &DstRegBank = *RBI.getRegBank(DstReg, MRI, TRI); 10270b57cec5SDimitry Andric 10280b57cec5SDimitry Andric if (SrcRegBank.getID() != DstRegBank.getID()) { 10290b57cec5SDimitry Andric LLVM_DEBUG( 10300b57cec5SDimitry Andric dbgs() 10310b57cec5SDimitry Andric << "G_INTTOPTR/G_PTRTOINT operands on different register banks\n"); 10320b57cec5SDimitry Andric return false; 10330b57cec5SDimitry Andric } 10340b57cec5SDimitry Andric 10350b57cec5SDimitry Andric if (SrcRegBank.getID() != ARM::GPRRegBankID) { 10360b57cec5SDimitry Andric LLVM_DEBUG( 10370b57cec5SDimitry Andric dbgs() << "G_INTTOPTR/G_PTRTOINT on non-GPR not supported yet\n"); 10380b57cec5SDimitry Andric return false; 10390b57cec5SDimitry Andric } 10400b57cec5SDimitry Andric 10410b57cec5SDimitry Andric I.setDesc(TII.get(COPY)); 10420b57cec5SDimitry Andric return selectCopy(I, TII, MRI, TRI, RBI); 10430b57cec5SDimitry Andric } 10440b57cec5SDimitry Andric case G_SELECT: 10450b57cec5SDimitry Andric return selectSelect(MIB, MRI); 10460b57cec5SDimitry Andric case G_ICMP: { 10470b57cec5SDimitry Andric CmpConstants Helper(Opcodes.CMPrr, ARM::INSTRUCTION_LIST_END, 10480b57cec5SDimitry Andric Opcodes.MOVCCi, ARM::GPRRegBankID, 32); 10490b57cec5SDimitry Andric return selectCmp(Helper, MIB, MRI); 10500b57cec5SDimitry Andric } 10510b57cec5SDimitry Andric case G_FCMP: { 10520b57cec5SDimitry Andric assert(STI.hasVFP2Base() && "Can't select fcmp without VFP"); 10530b57cec5SDimitry Andric 10548bcb0991SDimitry Andric Register OpReg = I.getOperand(2).getReg(); 10550b57cec5SDimitry Andric unsigned Size = MRI.getType(OpReg).getSizeInBits(); 10560b57cec5SDimitry Andric 10570b57cec5SDimitry Andric if (Size == 64 && !STI.hasFP64()) { 10580b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Subtarget only supports single precision"); 10590b57cec5SDimitry Andric return false; 10600b57cec5SDimitry Andric } 10610b57cec5SDimitry Andric if (Size != 32 && Size != 64) { 10620b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Unsupported size for G_FCMP operand"); 10630b57cec5SDimitry Andric return false; 10640b57cec5SDimitry Andric } 10650b57cec5SDimitry Andric 10660b57cec5SDimitry Andric CmpConstants Helper(Size == 32 ? ARM::VCMPS : ARM::VCMPD, ARM::FMSTAT, 10670b57cec5SDimitry Andric Opcodes.MOVCCi, ARM::FPRRegBankID, Size); 10680b57cec5SDimitry Andric return selectCmp(Helper, MIB, MRI); 10690b57cec5SDimitry Andric } 10700b57cec5SDimitry Andric case G_LSHR: 10710b57cec5SDimitry Andric return selectShift(ARM_AM::ShiftOpc::lsr, MIB); 10720b57cec5SDimitry Andric case G_ASHR: 10730b57cec5SDimitry Andric return selectShift(ARM_AM::ShiftOpc::asr, MIB); 10740b57cec5SDimitry Andric case G_SHL: { 10750b57cec5SDimitry Andric return selectShift(ARM_AM::ShiftOpc::lsl, MIB); 10760b57cec5SDimitry Andric } 1077480093f4SDimitry Andric case G_PTR_ADD: 10780b57cec5SDimitry Andric I.setDesc(TII.get(Opcodes.ADDrr)); 10790b57cec5SDimitry Andric MIB.add(predOps(ARMCC::AL)).add(condCodeOp()); 10800b57cec5SDimitry Andric break; 10810b57cec5SDimitry Andric case G_FRAME_INDEX: 10820b57cec5SDimitry Andric // Add 0 to the given frame index and hope it will eventually be folded into 10830b57cec5SDimitry Andric // the user(s). 10840b57cec5SDimitry Andric I.setDesc(TII.get(Opcodes.ADDri)); 10850b57cec5SDimitry Andric MIB.addImm(0).add(predOps(ARMCC::AL)).add(condCodeOp()); 10860b57cec5SDimitry Andric break; 10870b57cec5SDimitry Andric case G_GLOBAL_VALUE: 10880b57cec5SDimitry Andric return selectGlobal(MIB, MRI); 10890b57cec5SDimitry Andric case G_STORE: 10900b57cec5SDimitry Andric case G_LOAD: { 10910b57cec5SDimitry Andric const auto &MemOp = **I.memoperands_begin(); 10928bcb0991SDimitry Andric if (MemOp.isAtomic()) { 10930b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Atomic load/store not supported yet\n"); 10940b57cec5SDimitry Andric return false; 10950b57cec5SDimitry Andric } 10960b57cec5SDimitry Andric 10978bcb0991SDimitry Andric Register Reg = I.getOperand(0).getReg(); 10980b57cec5SDimitry Andric unsigned RegBank = RBI.getRegBank(Reg, MRI, TRI)->getID(); 10990b57cec5SDimitry Andric 11000b57cec5SDimitry Andric LLT ValTy = MRI.getType(Reg); 11010b57cec5SDimitry Andric const auto ValSize = ValTy.getSizeInBits(); 11020b57cec5SDimitry Andric 11030b57cec5SDimitry Andric assert((ValSize != 64 || STI.hasVFP2Base()) && 11040b57cec5SDimitry Andric "Don't know how to load/store 64-bit value without VFP"); 11050b57cec5SDimitry Andric 11060b57cec5SDimitry Andric const auto NewOpc = selectLoadStoreOpCode(I.getOpcode(), RegBank, ValSize); 11070b57cec5SDimitry Andric if (NewOpc == G_LOAD || NewOpc == G_STORE) 11080b57cec5SDimitry Andric return false; 11090b57cec5SDimitry Andric 11100b57cec5SDimitry Andric I.setDesc(TII.get(NewOpc)); 11110b57cec5SDimitry Andric 11120b57cec5SDimitry Andric if (NewOpc == ARM::LDRH || NewOpc == ARM::STRH) 11130b57cec5SDimitry Andric // LDRH has a funny addressing mode (there's already a FIXME for it). 11140b57cec5SDimitry Andric MIB.addReg(0); 11150b57cec5SDimitry Andric MIB.addImm(0).add(predOps(ARMCC::AL)); 11160b57cec5SDimitry Andric break; 11170b57cec5SDimitry Andric } 11180b57cec5SDimitry Andric case G_MERGE_VALUES: { 11190b57cec5SDimitry Andric if (!selectMergeValues(MIB, TII, MRI, TRI, RBI)) 11200b57cec5SDimitry Andric return false; 11210b57cec5SDimitry Andric break; 11220b57cec5SDimitry Andric } 11230b57cec5SDimitry Andric case G_UNMERGE_VALUES: { 11240b57cec5SDimitry Andric if (!selectUnmergeValues(MIB, TII, MRI, TRI, RBI)) 11250b57cec5SDimitry Andric return false; 11260b57cec5SDimitry Andric break; 11270b57cec5SDimitry Andric } 11280b57cec5SDimitry Andric case G_BRCOND: { 11290b57cec5SDimitry Andric if (!validReg(MRI, I.getOperand(0).getReg(), 1, ARM::GPRRegBankID)) { 11300b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Unsupported condition register for G_BRCOND"); 11310b57cec5SDimitry Andric return false; 11320b57cec5SDimitry Andric } 11330b57cec5SDimitry Andric 11340b57cec5SDimitry Andric // Set the flags. 11350b57cec5SDimitry Andric auto Test = 11360b57cec5SDimitry Andric BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(Opcodes.TSTri)) 11370b57cec5SDimitry Andric .addReg(I.getOperand(0).getReg()) 11380b57cec5SDimitry Andric .addImm(1) 11390b57cec5SDimitry Andric .add(predOps(ARMCC::AL)); 11400b57cec5SDimitry Andric if (!constrainSelectedInstRegOperands(*Test, TII, TRI, RBI)) 11410b57cec5SDimitry Andric return false; 11420b57cec5SDimitry Andric 11430b57cec5SDimitry Andric // Branch conditionally. 11440b57cec5SDimitry Andric auto Branch = 11450b57cec5SDimitry Andric BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(Opcodes.Bcc)) 11460b57cec5SDimitry Andric .add(I.getOperand(1)) 11470b57cec5SDimitry Andric .add(predOps(ARMCC::NE, ARM::CPSR)); 11480b57cec5SDimitry Andric if (!constrainSelectedInstRegOperands(*Branch, TII, TRI, RBI)) 11490b57cec5SDimitry Andric return false; 11500b57cec5SDimitry Andric I.eraseFromParent(); 11510b57cec5SDimitry Andric return true; 11520b57cec5SDimitry Andric } 11530b57cec5SDimitry Andric case G_PHI: { 11540b57cec5SDimitry Andric I.setDesc(TII.get(PHI)); 11550b57cec5SDimitry Andric 11568bcb0991SDimitry Andric Register DstReg = I.getOperand(0).getReg(); 11570b57cec5SDimitry Andric const TargetRegisterClass *RC = guessRegClass(DstReg, MRI, TRI, RBI); 11580b57cec5SDimitry Andric if (!RBI.constrainGenericRegister(DstReg, *RC, MRI)) { 11590b57cec5SDimitry Andric break; 11600b57cec5SDimitry Andric } 11610b57cec5SDimitry Andric 11620b57cec5SDimitry Andric return true; 11630b57cec5SDimitry Andric } 11640b57cec5SDimitry Andric default: 11650b57cec5SDimitry Andric return false; 11660b57cec5SDimitry Andric } 11670b57cec5SDimitry Andric 11680b57cec5SDimitry Andric return constrainSelectedInstRegOperands(I, TII, TRI, RBI); 11690b57cec5SDimitry Andric } 1170