15f757f3fSDimitry Andric //===- X86InstructionSelector.cpp -----------------------------------------===// 25f757f3fSDimitry Andric // 35f757f3fSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 45f757f3fSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 55f757f3fSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 65f757f3fSDimitry Andric // 75f757f3fSDimitry Andric //===----------------------------------------------------------------------===// 85f757f3fSDimitry Andric /// \file 95f757f3fSDimitry Andric /// This file implements the targeting of the InstructionSelector class for 105f757f3fSDimitry Andric /// X86. 115f757f3fSDimitry Andric /// \todo This should be generated by TableGen. 125f757f3fSDimitry Andric //===----------------------------------------------------------------------===// 135f757f3fSDimitry Andric 145f757f3fSDimitry Andric #include "MCTargetDesc/X86BaseInfo.h" 155f757f3fSDimitry Andric #include "X86.h" 165f757f3fSDimitry Andric #include "X86InstrBuilder.h" 175f757f3fSDimitry Andric #include "X86InstrInfo.h" 185f757f3fSDimitry Andric #include "X86RegisterBankInfo.h" 195f757f3fSDimitry Andric #include "X86RegisterInfo.h" 205f757f3fSDimitry Andric #include "X86Subtarget.h" 215f757f3fSDimitry Andric #include "X86TargetMachine.h" 225f757f3fSDimitry Andric #include "llvm/CodeGen/GlobalISel/GIMatchTableExecutorImpl.h" 235f757f3fSDimitry Andric #include "llvm/CodeGen/GlobalISel/GenericMachineInstrs.h" 245f757f3fSDimitry Andric #include "llvm/CodeGen/GlobalISel/InstructionSelector.h" 255f757f3fSDimitry Andric #include "llvm/CodeGen/GlobalISel/Utils.h" 265f757f3fSDimitry Andric #include "llvm/CodeGen/MachineBasicBlock.h" 275f757f3fSDimitry Andric #include "llvm/CodeGen/MachineConstantPool.h" 285f757f3fSDimitry Andric #include "llvm/CodeGen/MachineFunction.h" 295f757f3fSDimitry Andric #include "llvm/CodeGen/MachineInstr.h" 305f757f3fSDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h" 315f757f3fSDimitry Andric #include "llvm/CodeGen/MachineMemOperand.h" 325f757f3fSDimitry Andric #include "llvm/CodeGen/MachineOperand.h" 335f757f3fSDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h" 345f757f3fSDimitry Andric #include "llvm/CodeGen/RegisterBank.h" 355f757f3fSDimitry Andric #include "llvm/CodeGen/TargetOpcodes.h" 365f757f3fSDimitry Andric #include "llvm/CodeGen/TargetRegisterInfo.h" 37*0fca6ea1SDimitry Andric #include "llvm/CodeGenTypes/LowLevelType.h" 385f757f3fSDimitry Andric #include "llvm/IR/DataLayout.h" 395f757f3fSDimitry Andric #include "llvm/IR/InstrTypes.h" 405f757f3fSDimitry Andric #include "llvm/IR/IntrinsicsX86.h" 415f757f3fSDimitry Andric #include "llvm/Support/AtomicOrdering.h" 425f757f3fSDimitry Andric #include "llvm/Support/CodeGen.h" 435f757f3fSDimitry Andric #include "llvm/Support/Debug.h" 445f757f3fSDimitry Andric #include "llvm/Support/ErrorHandling.h" 455f757f3fSDimitry Andric #include "llvm/Support/MathExtras.h" 465f757f3fSDimitry Andric #include "llvm/Support/raw_ostream.h" 475f757f3fSDimitry Andric #include <cassert> 485f757f3fSDimitry Andric #include <cstdint> 495f757f3fSDimitry Andric #include <tuple> 505f757f3fSDimitry Andric 515f757f3fSDimitry Andric #define DEBUG_TYPE "X86-isel" 525f757f3fSDimitry Andric 535f757f3fSDimitry Andric using namespace llvm; 545f757f3fSDimitry Andric 555f757f3fSDimitry Andric namespace { 565f757f3fSDimitry Andric 575f757f3fSDimitry Andric #define GET_GLOBALISEL_PREDICATE_BITSET 585f757f3fSDimitry Andric #include "X86GenGlobalISel.inc" 595f757f3fSDimitry Andric #undef GET_GLOBALISEL_PREDICATE_BITSET 605f757f3fSDimitry Andric 615f757f3fSDimitry Andric class X86InstructionSelector : public InstructionSelector { 625f757f3fSDimitry Andric public: 635f757f3fSDimitry Andric X86InstructionSelector(const X86TargetMachine &TM, const X86Subtarget &STI, 645f757f3fSDimitry Andric const X86RegisterBankInfo &RBI); 655f757f3fSDimitry Andric 665f757f3fSDimitry Andric bool select(MachineInstr &I) override; 675f757f3fSDimitry Andric static const char *getName() { return DEBUG_TYPE; } 685f757f3fSDimitry Andric 695f757f3fSDimitry Andric private: 705f757f3fSDimitry Andric /// tblgen-erated 'select' implementation, used as the initial selector for 715f757f3fSDimitry Andric /// the patterns that don't require complex C++. 725f757f3fSDimitry Andric bool selectImpl(MachineInstr &I, CodeGenCoverage &CoverageInfo) const; 735f757f3fSDimitry Andric 745f757f3fSDimitry Andric // TODO: remove after supported by Tablegen-erated instruction selection. 755f757f3fSDimitry Andric unsigned getLoadStoreOp(const LLT &Ty, const RegisterBank &RB, unsigned Opc, 765f757f3fSDimitry Andric Align Alignment) const; 775f757f3fSDimitry Andric 785f757f3fSDimitry Andric bool selectLoadStoreOp(MachineInstr &I, MachineRegisterInfo &MRI, 795f757f3fSDimitry Andric MachineFunction &MF) const; 805f757f3fSDimitry Andric bool selectFrameIndexOrGep(MachineInstr &I, MachineRegisterInfo &MRI, 815f757f3fSDimitry Andric MachineFunction &MF) const; 825f757f3fSDimitry Andric bool selectGlobalValue(MachineInstr &I, MachineRegisterInfo &MRI, 835f757f3fSDimitry Andric MachineFunction &MF) const; 845f757f3fSDimitry Andric bool selectConstant(MachineInstr &I, MachineRegisterInfo &MRI, 855f757f3fSDimitry Andric MachineFunction &MF) const; 865f757f3fSDimitry Andric bool selectTruncOrPtrToInt(MachineInstr &I, MachineRegisterInfo &MRI, 875f757f3fSDimitry Andric MachineFunction &MF) const; 885f757f3fSDimitry Andric bool selectZext(MachineInstr &I, MachineRegisterInfo &MRI, 895f757f3fSDimitry Andric MachineFunction &MF) const; 905f757f3fSDimitry Andric bool selectAnyext(MachineInstr &I, MachineRegisterInfo &MRI, 915f757f3fSDimitry Andric MachineFunction &MF) const; 925f757f3fSDimitry Andric bool selectCmp(MachineInstr &I, MachineRegisterInfo &MRI, 935f757f3fSDimitry Andric MachineFunction &MF) const; 945f757f3fSDimitry Andric bool selectFCmp(MachineInstr &I, MachineRegisterInfo &MRI, 955f757f3fSDimitry Andric MachineFunction &MF) const; 965f757f3fSDimitry Andric bool selectUAddSub(MachineInstr &I, MachineRegisterInfo &MRI, 975f757f3fSDimitry Andric MachineFunction &MF) const; 985f757f3fSDimitry Andric bool selectDebugInstr(MachineInstr &I, MachineRegisterInfo &MRI) const; 995f757f3fSDimitry Andric bool selectCopy(MachineInstr &I, MachineRegisterInfo &MRI) const; 1005f757f3fSDimitry Andric bool selectUnmergeValues(MachineInstr &I, MachineRegisterInfo &MRI, 1015f757f3fSDimitry Andric MachineFunction &MF); 1025f757f3fSDimitry Andric bool selectMergeValues(MachineInstr &I, MachineRegisterInfo &MRI, 1035f757f3fSDimitry Andric MachineFunction &MF); 1045f757f3fSDimitry Andric bool selectInsert(MachineInstr &I, MachineRegisterInfo &MRI, 1055f757f3fSDimitry Andric MachineFunction &MF) const; 1065f757f3fSDimitry Andric bool selectExtract(MachineInstr &I, MachineRegisterInfo &MRI, 1075f757f3fSDimitry Andric MachineFunction &MF) const; 1085f757f3fSDimitry Andric bool selectCondBranch(MachineInstr &I, MachineRegisterInfo &MRI, 1095f757f3fSDimitry Andric MachineFunction &MF) const; 1105f757f3fSDimitry Andric bool selectTurnIntoCOPY(MachineInstr &I, MachineRegisterInfo &MRI, 1115f757f3fSDimitry Andric const unsigned DstReg, 1125f757f3fSDimitry Andric const TargetRegisterClass *DstRC, 1135f757f3fSDimitry Andric const unsigned SrcReg, 1145f757f3fSDimitry Andric const TargetRegisterClass *SrcRC) const; 1155f757f3fSDimitry Andric bool materializeFP(MachineInstr &I, MachineRegisterInfo &MRI, 1165f757f3fSDimitry Andric MachineFunction &MF) const; 1175f757f3fSDimitry Andric bool selectImplicitDefOrPHI(MachineInstr &I, MachineRegisterInfo &MRI) const; 1185f757f3fSDimitry Andric bool selectMulDivRem(MachineInstr &I, MachineRegisterInfo &MRI, 1195f757f3fSDimitry Andric MachineFunction &MF) const; 1205f757f3fSDimitry Andric bool selectSelect(MachineInstr &I, MachineRegisterInfo &MRI, 1215f757f3fSDimitry Andric MachineFunction &MF) const; 1225f757f3fSDimitry Andric 1235f757f3fSDimitry Andric // emit insert subreg instruction and insert it before MachineInstr &I 1245f757f3fSDimitry Andric bool emitInsertSubreg(unsigned DstReg, unsigned SrcReg, MachineInstr &I, 1255f757f3fSDimitry Andric MachineRegisterInfo &MRI, MachineFunction &MF) const; 1265f757f3fSDimitry Andric // emit extract subreg instruction and insert it before MachineInstr &I 1275f757f3fSDimitry Andric bool emitExtractSubreg(unsigned DstReg, unsigned SrcReg, MachineInstr &I, 1285f757f3fSDimitry Andric MachineRegisterInfo &MRI, MachineFunction &MF) const; 1295f757f3fSDimitry Andric 1305f757f3fSDimitry Andric const TargetRegisterClass *getRegClass(LLT Ty, const RegisterBank &RB) const; 1315f757f3fSDimitry Andric const TargetRegisterClass *getRegClass(LLT Ty, unsigned Reg, 1325f757f3fSDimitry Andric MachineRegisterInfo &MRI) const; 1335f757f3fSDimitry Andric 1345f757f3fSDimitry Andric const X86TargetMachine &TM; 1355f757f3fSDimitry Andric const X86Subtarget &STI; 1365f757f3fSDimitry Andric const X86InstrInfo &TII; 1375f757f3fSDimitry Andric const X86RegisterInfo &TRI; 1385f757f3fSDimitry Andric const X86RegisterBankInfo &RBI; 1395f757f3fSDimitry Andric 1405f757f3fSDimitry Andric #define GET_GLOBALISEL_PREDICATES_DECL 1415f757f3fSDimitry Andric #include "X86GenGlobalISel.inc" 1425f757f3fSDimitry Andric #undef GET_GLOBALISEL_PREDICATES_DECL 1435f757f3fSDimitry Andric 1445f757f3fSDimitry Andric #define GET_GLOBALISEL_TEMPORARIES_DECL 1455f757f3fSDimitry Andric #include "X86GenGlobalISel.inc" 1465f757f3fSDimitry Andric #undef GET_GLOBALISEL_TEMPORARIES_DECL 1475f757f3fSDimitry Andric }; 1485f757f3fSDimitry Andric 1495f757f3fSDimitry Andric } // end anonymous namespace 1505f757f3fSDimitry Andric 1515f757f3fSDimitry Andric #define GET_GLOBALISEL_IMPL 1525f757f3fSDimitry Andric #include "X86GenGlobalISel.inc" 1535f757f3fSDimitry Andric #undef GET_GLOBALISEL_IMPL 1545f757f3fSDimitry Andric 1555f757f3fSDimitry Andric X86InstructionSelector::X86InstructionSelector(const X86TargetMachine &TM, 1565f757f3fSDimitry Andric const X86Subtarget &STI, 1575f757f3fSDimitry Andric const X86RegisterBankInfo &RBI) 1585f757f3fSDimitry Andric : TM(TM), STI(STI), TII(*STI.getInstrInfo()), TRI(*STI.getRegisterInfo()), 1595f757f3fSDimitry Andric RBI(RBI), 1605f757f3fSDimitry Andric #define GET_GLOBALISEL_PREDICATES_INIT 1615f757f3fSDimitry Andric #include "X86GenGlobalISel.inc" 1625f757f3fSDimitry Andric #undef GET_GLOBALISEL_PREDICATES_INIT 1635f757f3fSDimitry Andric #define GET_GLOBALISEL_TEMPORARIES_INIT 1645f757f3fSDimitry Andric #include "X86GenGlobalISel.inc" 1655f757f3fSDimitry Andric #undef GET_GLOBALISEL_TEMPORARIES_INIT 1665f757f3fSDimitry Andric { 1675f757f3fSDimitry Andric } 1685f757f3fSDimitry Andric 1695f757f3fSDimitry Andric // FIXME: This should be target-independent, inferred from the types declared 1705f757f3fSDimitry Andric // for each class in the bank. 1715f757f3fSDimitry Andric const TargetRegisterClass * 1725f757f3fSDimitry Andric X86InstructionSelector::getRegClass(LLT Ty, const RegisterBank &RB) const { 1735f757f3fSDimitry Andric if (RB.getID() == X86::GPRRegBankID) { 1745f757f3fSDimitry Andric if (Ty.getSizeInBits() <= 8) 1755f757f3fSDimitry Andric return &X86::GR8RegClass; 1765f757f3fSDimitry Andric if (Ty.getSizeInBits() == 16) 1775f757f3fSDimitry Andric return &X86::GR16RegClass; 1785f757f3fSDimitry Andric if (Ty.getSizeInBits() == 32) 1795f757f3fSDimitry Andric return &X86::GR32RegClass; 1805f757f3fSDimitry Andric if (Ty.getSizeInBits() == 64) 1815f757f3fSDimitry Andric return &X86::GR64RegClass; 1825f757f3fSDimitry Andric } 1835f757f3fSDimitry Andric if (RB.getID() == X86::VECRRegBankID) { 1845f757f3fSDimitry Andric if (Ty.getSizeInBits() == 16) 1855f757f3fSDimitry Andric return STI.hasAVX512() ? &X86::FR16XRegClass : &X86::FR16RegClass; 1865f757f3fSDimitry Andric if (Ty.getSizeInBits() == 32) 1875f757f3fSDimitry Andric return STI.hasAVX512() ? &X86::FR32XRegClass : &X86::FR32RegClass; 1885f757f3fSDimitry Andric if (Ty.getSizeInBits() == 64) 1895f757f3fSDimitry Andric return STI.hasAVX512() ? &X86::FR64XRegClass : &X86::FR64RegClass; 1905f757f3fSDimitry Andric if (Ty.getSizeInBits() == 128) 1915f757f3fSDimitry Andric return STI.hasAVX512() ? &X86::VR128XRegClass : &X86::VR128RegClass; 1925f757f3fSDimitry Andric if (Ty.getSizeInBits() == 256) 1935f757f3fSDimitry Andric return STI.hasAVX512() ? &X86::VR256XRegClass : &X86::VR256RegClass; 1945f757f3fSDimitry Andric if (Ty.getSizeInBits() == 512) 1955f757f3fSDimitry Andric return &X86::VR512RegClass; 1965f757f3fSDimitry Andric } 1975f757f3fSDimitry Andric 198*0fca6ea1SDimitry Andric if (RB.getID() == X86::PSRRegBankID) { 199*0fca6ea1SDimitry Andric if (Ty.getSizeInBits() == 80) 200*0fca6ea1SDimitry Andric return &X86::RFP80RegClass; 201*0fca6ea1SDimitry Andric if (Ty.getSizeInBits() == 64) 202*0fca6ea1SDimitry Andric return &X86::RFP64RegClass; 203*0fca6ea1SDimitry Andric if (Ty.getSizeInBits() == 32) 204*0fca6ea1SDimitry Andric return &X86::RFP32RegClass; 205*0fca6ea1SDimitry Andric } 206*0fca6ea1SDimitry Andric 2075f757f3fSDimitry Andric llvm_unreachable("Unknown RegBank!"); 2085f757f3fSDimitry Andric } 2095f757f3fSDimitry Andric 2105f757f3fSDimitry Andric const TargetRegisterClass * 2115f757f3fSDimitry Andric X86InstructionSelector::getRegClass(LLT Ty, unsigned Reg, 2125f757f3fSDimitry Andric MachineRegisterInfo &MRI) const { 2135f757f3fSDimitry Andric const RegisterBank &RegBank = *RBI.getRegBank(Reg, MRI, TRI); 2145f757f3fSDimitry Andric return getRegClass(Ty, RegBank); 2155f757f3fSDimitry Andric } 2165f757f3fSDimitry Andric 2175f757f3fSDimitry Andric static unsigned getSubRegIndex(const TargetRegisterClass *RC) { 2185f757f3fSDimitry Andric unsigned SubIdx = X86::NoSubRegister; 2195f757f3fSDimitry Andric if (RC == &X86::GR32RegClass) { 2205f757f3fSDimitry Andric SubIdx = X86::sub_32bit; 2215f757f3fSDimitry Andric } else if (RC == &X86::GR16RegClass) { 2225f757f3fSDimitry Andric SubIdx = X86::sub_16bit; 2235f757f3fSDimitry Andric } else if (RC == &X86::GR8RegClass) { 2245f757f3fSDimitry Andric SubIdx = X86::sub_8bit; 2255f757f3fSDimitry Andric } 2265f757f3fSDimitry Andric 2275f757f3fSDimitry Andric return SubIdx; 2285f757f3fSDimitry Andric } 2295f757f3fSDimitry Andric 2305f757f3fSDimitry Andric static const TargetRegisterClass *getRegClassFromGRPhysReg(Register Reg) { 2315f757f3fSDimitry Andric assert(Reg.isPhysical()); 2325f757f3fSDimitry Andric if (X86::GR64RegClass.contains(Reg)) 2335f757f3fSDimitry Andric return &X86::GR64RegClass; 2345f757f3fSDimitry Andric if (X86::GR32RegClass.contains(Reg)) 2355f757f3fSDimitry Andric return &X86::GR32RegClass; 2365f757f3fSDimitry Andric if (X86::GR16RegClass.contains(Reg)) 2375f757f3fSDimitry Andric return &X86::GR16RegClass; 2385f757f3fSDimitry Andric if (X86::GR8RegClass.contains(Reg)) 2395f757f3fSDimitry Andric return &X86::GR8RegClass; 2405f757f3fSDimitry Andric 2415f757f3fSDimitry Andric llvm_unreachable("Unknown RegClass for PhysReg!"); 2425f757f3fSDimitry Andric } 2435f757f3fSDimitry Andric 2445f757f3fSDimitry Andric // FIXME: We need some sort of API in RBI/TRI to allow generic code to 2455f757f3fSDimitry Andric // constrain operands of simple instructions given a TargetRegisterClass 2465f757f3fSDimitry Andric // and LLT 2475f757f3fSDimitry Andric bool X86InstructionSelector::selectDebugInstr(MachineInstr &I, 2485f757f3fSDimitry Andric MachineRegisterInfo &MRI) const { 2495f757f3fSDimitry Andric for (MachineOperand &MO : I.operands()) { 2505f757f3fSDimitry Andric if (!MO.isReg()) 2515f757f3fSDimitry Andric continue; 2525f757f3fSDimitry Andric Register Reg = MO.getReg(); 2535f757f3fSDimitry Andric if (!Reg) 2545f757f3fSDimitry Andric continue; 2555f757f3fSDimitry Andric if (Reg.isPhysical()) 2565f757f3fSDimitry Andric continue; 2575f757f3fSDimitry Andric LLT Ty = MRI.getType(Reg); 2585f757f3fSDimitry Andric const RegClassOrRegBank &RegClassOrBank = MRI.getRegClassOrRegBank(Reg); 2595f757f3fSDimitry Andric const TargetRegisterClass *RC = 2605f757f3fSDimitry Andric dyn_cast_if_present<const TargetRegisterClass *>(RegClassOrBank); 2615f757f3fSDimitry Andric if (!RC) { 2625f757f3fSDimitry Andric const RegisterBank &RB = *cast<const RegisterBank *>(RegClassOrBank); 2635f757f3fSDimitry Andric RC = getRegClass(Ty, RB); 2645f757f3fSDimitry Andric if (!RC) { 2655f757f3fSDimitry Andric LLVM_DEBUG( 2665f757f3fSDimitry Andric dbgs() << "Warning: DBG_VALUE operand has unexpected size/bank\n"); 2675f757f3fSDimitry Andric break; 2685f757f3fSDimitry Andric } 2695f757f3fSDimitry Andric } 2705f757f3fSDimitry Andric RBI.constrainGenericRegister(Reg, *RC, MRI); 2715f757f3fSDimitry Andric } 2725f757f3fSDimitry Andric 2735f757f3fSDimitry Andric return true; 2745f757f3fSDimitry Andric } 2755f757f3fSDimitry Andric 2765f757f3fSDimitry Andric // Set X86 Opcode and constrain DestReg. 2775f757f3fSDimitry Andric bool X86InstructionSelector::selectCopy(MachineInstr &I, 2785f757f3fSDimitry Andric MachineRegisterInfo &MRI) const { 2795f757f3fSDimitry Andric Register DstReg = I.getOperand(0).getReg(); 2805f757f3fSDimitry Andric const unsigned DstSize = RBI.getSizeInBits(DstReg, MRI, TRI); 2815f757f3fSDimitry Andric const RegisterBank &DstRegBank = *RBI.getRegBank(DstReg, MRI, TRI); 2825f757f3fSDimitry Andric 2835f757f3fSDimitry Andric Register SrcReg = I.getOperand(1).getReg(); 2845f757f3fSDimitry Andric const unsigned SrcSize = RBI.getSizeInBits(SrcReg, MRI, TRI); 2855f757f3fSDimitry Andric const RegisterBank &SrcRegBank = *RBI.getRegBank(SrcReg, MRI, TRI); 2865f757f3fSDimitry Andric 2875f757f3fSDimitry Andric if (DstReg.isPhysical()) { 2885f757f3fSDimitry Andric assert(I.isCopy() && "Generic operators do not allow physical registers"); 2895f757f3fSDimitry Andric 2905f757f3fSDimitry Andric if (DstSize > SrcSize && SrcRegBank.getID() == X86::GPRRegBankID && 2915f757f3fSDimitry Andric DstRegBank.getID() == X86::GPRRegBankID) { 2925f757f3fSDimitry Andric 2935f757f3fSDimitry Andric const TargetRegisterClass *SrcRC = 2945f757f3fSDimitry Andric getRegClass(MRI.getType(SrcReg), SrcRegBank); 2955f757f3fSDimitry Andric const TargetRegisterClass *DstRC = getRegClassFromGRPhysReg(DstReg); 2965f757f3fSDimitry Andric 2975f757f3fSDimitry Andric if (SrcRC != DstRC) { 2985f757f3fSDimitry Andric // This case can be generated by ABI lowering, performe anyext 2995f757f3fSDimitry Andric Register ExtSrc = MRI.createVirtualRegister(DstRC); 3005f757f3fSDimitry Andric BuildMI(*I.getParent(), I, I.getDebugLoc(), 3015f757f3fSDimitry Andric TII.get(TargetOpcode::SUBREG_TO_REG)) 3025f757f3fSDimitry Andric .addDef(ExtSrc) 3035f757f3fSDimitry Andric .addImm(0) 3045f757f3fSDimitry Andric .addReg(SrcReg) 3055f757f3fSDimitry Andric .addImm(getSubRegIndex(SrcRC)); 3065f757f3fSDimitry Andric 3075f757f3fSDimitry Andric I.getOperand(1).setReg(ExtSrc); 3085f757f3fSDimitry Andric } 3095f757f3fSDimitry Andric } 3105f757f3fSDimitry Andric 3115f757f3fSDimitry Andric return true; 3125f757f3fSDimitry Andric } 3135f757f3fSDimitry Andric 3145f757f3fSDimitry Andric assert((!SrcReg.isPhysical() || I.isCopy()) && 3155f757f3fSDimitry Andric "No phys reg on generic operators"); 3165f757f3fSDimitry Andric assert((DstSize == SrcSize || 3175f757f3fSDimitry Andric // Copies are a mean to setup initial types, the number of 3185f757f3fSDimitry Andric // bits may not exactly match. 3195f757f3fSDimitry Andric (SrcReg.isPhysical() && 3205f757f3fSDimitry Andric DstSize <= RBI.getSizeInBits(SrcReg, MRI, TRI))) && 3215f757f3fSDimitry Andric "Copy with different width?!"); 3225f757f3fSDimitry Andric 3235f757f3fSDimitry Andric const TargetRegisterClass *DstRC = 3245f757f3fSDimitry Andric getRegClass(MRI.getType(DstReg), DstRegBank); 3255f757f3fSDimitry Andric 3265f757f3fSDimitry Andric if (SrcRegBank.getID() == X86::GPRRegBankID && 3275f757f3fSDimitry Andric DstRegBank.getID() == X86::GPRRegBankID && SrcSize > DstSize && 3285f757f3fSDimitry Andric SrcReg.isPhysical()) { 3295f757f3fSDimitry Andric // Change the physical register to performe truncate. 3305f757f3fSDimitry Andric 3315f757f3fSDimitry Andric const TargetRegisterClass *SrcRC = getRegClassFromGRPhysReg(SrcReg); 3325f757f3fSDimitry Andric 3335f757f3fSDimitry Andric if (DstRC != SrcRC) { 3345f757f3fSDimitry Andric I.getOperand(1).setSubReg(getSubRegIndex(DstRC)); 3355f757f3fSDimitry Andric I.getOperand(1).substPhysReg(SrcReg, TRI); 3365f757f3fSDimitry Andric } 3375f757f3fSDimitry Andric } 3385f757f3fSDimitry Andric 3395f757f3fSDimitry Andric // No need to constrain SrcReg. It will get constrained when 3405f757f3fSDimitry Andric // we hit another of its use or its defs. 3415f757f3fSDimitry Andric // Copies do not have constraints. 3425f757f3fSDimitry Andric const TargetRegisterClass *OldRC = MRI.getRegClassOrNull(DstReg); 3435f757f3fSDimitry Andric if (!OldRC || !DstRC->hasSubClassEq(OldRC)) { 3445f757f3fSDimitry Andric if (!RBI.constrainGenericRegister(DstReg, *DstRC, MRI)) { 3455f757f3fSDimitry Andric LLVM_DEBUG(dbgs() << "Failed to constrain " << TII.getName(I.getOpcode()) 3465f757f3fSDimitry Andric << " operand\n"); 3475f757f3fSDimitry Andric return false; 3485f757f3fSDimitry Andric } 3495f757f3fSDimitry Andric } 3505f757f3fSDimitry Andric I.setDesc(TII.get(X86::COPY)); 3515f757f3fSDimitry Andric return true; 3525f757f3fSDimitry Andric } 3535f757f3fSDimitry Andric 3545f757f3fSDimitry Andric bool X86InstructionSelector::select(MachineInstr &I) { 3555f757f3fSDimitry Andric assert(I.getParent() && "Instruction should be in a basic block!"); 3565f757f3fSDimitry Andric assert(I.getParent()->getParent() && "Instruction should be in a function!"); 3575f757f3fSDimitry Andric 3585f757f3fSDimitry Andric MachineBasicBlock &MBB = *I.getParent(); 3595f757f3fSDimitry Andric MachineFunction &MF = *MBB.getParent(); 3605f757f3fSDimitry Andric MachineRegisterInfo &MRI = MF.getRegInfo(); 3615f757f3fSDimitry Andric 3625f757f3fSDimitry Andric unsigned Opcode = I.getOpcode(); 3635f757f3fSDimitry Andric if (!isPreISelGenericOpcode(Opcode)) { 3645f757f3fSDimitry Andric // Certain non-generic instructions also need some special handling. 3655f757f3fSDimitry Andric 3665f757f3fSDimitry Andric if (Opcode == TargetOpcode::LOAD_STACK_GUARD) 3675f757f3fSDimitry Andric return false; 3685f757f3fSDimitry Andric 3695f757f3fSDimitry Andric if (I.isCopy()) 3705f757f3fSDimitry Andric return selectCopy(I, MRI); 3715f757f3fSDimitry Andric 3725f757f3fSDimitry Andric if (I.isDebugInstr()) 3735f757f3fSDimitry Andric return selectDebugInstr(I, MRI); 3745f757f3fSDimitry Andric 3755f757f3fSDimitry Andric return true; 3765f757f3fSDimitry Andric } 3775f757f3fSDimitry Andric 3785f757f3fSDimitry Andric assert(I.getNumOperands() == I.getNumExplicitOperands() && 3795f757f3fSDimitry Andric "Generic instruction has unexpected implicit operands\n"); 3805f757f3fSDimitry Andric 3815f757f3fSDimitry Andric if (selectImpl(I, *CoverageInfo)) 3825f757f3fSDimitry Andric return true; 3835f757f3fSDimitry Andric 3845f757f3fSDimitry Andric LLVM_DEBUG(dbgs() << " C++ instruction selection: "; I.print(dbgs())); 3855f757f3fSDimitry Andric 3865f757f3fSDimitry Andric // TODO: This should be implemented by tblgen. 3875f757f3fSDimitry Andric switch (I.getOpcode()) { 3885f757f3fSDimitry Andric default: 3895f757f3fSDimitry Andric return false; 3905f757f3fSDimitry Andric case TargetOpcode::G_STORE: 3915f757f3fSDimitry Andric case TargetOpcode::G_LOAD: 3925f757f3fSDimitry Andric return selectLoadStoreOp(I, MRI, MF); 3935f757f3fSDimitry Andric case TargetOpcode::G_PTR_ADD: 3945f757f3fSDimitry Andric case TargetOpcode::G_FRAME_INDEX: 3955f757f3fSDimitry Andric return selectFrameIndexOrGep(I, MRI, MF); 3965f757f3fSDimitry Andric case TargetOpcode::G_GLOBAL_VALUE: 3975f757f3fSDimitry Andric return selectGlobalValue(I, MRI, MF); 3985f757f3fSDimitry Andric case TargetOpcode::G_CONSTANT: 3995f757f3fSDimitry Andric return selectConstant(I, MRI, MF); 4005f757f3fSDimitry Andric case TargetOpcode::G_FCONSTANT: 4015f757f3fSDimitry Andric return materializeFP(I, MRI, MF); 4025f757f3fSDimitry Andric case TargetOpcode::G_PTRTOINT: 4035f757f3fSDimitry Andric case TargetOpcode::G_TRUNC: 4045f757f3fSDimitry Andric return selectTruncOrPtrToInt(I, MRI, MF); 4055f757f3fSDimitry Andric case TargetOpcode::G_INTTOPTR: 4065f757f3fSDimitry Andric return selectCopy(I, MRI); 4075f757f3fSDimitry Andric case TargetOpcode::G_ZEXT: 4085f757f3fSDimitry Andric return selectZext(I, MRI, MF); 4095f757f3fSDimitry Andric case TargetOpcode::G_ANYEXT: 4105f757f3fSDimitry Andric return selectAnyext(I, MRI, MF); 4115f757f3fSDimitry Andric case TargetOpcode::G_ICMP: 4125f757f3fSDimitry Andric return selectCmp(I, MRI, MF); 4135f757f3fSDimitry Andric case TargetOpcode::G_FCMP: 4145f757f3fSDimitry Andric return selectFCmp(I, MRI, MF); 4155f757f3fSDimitry Andric case TargetOpcode::G_UADDE: 4165f757f3fSDimitry Andric case TargetOpcode::G_UADDO: 4175f757f3fSDimitry Andric case TargetOpcode::G_USUBE: 4185f757f3fSDimitry Andric case TargetOpcode::G_USUBO: 4195f757f3fSDimitry Andric return selectUAddSub(I, MRI, MF); 4205f757f3fSDimitry Andric case TargetOpcode::G_UNMERGE_VALUES: 4215f757f3fSDimitry Andric return selectUnmergeValues(I, MRI, MF); 4225f757f3fSDimitry Andric case TargetOpcode::G_MERGE_VALUES: 4235f757f3fSDimitry Andric case TargetOpcode::G_CONCAT_VECTORS: 4245f757f3fSDimitry Andric return selectMergeValues(I, MRI, MF); 4255f757f3fSDimitry Andric case TargetOpcode::G_EXTRACT: 4265f757f3fSDimitry Andric return selectExtract(I, MRI, MF); 4275f757f3fSDimitry Andric case TargetOpcode::G_INSERT: 4285f757f3fSDimitry Andric return selectInsert(I, MRI, MF); 4295f757f3fSDimitry Andric case TargetOpcode::G_BRCOND: 4305f757f3fSDimitry Andric return selectCondBranch(I, MRI, MF); 4315f757f3fSDimitry Andric case TargetOpcode::G_IMPLICIT_DEF: 4325f757f3fSDimitry Andric case TargetOpcode::G_PHI: 4335f757f3fSDimitry Andric return selectImplicitDefOrPHI(I, MRI); 4345f757f3fSDimitry Andric case TargetOpcode::G_MUL: 4355f757f3fSDimitry Andric case TargetOpcode::G_SMULH: 4365f757f3fSDimitry Andric case TargetOpcode::G_UMULH: 4375f757f3fSDimitry Andric case TargetOpcode::G_SDIV: 4385f757f3fSDimitry Andric case TargetOpcode::G_UDIV: 4395f757f3fSDimitry Andric case TargetOpcode::G_SREM: 4405f757f3fSDimitry Andric case TargetOpcode::G_UREM: 4415f757f3fSDimitry Andric return selectMulDivRem(I, MRI, MF); 4425f757f3fSDimitry Andric case TargetOpcode::G_SELECT: 4435f757f3fSDimitry Andric return selectSelect(I, MRI, MF); 4445f757f3fSDimitry Andric } 4455f757f3fSDimitry Andric 4465f757f3fSDimitry Andric return false; 4475f757f3fSDimitry Andric } 4485f757f3fSDimitry Andric 4495f757f3fSDimitry Andric unsigned X86InstructionSelector::getLoadStoreOp(const LLT &Ty, 4505f757f3fSDimitry Andric const RegisterBank &RB, 4515f757f3fSDimitry Andric unsigned Opc, 4525f757f3fSDimitry Andric Align Alignment) const { 4535f757f3fSDimitry Andric bool Isload = (Opc == TargetOpcode::G_LOAD); 4545f757f3fSDimitry Andric bool HasAVX = STI.hasAVX(); 4555f757f3fSDimitry Andric bool HasAVX512 = STI.hasAVX512(); 4565f757f3fSDimitry Andric bool HasVLX = STI.hasVLX(); 4575f757f3fSDimitry Andric 4585f757f3fSDimitry Andric if (Ty == LLT::scalar(8)) { 4595f757f3fSDimitry Andric if (X86::GPRRegBankID == RB.getID()) 4605f757f3fSDimitry Andric return Isload ? X86::MOV8rm : X86::MOV8mr; 4615f757f3fSDimitry Andric } else if (Ty == LLT::scalar(16)) { 4625f757f3fSDimitry Andric if (X86::GPRRegBankID == RB.getID()) 4635f757f3fSDimitry Andric return Isload ? X86::MOV16rm : X86::MOV16mr; 4645f757f3fSDimitry Andric } else if (Ty == LLT::scalar(32) || Ty == LLT::pointer(0, 32)) { 4655f757f3fSDimitry Andric if (X86::GPRRegBankID == RB.getID()) 4665f757f3fSDimitry Andric return Isload ? X86::MOV32rm : X86::MOV32mr; 4675f757f3fSDimitry Andric if (X86::VECRRegBankID == RB.getID()) 4685f757f3fSDimitry Andric return Isload ? (HasAVX512 ? X86::VMOVSSZrm_alt : 4695f757f3fSDimitry Andric HasAVX ? X86::VMOVSSrm_alt : 4705f757f3fSDimitry Andric X86::MOVSSrm_alt) 4715f757f3fSDimitry Andric : (HasAVX512 ? X86::VMOVSSZmr : 4725f757f3fSDimitry Andric HasAVX ? X86::VMOVSSmr : 4735f757f3fSDimitry Andric X86::MOVSSmr); 474*0fca6ea1SDimitry Andric if (X86::PSRRegBankID == RB.getID()) 475*0fca6ea1SDimitry Andric return Isload ? X86::LD_Fp32m : X86::ST_Fp32m; 4765f757f3fSDimitry Andric } else if (Ty == LLT::scalar(64) || Ty == LLT::pointer(0, 64)) { 4775f757f3fSDimitry Andric if (X86::GPRRegBankID == RB.getID()) 4785f757f3fSDimitry Andric return Isload ? X86::MOV64rm : X86::MOV64mr; 4795f757f3fSDimitry Andric if (X86::VECRRegBankID == RB.getID()) 4805f757f3fSDimitry Andric return Isload ? (HasAVX512 ? X86::VMOVSDZrm_alt : 4815f757f3fSDimitry Andric HasAVX ? X86::VMOVSDrm_alt : 4825f757f3fSDimitry Andric X86::MOVSDrm_alt) 4835f757f3fSDimitry Andric : (HasAVX512 ? X86::VMOVSDZmr : 4845f757f3fSDimitry Andric HasAVX ? X86::VMOVSDmr : 4855f757f3fSDimitry Andric X86::MOVSDmr); 486*0fca6ea1SDimitry Andric if (X86::PSRRegBankID == RB.getID()) 487*0fca6ea1SDimitry Andric return Isload ? X86::LD_Fp64m : X86::ST_Fp64m; 488*0fca6ea1SDimitry Andric } else if (Ty == LLT::scalar(80)) { 489*0fca6ea1SDimitry Andric return Isload ? X86::LD_Fp80m : X86::ST_FpP80m; 4905f757f3fSDimitry Andric } else if (Ty.isVector() && Ty.getSizeInBits() == 128) { 4915f757f3fSDimitry Andric if (Alignment >= Align(16)) 4925f757f3fSDimitry Andric return Isload ? (HasVLX ? X86::VMOVAPSZ128rm 4935f757f3fSDimitry Andric : HasAVX512 4945f757f3fSDimitry Andric ? X86::VMOVAPSZ128rm_NOVLX 4955f757f3fSDimitry Andric : HasAVX ? X86::VMOVAPSrm : X86::MOVAPSrm) 4965f757f3fSDimitry Andric : (HasVLX ? X86::VMOVAPSZ128mr 4975f757f3fSDimitry Andric : HasAVX512 4985f757f3fSDimitry Andric ? X86::VMOVAPSZ128mr_NOVLX 4995f757f3fSDimitry Andric : HasAVX ? X86::VMOVAPSmr : X86::MOVAPSmr); 5005f757f3fSDimitry Andric else 5015f757f3fSDimitry Andric return Isload ? (HasVLX ? X86::VMOVUPSZ128rm 5025f757f3fSDimitry Andric : HasAVX512 5035f757f3fSDimitry Andric ? X86::VMOVUPSZ128rm_NOVLX 5045f757f3fSDimitry Andric : HasAVX ? X86::VMOVUPSrm : X86::MOVUPSrm) 5055f757f3fSDimitry Andric : (HasVLX ? X86::VMOVUPSZ128mr 5065f757f3fSDimitry Andric : HasAVX512 5075f757f3fSDimitry Andric ? X86::VMOVUPSZ128mr_NOVLX 5085f757f3fSDimitry Andric : HasAVX ? X86::VMOVUPSmr : X86::MOVUPSmr); 5095f757f3fSDimitry Andric } else if (Ty.isVector() && Ty.getSizeInBits() == 256) { 5105f757f3fSDimitry Andric if (Alignment >= Align(32)) 5115f757f3fSDimitry Andric return Isload ? (HasVLX ? X86::VMOVAPSZ256rm 5125f757f3fSDimitry Andric : HasAVX512 ? X86::VMOVAPSZ256rm_NOVLX 5135f757f3fSDimitry Andric : X86::VMOVAPSYrm) 5145f757f3fSDimitry Andric : (HasVLX ? X86::VMOVAPSZ256mr 5155f757f3fSDimitry Andric : HasAVX512 ? X86::VMOVAPSZ256mr_NOVLX 5165f757f3fSDimitry Andric : X86::VMOVAPSYmr); 5175f757f3fSDimitry Andric else 5185f757f3fSDimitry Andric return Isload ? (HasVLX ? X86::VMOVUPSZ256rm 5195f757f3fSDimitry Andric : HasAVX512 ? X86::VMOVUPSZ256rm_NOVLX 5205f757f3fSDimitry Andric : X86::VMOVUPSYrm) 5215f757f3fSDimitry Andric : (HasVLX ? X86::VMOVUPSZ256mr 5225f757f3fSDimitry Andric : HasAVX512 ? X86::VMOVUPSZ256mr_NOVLX 5235f757f3fSDimitry Andric : X86::VMOVUPSYmr); 5245f757f3fSDimitry Andric } else if (Ty.isVector() && Ty.getSizeInBits() == 512) { 5255f757f3fSDimitry Andric if (Alignment >= Align(64)) 5265f757f3fSDimitry Andric return Isload ? X86::VMOVAPSZrm : X86::VMOVAPSZmr; 5275f757f3fSDimitry Andric else 5285f757f3fSDimitry Andric return Isload ? X86::VMOVUPSZrm : X86::VMOVUPSZmr; 5295f757f3fSDimitry Andric } 5305f757f3fSDimitry Andric return Opc; 5315f757f3fSDimitry Andric } 5325f757f3fSDimitry Andric 5335f757f3fSDimitry Andric // Fill in an address from the given instruction. 5345f757f3fSDimitry Andric static void X86SelectAddress(const MachineInstr &I, 5355f757f3fSDimitry Andric const MachineRegisterInfo &MRI, 5365f757f3fSDimitry Andric X86AddressMode &AM) { 5375f757f3fSDimitry Andric assert(I.getOperand(0).isReg() && "unsupported opperand."); 5385f757f3fSDimitry Andric assert(MRI.getType(I.getOperand(0).getReg()).isPointer() && 5395f757f3fSDimitry Andric "unsupported type."); 5405f757f3fSDimitry Andric 5415f757f3fSDimitry Andric if (I.getOpcode() == TargetOpcode::G_PTR_ADD) { 5425f757f3fSDimitry Andric if (auto COff = getIConstantVRegSExtVal(I.getOperand(2).getReg(), MRI)) { 5435f757f3fSDimitry Andric int64_t Imm = *COff; 5445f757f3fSDimitry Andric if (isInt<32>(Imm)) { // Check for displacement overflow. 5455f757f3fSDimitry Andric AM.Disp = static_cast<int32_t>(Imm); 5465f757f3fSDimitry Andric AM.Base.Reg = I.getOperand(1).getReg(); 5475f757f3fSDimitry Andric return; 5485f757f3fSDimitry Andric } 5495f757f3fSDimitry Andric } 5505f757f3fSDimitry Andric } else if (I.getOpcode() == TargetOpcode::G_FRAME_INDEX) { 5515f757f3fSDimitry Andric AM.Base.FrameIndex = I.getOperand(1).getIndex(); 5525f757f3fSDimitry Andric AM.BaseType = X86AddressMode::FrameIndexBase; 5535f757f3fSDimitry Andric return; 5545f757f3fSDimitry Andric } 5555f757f3fSDimitry Andric 5565f757f3fSDimitry Andric // Default behavior. 5575f757f3fSDimitry Andric AM.Base.Reg = I.getOperand(0).getReg(); 5585f757f3fSDimitry Andric } 5595f757f3fSDimitry Andric 5605f757f3fSDimitry Andric bool X86InstructionSelector::selectLoadStoreOp(MachineInstr &I, 5615f757f3fSDimitry Andric MachineRegisterInfo &MRI, 5625f757f3fSDimitry Andric MachineFunction &MF) const { 5635f757f3fSDimitry Andric unsigned Opc = I.getOpcode(); 5645f757f3fSDimitry Andric 5655f757f3fSDimitry Andric assert((Opc == TargetOpcode::G_STORE || Opc == TargetOpcode::G_LOAD) && 566*0fca6ea1SDimitry Andric "Only G_STORE and G_LOAD are expected for selection"); 5675f757f3fSDimitry Andric 5685f757f3fSDimitry Andric const Register DefReg = I.getOperand(0).getReg(); 5695f757f3fSDimitry Andric LLT Ty = MRI.getType(DefReg); 5705f757f3fSDimitry Andric const RegisterBank &RB = *RBI.getRegBank(DefReg, MRI, TRI); 5715f757f3fSDimitry Andric 5725f757f3fSDimitry Andric assert(I.hasOneMemOperand()); 5735f757f3fSDimitry Andric auto &MemOp = **I.memoperands_begin(); 5745f757f3fSDimitry Andric if (MemOp.isAtomic()) { 5755f757f3fSDimitry Andric // Note: for unordered operations, we rely on the fact the appropriate MMO 5765f757f3fSDimitry Andric // is already on the instruction we're mutating, and thus we don't need to 5775f757f3fSDimitry Andric // make any changes. So long as we select an opcode which is capable of 5785f757f3fSDimitry Andric // loading or storing the appropriate size atomically, the rest of the 5795f757f3fSDimitry Andric // backend is required to respect the MMO state. 5805f757f3fSDimitry Andric if (!MemOp.isUnordered()) { 5815f757f3fSDimitry Andric LLVM_DEBUG(dbgs() << "Atomic ordering not supported yet\n"); 5825f757f3fSDimitry Andric return false; 5835f757f3fSDimitry Andric } 5845f757f3fSDimitry Andric if (MemOp.getAlign() < Ty.getSizeInBits() / 8) { 5855f757f3fSDimitry Andric LLVM_DEBUG(dbgs() << "Unaligned atomics not supported yet\n"); 5865f757f3fSDimitry Andric return false; 5875f757f3fSDimitry Andric } 5885f757f3fSDimitry Andric } 5895f757f3fSDimitry Andric 5905f757f3fSDimitry Andric unsigned NewOpc = getLoadStoreOp(Ty, RB, Opc, MemOp.getAlign()); 5915f757f3fSDimitry Andric if (NewOpc == Opc) 5925f757f3fSDimitry Andric return false; 5935f757f3fSDimitry Andric 5945f757f3fSDimitry Andric I.setDesc(TII.get(NewOpc)); 5955f757f3fSDimitry Andric MachineInstrBuilder MIB(MF, I); 596*0fca6ea1SDimitry Andric const MachineInstr *Ptr = MRI.getVRegDef(I.getOperand(1).getReg()); 597*0fca6ea1SDimitry Andric 598*0fca6ea1SDimitry Andric if (Ptr->getOpcode() == TargetOpcode::G_CONSTANT_POOL) { 599*0fca6ea1SDimitry Andric assert(Opc == TargetOpcode::G_LOAD && 600*0fca6ea1SDimitry Andric "Only G_LOAD from constant pool is expected"); 601*0fca6ea1SDimitry Andric // TODO: Need a separate move for Large model 602*0fca6ea1SDimitry Andric if (TM.getCodeModel() == CodeModel::Large) 603*0fca6ea1SDimitry Andric return false; 604*0fca6ea1SDimitry Andric 605*0fca6ea1SDimitry Andric unsigned char OpFlag = STI.classifyLocalReference(nullptr); 606*0fca6ea1SDimitry Andric unsigned PICBase = 0; 607*0fca6ea1SDimitry Andric if (OpFlag == X86II::MO_GOTOFF) 608*0fca6ea1SDimitry Andric PICBase = TII.getGlobalBaseReg(&MF); 609*0fca6ea1SDimitry Andric else if (STI.is64Bit()) 610*0fca6ea1SDimitry Andric PICBase = X86::RIP; 611*0fca6ea1SDimitry Andric 612*0fca6ea1SDimitry Andric I.removeOperand(1); 613*0fca6ea1SDimitry Andric addConstantPoolReference(MIB, Ptr->getOperand(1).getIndex(), PICBase, 614*0fca6ea1SDimitry Andric OpFlag); 615*0fca6ea1SDimitry Andric return constrainSelectedInstRegOperands(I, TII, TRI, RBI); 616*0fca6ea1SDimitry Andric } 617*0fca6ea1SDimitry Andric 618*0fca6ea1SDimitry Andric X86AddressMode AM; 619*0fca6ea1SDimitry Andric X86SelectAddress(*Ptr, MRI, AM); 6205f757f3fSDimitry Andric if (Opc == TargetOpcode::G_LOAD) { 6215f757f3fSDimitry Andric I.removeOperand(1); 6225f757f3fSDimitry Andric addFullAddress(MIB, AM); 6235f757f3fSDimitry Andric } else { 6245f757f3fSDimitry Andric // G_STORE (VAL, Addr), X86Store instruction (Addr, VAL) 6255f757f3fSDimitry Andric I.removeOperand(1); 6265f757f3fSDimitry Andric I.removeOperand(0); 6275f757f3fSDimitry Andric addFullAddress(MIB, AM).addUse(DefReg); 6285f757f3fSDimitry Andric } 629*0fca6ea1SDimitry Andric bool Constrained = constrainSelectedInstRegOperands(I, TII, TRI, RBI); 630*0fca6ea1SDimitry Andric I.addImplicitDefUseOperands(MF); 631*0fca6ea1SDimitry Andric return Constrained; 6325f757f3fSDimitry Andric } 6335f757f3fSDimitry Andric 6345f757f3fSDimitry Andric static unsigned getLeaOP(LLT Ty, const X86Subtarget &STI) { 6355f757f3fSDimitry Andric if (Ty == LLT::pointer(0, 64)) 6365f757f3fSDimitry Andric return X86::LEA64r; 6375f757f3fSDimitry Andric else if (Ty == LLT::pointer(0, 32)) 6385f757f3fSDimitry Andric return STI.isTarget64BitILP32() ? X86::LEA64_32r : X86::LEA32r; 6395f757f3fSDimitry Andric else 6405f757f3fSDimitry Andric llvm_unreachable("Can't get LEA opcode. Unsupported type."); 6415f757f3fSDimitry Andric } 6425f757f3fSDimitry Andric 6435f757f3fSDimitry Andric bool X86InstructionSelector::selectFrameIndexOrGep(MachineInstr &I, 6445f757f3fSDimitry Andric MachineRegisterInfo &MRI, 6455f757f3fSDimitry Andric MachineFunction &MF) const { 6465f757f3fSDimitry Andric unsigned Opc = I.getOpcode(); 6475f757f3fSDimitry Andric 6485f757f3fSDimitry Andric assert((Opc == TargetOpcode::G_FRAME_INDEX || Opc == TargetOpcode::G_PTR_ADD) && 6495f757f3fSDimitry Andric "unexpected instruction"); 6505f757f3fSDimitry Andric 6515f757f3fSDimitry Andric const Register DefReg = I.getOperand(0).getReg(); 6525f757f3fSDimitry Andric LLT Ty = MRI.getType(DefReg); 6535f757f3fSDimitry Andric 6545f757f3fSDimitry Andric // Use LEA to calculate frame index and GEP 6555f757f3fSDimitry Andric unsigned NewOpc = getLeaOP(Ty, STI); 6565f757f3fSDimitry Andric I.setDesc(TII.get(NewOpc)); 6575f757f3fSDimitry Andric MachineInstrBuilder MIB(MF, I); 6585f757f3fSDimitry Andric 6595f757f3fSDimitry Andric if (Opc == TargetOpcode::G_FRAME_INDEX) { 6605f757f3fSDimitry Andric addOffset(MIB, 0); 6615f757f3fSDimitry Andric } else { 6625f757f3fSDimitry Andric MachineOperand &InxOp = I.getOperand(2); 6635f757f3fSDimitry Andric I.addOperand(InxOp); // set IndexReg 6645f757f3fSDimitry Andric InxOp.ChangeToImmediate(1); // set Scale 6655f757f3fSDimitry Andric MIB.addImm(0).addReg(0); 6665f757f3fSDimitry Andric } 6675f757f3fSDimitry Andric 6685f757f3fSDimitry Andric return constrainSelectedInstRegOperands(I, TII, TRI, RBI); 6695f757f3fSDimitry Andric } 6705f757f3fSDimitry Andric 6715f757f3fSDimitry Andric bool X86InstructionSelector::selectGlobalValue(MachineInstr &I, 6725f757f3fSDimitry Andric MachineRegisterInfo &MRI, 6735f757f3fSDimitry Andric MachineFunction &MF) const { 6745f757f3fSDimitry Andric assert((I.getOpcode() == TargetOpcode::G_GLOBAL_VALUE) && 6755f757f3fSDimitry Andric "unexpected instruction"); 6765f757f3fSDimitry Andric 6775f757f3fSDimitry Andric auto GV = I.getOperand(1).getGlobal(); 6785f757f3fSDimitry Andric if (GV->isThreadLocal()) { 6795f757f3fSDimitry Andric return false; // TODO: we don't support TLS yet. 6805f757f3fSDimitry Andric } 6815f757f3fSDimitry Andric 6825f757f3fSDimitry Andric // Can't handle alternate code models yet. 6835f757f3fSDimitry Andric if (TM.getCodeModel() != CodeModel::Small) 6845f757f3fSDimitry Andric return false; 6855f757f3fSDimitry Andric 6865f757f3fSDimitry Andric X86AddressMode AM; 6875f757f3fSDimitry Andric AM.GV = GV; 6885f757f3fSDimitry Andric AM.GVOpFlags = STI.classifyGlobalReference(GV); 6895f757f3fSDimitry Andric 6905f757f3fSDimitry Andric // TODO: The ABI requires an extra load. not supported yet. 6915f757f3fSDimitry Andric if (isGlobalStubReference(AM.GVOpFlags)) 6925f757f3fSDimitry Andric return false; 6935f757f3fSDimitry Andric 6945f757f3fSDimitry Andric // TODO: This reference is relative to the pic base. not supported yet. 6955f757f3fSDimitry Andric if (isGlobalRelativeToPICBase(AM.GVOpFlags)) 6965f757f3fSDimitry Andric return false; 6975f757f3fSDimitry Andric 6985f757f3fSDimitry Andric if (STI.isPICStyleRIPRel()) { 6995f757f3fSDimitry Andric // Use rip-relative addressing. 7005f757f3fSDimitry Andric assert(AM.Base.Reg == 0 && AM.IndexReg == 0); 7015f757f3fSDimitry Andric AM.Base.Reg = X86::RIP; 7025f757f3fSDimitry Andric } 7035f757f3fSDimitry Andric 7045f757f3fSDimitry Andric const Register DefReg = I.getOperand(0).getReg(); 7055f757f3fSDimitry Andric LLT Ty = MRI.getType(DefReg); 7065f757f3fSDimitry Andric unsigned NewOpc = getLeaOP(Ty, STI); 7075f757f3fSDimitry Andric 7085f757f3fSDimitry Andric I.setDesc(TII.get(NewOpc)); 7095f757f3fSDimitry Andric MachineInstrBuilder MIB(MF, I); 7105f757f3fSDimitry Andric 7115f757f3fSDimitry Andric I.removeOperand(1); 7125f757f3fSDimitry Andric addFullAddress(MIB, AM); 7135f757f3fSDimitry Andric 7145f757f3fSDimitry Andric return constrainSelectedInstRegOperands(I, TII, TRI, RBI); 7155f757f3fSDimitry Andric } 7165f757f3fSDimitry Andric 7175f757f3fSDimitry Andric bool X86InstructionSelector::selectConstant(MachineInstr &I, 7185f757f3fSDimitry Andric MachineRegisterInfo &MRI, 7195f757f3fSDimitry Andric MachineFunction &MF) const { 7205f757f3fSDimitry Andric assert((I.getOpcode() == TargetOpcode::G_CONSTANT) && 7215f757f3fSDimitry Andric "unexpected instruction"); 7225f757f3fSDimitry Andric 7235f757f3fSDimitry Andric const Register DefReg = I.getOperand(0).getReg(); 7245f757f3fSDimitry Andric LLT Ty = MRI.getType(DefReg); 7255f757f3fSDimitry Andric 7265f757f3fSDimitry Andric if (RBI.getRegBank(DefReg, MRI, TRI)->getID() != X86::GPRRegBankID) 7275f757f3fSDimitry Andric return false; 7285f757f3fSDimitry Andric 7295f757f3fSDimitry Andric uint64_t Val = 0; 7305f757f3fSDimitry Andric if (I.getOperand(1).isCImm()) { 7315f757f3fSDimitry Andric Val = I.getOperand(1).getCImm()->getZExtValue(); 7325f757f3fSDimitry Andric I.getOperand(1).ChangeToImmediate(Val); 7335f757f3fSDimitry Andric } else if (I.getOperand(1).isImm()) { 7345f757f3fSDimitry Andric Val = I.getOperand(1).getImm(); 7355f757f3fSDimitry Andric } else 7365f757f3fSDimitry Andric llvm_unreachable("Unsupported operand type."); 7375f757f3fSDimitry Andric 7385f757f3fSDimitry Andric unsigned NewOpc; 7395f757f3fSDimitry Andric switch (Ty.getSizeInBits()) { 7405f757f3fSDimitry Andric case 8: 7415f757f3fSDimitry Andric NewOpc = X86::MOV8ri; 7425f757f3fSDimitry Andric break; 7435f757f3fSDimitry Andric case 16: 7445f757f3fSDimitry Andric NewOpc = X86::MOV16ri; 7455f757f3fSDimitry Andric break; 7465f757f3fSDimitry Andric case 32: 7475f757f3fSDimitry Andric NewOpc = X86::MOV32ri; 7485f757f3fSDimitry Andric break; 7495f757f3fSDimitry Andric case 64: 7505f757f3fSDimitry Andric // TODO: in case isUInt<32>(Val), X86::MOV32ri can be used 7515f757f3fSDimitry Andric if (isInt<32>(Val)) 7525f757f3fSDimitry Andric NewOpc = X86::MOV64ri32; 7535f757f3fSDimitry Andric else 7545f757f3fSDimitry Andric NewOpc = X86::MOV64ri; 7555f757f3fSDimitry Andric break; 7565f757f3fSDimitry Andric default: 7575f757f3fSDimitry Andric llvm_unreachable("Can't select G_CONSTANT, unsupported type."); 7585f757f3fSDimitry Andric } 7595f757f3fSDimitry Andric 7605f757f3fSDimitry Andric I.setDesc(TII.get(NewOpc)); 7615f757f3fSDimitry Andric return constrainSelectedInstRegOperands(I, TII, TRI, RBI); 7625f757f3fSDimitry Andric } 7635f757f3fSDimitry Andric 7645f757f3fSDimitry Andric // Helper function for selectTruncOrPtrToInt and selectAnyext. 7655f757f3fSDimitry Andric // Returns true if DstRC lives on a floating register class and 7665f757f3fSDimitry Andric // SrcRC lives on a 128-bit vector class. 7675f757f3fSDimitry Andric static bool canTurnIntoCOPY(const TargetRegisterClass *DstRC, 7685f757f3fSDimitry Andric const TargetRegisterClass *SrcRC) { 7695f757f3fSDimitry Andric return (DstRC == &X86::FR32RegClass || DstRC == &X86::FR32XRegClass || 7705f757f3fSDimitry Andric DstRC == &X86::FR64RegClass || DstRC == &X86::FR64XRegClass) && 7715f757f3fSDimitry Andric (SrcRC == &X86::VR128RegClass || SrcRC == &X86::VR128XRegClass); 7725f757f3fSDimitry Andric } 7735f757f3fSDimitry Andric 7745f757f3fSDimitry Andric bool X86InstructionSelector::selectTurnIntoCOPY( 7755f757f3fSDimitry Andric MachineInstr &I, MachineRegisterInfo &MRI, const unsigned DstReg, 7765f757f3fSDimitry Andric const TargetRegisterClass *DstRC, const unsigned SrcReg, 7775f757f3fSDimitry Andric const TargetRegisterClass *SrcRC) const { 7785f757f3fSDimitry Andric 7795f757f3fSDimitry Andric if (!RBI.constrainGenericRegister(SrcReg, *SrcRC, MRI) || 7805f757f3fSDimitry Andric !RBI.constrainGenericRegister(DstReg, *DstRC, MRI)) { 7815f757f3fSDimitry Andric LLVM_DEBUG(dbgs() << "Failed to constrain " << TII.getName(I.getOpcode()) 7825f757f3fSDimitry Andric << " operand\n"); 7835f757f3fSDimitry Andric return false; 7845f757f3fSDimitry Andric } 7855f757f3fSDimitry Andric I.setDesc(TII.get(X86::COPY)); 7865f757f3fSDimitry Andric return true; 7875f757f3fSDimitry Andric } 7885f757f3fSDimitry Andric 7895f757f3fSDimitry Andric bool X86InstructionSelector::selectTruncOrPtrToInt(MachineInstr &I, 7905f757f3fSDimitry Andric MachineRegisterInfo &MRI, 7915f757f3fSDimitry Andric MachineFunction &MF) const { 7925f757f3fSDimitry Andric assert((I.getOpcode() == TargetOpcode::G_TRUNC || 7935f757f3fSDimitry Andric I.getOpcode() == TargetOpcode::G_PTRTOINT) && 7945f757f3fSDimitry Andric "unexpected instruction"); 7955f757f3fSDimitry Andric 7965f757f3fSDimitry Andric const Register DstReg = I.getOperand(0).getReg(); 7975f757f3fSDimitry Andric const Register SrcReg = I.getOperand(1).getReg(); 7985f757f3fSDimitry Andric 7995f757f3fSDimitry Andric const LLT DstTy = MRI.getType(DstReg); 8005f757f3fSDimitry Andric const LLT SrcTy = MRI.getType(SrcReg); 8015f757f3fSDimitry Andric 8025f757f3fSDimitry Andric const RegisterBank &DstRB = *RBI.getRegBank(DstReg, MRI, TRI); 8035f757f3fSDimitry Andric const RegisterBank &SrcRB = *RBI.getRegBank(SrcReg, MRI, TRI); 8045f757f3fSDimitry Andric 8055f757f3fSDimitry Andric if (DstRB.getID() != SrcRB.getID()) { 8065f757f3fSDimitry Andric LLVM_DEBUG(dbgs() << TII.getName(I.getOpcode()) 8075f757f3fSDimitry Andric << " input/output on different banks\n"); 8085f757f3fSDimitry Andric return false; 8095f757f3fSDimitry Andric } 8105f757f3fSDimitry Andric 8115f757f3fSDimitry Andric const TargetRegisterClass *DstRC = getRegClass(DstTy, DstRB); 8125f757f3fSDimitry Andric const TargetRegisterClass *SrcRC = getRegClass(SrcTy, SrcRB); 8135f757f3fSDimitry Andric 8145f757f3fSDimitry Andric if (!DstRC || !SrcRC) 8155f757f3fSDimitry Andric return false; 8165f757f3fSDimitry Andric 8175f757f3fSDimitry Andric // If that's truncation of the value that lives on the vector class and goes 8185f757f3fSDimitry Andric // into the floating class, just replace it with copy, as we are able to 8195f757f3fSDimitry Andric // select it as a regular move. 8205f757f3fSDimitry Andric if (canTurnIntoCOPY(DstRC, SrcRC)) 8215f757f3fSDimitry Andric return selectTurnIntoCOPY(I, MRI, DstReg, DstRC, SrcReg, SrcRC); 8225f757f3fSDimitry Andric 8235f757f3fSDimitry Andric if (DstRB.getID() != X86::GPRRegBankID) 8245f757f3fSDimitry Andric return false; 8255f757f3fSDimitry Andric 8265f757f3fSDimitry Andric unsigned SubIdx; 8275f757f3fSDimitry Andric if (DstRC == SrcRC) { 8285f757f3fSDimitry Andric // Nothing to be done 8295f757f3fSDimitry Andric SubIdx = X86::NoSubRegister; 8305f757f3fSDimitry Andric } else if (DstRC == &X86::GR32RegClass) { 8315f757f3fSDimitry Andric SubIdx = X86::sub_32bit; 8325f757f3fSDimitry Andric } else if (DstRC == &X86::GR16RegClass) { 8335f757f3fSDimitry Andric SubIdx = X86::sub_16bit; 8345f757f3fSDimitry Andric } else if (DstRC == &X86::GR8RegClass) { 8355f757f3fSDimitry Andric SubIdx = X86::sub_8bit; 8365f757f3fSDimitry Andric } else { 8375f757f3fSDimitry Andric return false; 8385f757f3fSDimitry Andric } 8395f757f3fSDimitry Andric 8405f757f3fSDimitry Andric SrcRC = TRI.getSubClassWithSubReg(SrcRC, SubIdx); 8415f757f3fSDimitry Andric 8425f757f3fSDimitry Andric if (!RBI.constrainGenericRegister(SrcReg, *SrcRC, MRI) || 8435f757f3fSDimitry Andric !RBI.constrainGenericRegister(DstReg, *DstRC, MRI)) { 8445f757f3fSDimitry Andric LLVM_DEBUG(dbgs() << "Failed to constrain " << TII.getName(I.getOpcode()) 8455f757f3fSDimitry Andric << "\n"); 8465f757f3fSDimitry Andric return false; 8475f757f3fSDimitry Andric } 8485f757f3fSDimitry Andric 8495f757f3fSDimitry Andric I.getOperand(1).setSubReg(SubIdx); 8505f757f3fSDimitry Andric 8515f757f3fSDimitry Andric I.setDesc(TII.get(X86::COPY)); 8525f757f3fSDimitry Andric return true; 8535f757f3fSDimitry Andric } 8545f757f3fSDimitry Andric 8555f757f3fSDimitry Andric bool X86InstructionSelector::selectZext(MachineInstr &I, 8565f757f3fSDimitry Andric MachineRegisterInfo &MRI, 8575f757f3fSDimitry Andric MachineFunction &MF) const { 8585f757f3fSDimitry Andric assert((I.getOpcode() == TargetOpcode::G_ZEXT) && "unexpected instruction"); 8595f757f3fSDimitry Andric 8605f757f3fSDimitry Andric const Register DstReg = I.getOperand(0).getReg(); 8615f757f3fSDimitry Andric const Register SrcReg = I.getOperand(1).getReg(); 8625f757f3fSDimitry Andric 8635f757f3fSDimitry Andric const LLT DstTy = MRI.getType(DstReg); 8645f757f3fSDimitry Andric const LLT SrcTy = MRI.getType(SrcReg); 8655f757f3fSDimitry Andric 8665f757f3fSDimitry Andric assert(!(SrcTy == LLT::scalar(8) && DstTy == LLT::scalar(16)) && 8675f757f3fSDimitry Andric "8=>16 Zext is handled by tablegen"); 8685f757f3fSDimitry Andric assert(!(SrcTy == LLT::scalar(8) && DstTy == LLT::scalar(32)) && 8695f757f3fSDimitry Andric "8=>32 Zext is handled by tablegen"); 8705f757f3fSDimitry Andric assert(!(SrcTy == LLT::scalar(16) && DstTy == LLT::scalar(32)) && 8715f757f3fSDimitry Andric "16=>32 Zext is handled by tablegen"); 8725f757f3fSDimitry Andric assert(!(SrcTy == LLT::scalar(8) && DstTy == LLT::scalar(64)) && 8735f757f3fSDimitry Andric "8=>64 Zext is handled by tablegen"); 8745f757f3fSDimitry Andric assert(!(SrcTy == LLT::scalar(16) && DstTy == LLT::scalar(64)) && 8755f757f3fSDimitry Andric "16=>64 Zext is handled by tablegen"); 8765f757f3fSDimitry Andric assert(!(SrcTy == LLT::scalar(32) && DstTy == LLT::scalar(64)) && 8775f757f3fSDimitry Andric "32=>64 Zext is handled by tablegen"); 8785f757f3fSDimitry Andric 8795f757f3fSDimitry Andric if (SrcTy != LLT::scalar(1)) 8805f757f3fSDimitry Andric return false; 8815f757f3fSDimitry Andric 8825f757f3fSDimitry Andric unsigned AndOpc; 8835f757f3fSDimitry Andric if (DstTy == LLT::scalar(8)) 8845f757f3fSDimitry Andric AndOpc = X86::AND8ri; 8855f757f3fSDimitry Andric else if (DstTy == LLT::scalar(16)) 8865f757f3fSDimitry Andric AndOpc = X86::AND16ri; 8875f757f3fSDimitry Andric else if (DstTy == LLT::scalar(32)) 8885f757f3fSDimitry Andric AndOpc = X86::AND32ri; 8895f757f3fSDimitry Andric else if (DstTy == LLT::scalar(64)) 8905f757f3fSDimitry Andric AndOpc = X86::AND64ri32; 8915f757f3fSDimitry Andric else 8925f757f3fSDimitry Andric return false; 8935f757f3fSDimitry Andric 8945f757f3fSDimitry Andric Register DefReg = SrcReg; 8955f757f3fSDimitry Andric if (DstTy != LLT::scalar(8)) { 8965f757f3fSDimitry Andric Register ImpDefReg = 8975f757f3fSDimitry Andric MRI.createVirtualRegister(getRegClass(DstTy, DstReg, MRI)); 8985f757f3fSDimitry Andric BuildMI(*I.getParent(), I, I.getDebugLoc(), 8995f757f3fSDimitry Andric TII.get(TargetOpcode::IMPLICIT_DEF), ImpDefReg); 9005f757f3fSDimitry Andric 9015f757f3fSDimitry Andric DefReg = MRI.createVirtualRegister(getRegClass(DstTy, DstReg, MRI)); 9025f757f3fSDimitry Andric BuildMI(*I.getParent(), I, I.getDebugLoc(), 9035f757f3fSDimitry Andric TII.get(TargetOpcode::INSERT_SUBREG), DefReg) 9045f757f3fSDimitry Andric .addReg(ImpDefReg) 9055f757f3fSDimitry Andric .addReg(SrcReg) 9065f757f3fSDimitry Andric .addImm(X86::sub_8bit); 9075f757f3fSDimitry Andric } 9085f757f3fSDimitry Andric 9095f757f3fSDimitry Andric MachineInstr &AndInst = 9105f757f3fSDimitry Andric *BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(AndOpc), DstReg) 9115f757f3fSDimitry Andric .addReg(DefReg) 9125f757f3fSDimitry Andric .addImm(1); 9135f757f3fSDimitry Andric 9145f757f3fSDimitry Andric constrainSelectedInstRegOperands(AndInst, TII, TRI, RBI); 9155f757f3fSDimitry Andric 9165f757f3fSDimitry Andric I.eraseFromParent(); 9175f757f3fSDimitry Andric return true; 9185f757f3fSDimitry Andric } 9195f757f3fSDimitry Andric 9205f757f3fSDimitry Andric bool X86InstructionSelector::selectAnyext(MachineInstr &I, 9215f757f3fSDimitry Andric MachineRegisterInfo &MRI, 9225f757f3fSDimitry Andric MachineFunction &MF) const { 9235f757f3fSDimitry Andric assert((I.getOpcode() == TargetOpcode::G_ANYEXT) && "unexpected instruction"); 9245f757f3fSDimitry Andric 9255f757f3fSDimitry Andric const Register DstReg = I.getOperand(0).getReg(); 9265f757f3fSDimitry Andric const Register SrcReg = I.getOperand(1).getReg(); 9275f757f3fSDimitry Andric 9285f757f3fSDimitry Andric const LLT DstTy = MRI.getType(DstReg); 9295f757f3fSDimitry Andric const LLT SrcTy = MRI.getType(SrcReg); 9305f757f3fSDimitry Andric 9315f757f3fSDimitry Andric const RegisterBank &DstRB = *RBI.getRegBank(DstReg, MRI, TRI); 9325f757f3fSDimitry Andric const RegisterBank &SrcRB = *RBI.getRegBank(SrcReg, MRI, TRI); 9335f757f3fSDimitry Andric 9345f757f3fSDimitry Andric assert(DstRB.getID() == SrcRB.getID() && 9355f757f3fSDimitry Andric "G_ANYEXT input/output on different banks\n"); 9365f757f3fSDimitry Andric 9375f757f3fSDimitry Andric assert(DstTy.getSizeInBits() > SrcTy.getSizeInBits() && 9385f757f3fSDimitry Andric "G_ANYEXT incorrect operand size"); 9395f757f3fSDimitry Andric 9405f757f3fSDimitry Andric const TargetRegisterClass *DstRC = getRegClass(DstTy, DstRB); 9415f757f3fSDimitry Andric const TargetRegisterClass *SrcRC = getRegClass(SrcTy, SrcRB); 9425f757f3fSDimitry Andric 9435f757f3fSDimitry Andric // If that's ANY_EXT of the value that lives on the floating class and goes 9445f757f3fSDimitry Andric // into the vector class, just replace it with copy, as we are able to select 9455f757f3fSDimitry Andric // it as a regular move. 9465f757f3fSDimitry Andric if (canTurnIntoCOPY(SrcRC, DstRC)) 9475f757f3fSDimitry Andric return selectTurnIntoCOPY(I, MRI, SrcReg, SrcRC, DstReg, DstRC); 9485f757f3fSDimitry Andric 9495f757f3fSDimitry Andric if (DstRB.getID() != X86::GPRRegBankID) 9505f757f3fSDimitry Andric return false; 9515f757f3fSDimitry Andric 9525f757f3fSDimitry Andric if (!RBI.constrainGenericRegister(SrcReg, *SrcRC, MRI) || 9535f757f3fSDimitry Andric !RBI.constrainGenericRegister(DstReg, *DstRC, MRI)) { 9545f757f3fSDimitry Andric LLVM_DEBUG(dbgs() << "Failed to constrain " << TII.getName(I.getOpcode()) 9555f757f3fSDimitry Andric << " operand\n"); 9565f757f3fSDimitry Andric return false; 9575f757f3fSDimitry Andric } 9585f757f3fSDimitry Andric 9595f757f3fSDimitry Andric if (SrcRC == DstRC) { 9605f757f3fSDimitry Andric I.setDesc(TII.get(X86::COPY)); 9615f757f3fSDimitry Andric return true; 9625f757f3fSDimitry Andric } 9635f757f3fSDimitry Andric 9645f757f3fSDimitry Andric BuildMI(*I.getParent(), I, I.getDebugLoc(), 9655f757f3fSDimitry Andric TII.get(TargetOpcode::SUBREG_TO_REG)) 9665f757f3fSDimitry Andric .addDef(DstReg) 9675f757f3fSDimitry Andric .addImm(0) 9685f757f3fSDimitry Andric .addReg(SrcReg) 9695f757f3fSDimitry Andric .addImm(getSubRegIndex(SrcRC)); 9705f757f3fSDimitry Andric 9715f757f3fSDimitry Andric I.eraseFromParent(); 9725f757f3fSDimitry Andric return true; 9735f757f3fSDimitry Andric } 9745f757f3fSDimitry Andric 9755f757f3fSDimitry Andric bool X86InstructionSelector::selectCmp(MachineInstr &I, 9765f757f3fSDimitry Andric MachineRegisterInfo &MRI, 9775f757f3fSDimitry Andric MachineFunction &MF) const { 9785f757f3fSDimitry Andric assert((I.getOpcode() == TargetOpcode::G_ICMP) && "unexpected instruction"); 9795f757f3fSDimitry Andric 9805f757f3fSDimitry Andric X86::CondCode CC; 9815f757f3fSDimitry Andric bool SwapArgs; 9825f757f3fSDimitry Andric std::tie(CC, SwapArgs) = X86::getX86ConditionCode( 9835f757f3fSDimitry Andric (CmpInst::Predicate)I.getOperand(1).getPredicate()); 9845f757f3fSDimitry Andric 9855f757f3fSDimitry Andric Register LHS = I.getOperand(2).getReg(); 9865f757f3fSDimitry Andric Register RHS = I.getOperand(3).getReg(); 9875f757f3fSDimitry Andric 9885f757f3fSDimitry Andric if (SwapArgs) 9895f757f3fSDimitry Andric std::swap(LHS, RHS); 9905f757f3fSDimitry Andric 9915f757f3fSDimitry Andric unsigned OpCmp; 9925f757f3fSDimitry Andric LLT Ty = MRI.getType(LHS); 9935f757f3fSDimitry Andric 9945f757f3fSDimitry Andric switch (Ty.getSizeInBits()) { 9955f757f3fSDimitry Andric default: 9965f757f3fSDimitry Andric return false; 9975f757f3fSDimitry Andric case 8: 9985f757f3fSDimitry Andric OpCmp = X86::CMP8rr; 9995f757f3fSDimitry Andric break; 10005f757f3fSDimitry Andric case 16: 10015f757f3fSDimitry Andric OpCmp = X86::CMP16rr; 10025f757f3fSDimitry Andric break; 10035f757f3fSDimitry Andric case 32: 10045f757f3fSDimitry Andric OpCmp = X86::CMP32rr; 10055f757f3fSDimitry Andric break; 10065f757f3fSDimitry Andric case 64: 10075f757f3fSDimitry Andric OpCmp = X86::CMP64rr; 10085f757f3fSDimitry Andric break; 10095f757f3fSDimitry Andric } 10105f757f3fSDimitry Andric 10115f757f3fSDimitry Andric MachineInstr &CmpInst = 10125f757f3fSDimitry Andric *BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(OpCmp)) 10135f757f3fSDimitry Andric .addReg(LHS) 10145f757f3fSDimitry Andric .addReg(RHS); 10155f757f3fSDimitry Andric 10165f757f3fSDimitry Andric MachineInstr &SetInst = *BuildMI(*I.getParent(), I, I.getDebugLoc(), 10175f757f3fSDimitry Andric TII.get(X86::SETCCr), I.getOperand(0).getReg()).addImm(CC); 10185f757f3fSDimitry Andric 10195f757f3fSDimitry Andric constrainSelectedInstRegOperands(CmpInst, TII, TRI, RBI); 10205f757f3fSDimitry Andric constrainSelectedInstRegOperands(SetInst, TII, TRI, RBI); 10215f757f3fSDimitry Andric 10225f757f3fSDimitry Andric I.eraseFromParent(); 10235f757f3fSDimitry Andric return true; 10245f757f3fSDimitry Andric } 10255f757f3fSDimitry Andric 10265f757f3fSDimitry Andric bool X86InstructionSelector::selectFCmp(MachineInstr &I, 10275f757f3fSDimitry Andric MachineRegisterInfo &MRI, 10285f757f3fSDimitry Andric MachineFunction &MF) const { 10295f757f3fSDimitry Andric assert((I.getOpcode() == TargetOpcode::G_FCMP) && "unexpected instruction"); 10305f757f3fSDimitry Andric 10315f757f3fSDimitry Andric Register LhsReg = I.getOperand(2).getReg(); 10325f757f3fSDimitry Andric Register RhsReg = I.getOperand(3).getReg(); 10335f757f3fSDimitry Andric CmpInst::Predicate Predicate = 10345f757f3fSDimitry Andric (CmpInst::Predicate)I.getOperand(1).getPredicate(); 10355f757f3fSDimitry Andric 10365f757f3fSDimitry Andric // FCMP_OEQ and FCMP_UNE cannot be checked with a single instruction. 10375f757f3fSDimitry Andric static const uint16_t SETFOpcTable[2][3] = { 10385f757f3fSDimitry Andric {X86::COND_E, X86::COND_NP, X86::AND8rr}, 10395f757f3fSDimitry Andric {X86::COND_NE, X86::COND_P, X86::OR8rr}}; 10405f757f3fSDimitry Andric const uint16_t *SETFOpc = nullptr; 10415f757f3fSDimitry Andric switch (Predicate) { 10425f757f3fSDimitry Andric default: 10435f757f3fSDimitry Andric break; 10445f757f3fSDimitry Andric case CmpInst::FCMP_OEQ: 10455f757f3fSDimitry Andric SETFOpc = &SETFOpcTable[0][0]; 10465f757f3fSDimitry Andric break; 10475f757f3fSDimitry Andric case CmpInst::FCMP_UNE: 10485f757f3fSDimitry Andric SETFOpc = &SETFOpcTable[1][0]; 10495f757f3fSDimitry Andric break; 10505f757f3fSDimitry Andric } 10515f757f3fSDimitry Andric 10525f757f3fSDimitry Andric // Compute the opcode for the CMP instruction. 10535f757f3fSDimitry Andric unsigned OpCmp; 10545f757f3fSDimitry Andric LLT Ty = MRI.getType(LhsReg); 10555f757f3fSDimitry Andric switch (Ty.getSizeInBits()) { 10565f757f3fSDimitry Andric default: 10575f757f3fSDimitry Andric return false; 10585f757f3fSDimitry Andric case 32: 10595f757f3fSDimitry Andric OpCmp = X86::UCOMISSrr; 10605f757f3fSDimitry Andric break; 10615f757f3fSDimitry Andric case 64: 10625f757f3fSDimitry Andric OpCmp = X86::UCOMISDrr; 10635f757f3fSDimitry Andric break; 10645f757f3fSDimitry Andric } 10655f757f3fSDimitry Andric 10665f757f3fSDimitry Andric Register ResultReg = I.getOperand(0).getReg(); 10675f757f3fSDimitry Andric RBI.constrainGenericRegister( 10685f757f3fSDimitry Andric ResultReg, 10695f757f3fSDimitry Andric *getRegClass(LLT::scalar(8), *RBI.getRegBank(ResultReg, MRI, TRI)), MRI); 10705f757f3fSDimitry Andric if (SETFOpc) { 10715f757f3fSDimitry Andric MachineInstr &CmpInst = 10725f757f3fSDimitry Andric *BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(OpCmp)) 10735f757f3fSDimitry Andric .addReg(LhsReg) 10745f757f3fSDimitry Andric .addReg(RhsReg); 10755f757f3fSDimitry Andric 10765f757f3fSDimitry Andric Register FlagReg1 = MRI.createVirtualRegister(&X86::GR8RegClass); 10775f757f3fSDimitry Andric Register FlagReg2 = MRI.createVirtualRegister(&X86::GR8RegClass); 10785f757f3fSDimitry Andric MachineInstr &Set1 = *BuildMI(*I.getParent(), I, I.getDebugLoc(), 10795f757f3fSDimitry Andric TII.get(X86::SETCCr), FlagReg1).addImm(SETFOpc[0]); 10805f757f3fSDimitry Andric MachineInstr &Set2 = *BuildMI(*I.getParent(), I, I.getDebugLoc(), 10815f757f3fSDimitry Andric TII.get(X86::SETCCr), FlagReg2).addImm(SETFOpc[1]); 10825f757f3fSDimitry Andric MachineInstr &Set3 = *BuildMI(*I.getParent(), I, I.getDebugLoc(), 10835f757f3fSDimitry Andric TII.get(SETFOpc[2]), ResultReg) 10845f757f3fSDimitry Andric .addReg(FlagReg1) 10855f757f3fSDimitry Andric .addReg(FlagReg2); 10865f757f3fSDimitry Andric constrainSelectedInstRegOperands(CmpInst, TII, TRI, RBI); 10875f757f3fSDimitry Andric constrainSelectedInstRegOperands(Set1, TII, TRI, RBI); 10885f757f3fSDimitry Andric constrainSelectedInstRegOperands(Set2, TII, TRI, RBI); 10895f757f3fSDimitry Andric constrainSelectedInstRegOperands(Set3, TII, TRI, RBI); 10905f757f3fSDimitry Andric 10915f757f3fSDimitry Andric I.eraseFromParent(); 10925f757f3fSDimitry Andric return true; 10935f757f3fSDimitry Andric } 10945f757f3fSDimitry Andric 10955f757f3fSDimitry Andric X86::CondCode CC; 10965f757f3fSDimitry Andric bool SwapArgs; 10975f757f3fSDimitry Andric std::tie(CC, SwapArgs) = X86::getX86ConditionCode(Predicate); 10985f757f3fSDimitry Andric assert(CC <= X86::LAST_VALID_COND && "Unexpected condition code."); 10995f757f3fSDimitry Andric 11005f757f3fSDimitry Andric if (SwapArgs) 11015f757f3fSDimitry Andric std::swap(LhsReg, RhsReg); 11025f757f3fSDimitry Andric 11035f757f3fSDimitry Andric // Emit a compare of LHS/RHS. 11045f757f3fSDimitry Andric MachineInstr &CmpInst = 11055f757f3fSDimitry Andric *BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(OpCmp)) 11065f757f3fSDimitry Andric .addReg(LhsReg) 11075f757f3fSDimitry Andric .addReg(RhsReg); 11085f757f3fSDimitry Andric 11095f757f3fSDimitry Andric MachineInstr &Set = 11105f757f3fSDimitry Andric *BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(X86::SETCCr), ResultReg).addImm(CC); 11115f757f3fSDimitry Andric constrainSelectedInstRegOperands(CmpInst, TII, TRI, RBI); 11125f757f3fSDimitry Andric constrainSelectedInstRegOperands(Set, TII, TRI, RBI); 11135f757f3fSDimitry Andric I.eraseFromParent(); 11145f757f3fSDimitry Andric return true; 11155f757f3fSDimitry Andric } 11165f757f3fSDimitry Andric 11175f757f3fSDimitry Andric bool X86InstructionSelector::selectUAddSub(MachineInstr &I, 11185f757f3fSDimitry Andric MachineRegisterInfo &MRI, 11195f757f3fSDimitry Andric MachineFunction &MF) const { 11205f757f3fSDimitry Andric assert((I.getOpcode() == TargetOpcode::G_UADDE || 11215f757f3fSDimitry Andric I.getOpcode() == TargetOpcode::G_UADDO || 11225f757f3fSDimitry Andric I.getOpcode() == TargetOpcode::G_USUBE || 11235f757f3fSDimitry Andric I.getOpcode() == TargetOpcode::G_USUBO) && 11245f757f3fSDimitry Andric "unexpected instruction"); 11255f757f3fSDimitry Andric 11265f757f3fSDimitry Andric const Register DstReg = I.getOperand(0).getReg(); 11275f757f3fSDimitry Andric const Register CarryOutReg = I.getOperand(1).getReg(); 11285f757f3fSDimitry Andric const Register Op0Reg = I.getOperand(2).getReg(); 11295f757f3fSDimitry Andric const Register Op1Reg = I.getOperand(3).getReg(); 11305f757f3fSDimitry Andric bool IsSub = I.getOpcode() == TargetOpcode::G_USUBE || 11315f757f3fSDimitry Andric I.getOpcode() == TargetOpcode::G_USUBO; 11325f757f3fSDimitry Andric bool HasCarryIn = I.getOpcode() == TargetOpcode::G_UADDE || 11335f757f3fSDimitry Andric I.getOpcode() == TargetOpcode::G_USUBE; 11345f757f3fSDimitry Andric 11355f757f3fSDimitry Andric const LLT DstTy = MRI.getType(DstReg); 11365f757f3fSDimitry Andric assert(DstTy.isScalar() && "selectUAddSub only supported for scalar types"); 11375f757f3fSDimitry Andric 11385f757f3fSDimitry Andric // TODO: Handle immediate argument variants? 11395f757f3fSDimitry Andric unsigned OpADC, OpADD, OpSBB, OpSUB; 11405f757f3fSDimitry Andric switch (DstTy.getSizeInBits()) { 11415f757f3fSDimitry Andric case 8: 11425f757f3fSDimitry Andric OpADC = X86::ADC8rr; 11435f757f3fSDimitry Andric OpADD = X86::ADD8rr; 11445f757f3fSDimitry Andric OpSBB = X86::SBB8rr; 11455f757f3fSDimitry Andric OpSUB = X86::SUB8rr; 11465f757f3fSDimitry Andric break; 11475f757f3fSDimitry Andric case 16: 11485f757f3fSDimitry Andric OpADC = X86::ADC16rr; 11495f757f3fSDimitry Andric OpADD = X86::ADD16rr; 11505f757f3fSDimitry Andric OpSBB = X86::SBB16rr; 11515f757f3fSDimitry Andric OpSUB = X86::SUB16rr; 11525f757f3fSDimitry Andric break; 11535f757f3fSDimitry Andric case 32: 11545f757f3fSDimitry Andric OpADC = X86::ADC32rr; 11555f757f3fSDimitry Andric OpADD = X86::ADD32rr; 11565f757f3fSDimitry Andric OpSBB = X86::SBB32rr; 11575f757f3fSDimitry Andric OpSUB = X86::SUB32rr; 11585f757f3fSDimitry Andric break; 11595f757f3fSDimitry Andric case 64: 11605f757f3fSDimitry Andric OpADC = X86::ADC64rr; 11615f757f3fSDimitry Andric OpADD = X86::ADD64rr; 11625f757f3fSDimitry Andric OpSBB = X86::SBB64rr; 11635f757f3fSDimitry Andric OpSUB = X86::SUB64rr; 11645f757f3fSDimitry Andric break; 11655f757f3fSDimitry Andric default: 11665f757f3fSDimitry Andric llvm_unreachable("selectUAddSub unsupported type."); 11675f757f3fSDimitry Andric } 11685f757f3fSDimitry Andric 11695f757f3fSDimitry Andric const RegisterBank &DstRB = *RBI.getRegBank(DstReg, MRI, TRI); 11705f757f3fSDimitry Andric const TargetRegisterClass *DstRC = getRegClass(DstTy, DstRB); 11715f757f3fSDimitry Andric 11725f757f3fSDimitry Andric unsigned Opcode = IsSub ? OpSUB : OpADD; 11735f757f3fSDimitry Andric 11745f757f3fSDimitry Andric // G_UADDE/G_USUBE - find CarryIn def instruction. 11755f757f3fSDimitry Andric if (HasCarryIn) { 11765f757f3fSDimitry Andric Register CarryInReg = I.getOperand(4).getReg(); 11775f757f3fSDimitry Andric MachineInstr *Def = MRI.getVRegDef(CarryInReg); 11785f757f3fSDimitry Andric while (Def->getOpcode() == TargetOpcode::G_TRUNC) { 11795f757f3fSDimitry Andric CarryInReg = Def->getOperand(1).getReg(); 11805f757f3fSDimitry Andric Def = MRI.getVRegDef(CarryInReg); 11815f757f3fSDimitry Andric } 11825f757f3fSDimitry Andric 11835f757f3fSDimitry Andric // TODO - handle more CF generating instructions 11845f757f3fSDimitry Andric if (Def->getOpcode() == TargetOpcode::G_UADDE || 11855f757f3fSDimitry Andric Def->getOpcode() == TargetOpcode::G_UADDO || 11865f757f3fSDimitry Andric Def->getOpcode() == TargetOpcode::G_USUBE || 11875f757f3fSDimitry Andric Def->getOpcode() == TargetOpcode::G_USUBO) { 11885f757f3fSDimitry Andric // carry set by prev ADD/SUB. 11895f757f3fSDimitry Andric BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(X86::COPY), 11905f757f3fSDimitry Andric X86::EFLAGS) 11915f757f3fSDimitry Andric .addReg(CarryInReg); 11925f757f3fSDimitry Andric 11935f757f3fSDimitry Andric if (!RBI.constrainGenericRegister(CarryInReg, *DstRC, MRI)) 11945f757f3fSDimitry Andric return false; 11955f757f3fSDimitry Andric 11965f757f3fSDimitry Andric Opcode = IsSub ? OpSBB : OpADC; 11975f757f3fSDimitry Andric } else if (auto val = getIConstantVRegVal(CarryInReg, MRI)) { 11985f757f3fSDimitry Andric // carry is constant, support only 0. 11995f757f3fSDimitry Andric if (*val != 0) 12005f757f3fSDimitry Andric return false; 12015f757f3fSDimitry Andric 12025f757f3fSDimitry Andric Opcode = IsSub ? OpSUB : OpADD; 12035f757f3fSDimitry Andric } else 12045f757f3fSDimitry Andric return false; 12055f757f3fSDimitry Andric } 12065f757f3fSDimitry Andric 12075f757f3fSDimitry Andric MachineInstr &Inst = 12085f757f3fSDimitry Andric *BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(Opcode), DstReg) 12095f757f3fSDimitry Andric .addReg(Op0Reg) 12105f757f3fSDimitry Andric .addReg(Op1Reg); 12115f757f3fSDimitry Andric 12125f757f3fSDimitry Andric BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(X86::COPY), CarryOutReg) 12135f757f3fSDimitry Andric .addReg(X86::EFLAGS); 12145f757f3fSDimitry Andric 12155f757f3fSDimitry Andric if (!constrainSelectedInstRegOperands(Inst, TII, TRI, RBI) || 12165f757f3fSDimitry Andric !RBI.constrainGenericRegister(CarryOutReg, *DstRC, MRI)) 12175f757f3fSDimitry Andric return false; 12185f757f3fSDimitry Andric 12195f757f3fSDimitry Andric I.eraseFromParent(); 12205f757f3fSDimitry Andric return true; 12215f757f3fSDimitry Andric } 12225f757f3fSDimitry Andric 12235f757f3fSDimitry Andric bool X86InstructionSelector::selectExtract(MachineInstr &I, 12245f757f3fSDimitry Andric MachineRegisterInfo &MRI, 12255f757f3fSDimitry Andric MachineFunction &MF) const { 12265f757f3fSDimitry Andric assert((I.getOpcode() == TargetOpcode::G_EXTRACT) && 12275f757f3fSDimitry Andric "unexpected instruction"); 12285f757f3fSDimitry Andric 12295f757f3fSDimitry Andric const Register DstReg = I.getOperand(0).getReg(); 12305f757f3fSDimitry Andric const Register SrcReg = I.getOperand(1).getReg(); 12315f757f3fSDimitry Andric int64_t Index = I.getOperand(2).getImm(); 12325f757f3fSDimitry Andric 12335f757f3fSDimitry Andric const LLT DstTy = MRI.getType(DstReg); 12345f757f3fSDimitry Andric const LLT SrcTy = MRI.getType(SrcReg); 12355f757f3fSDimitry Andric 12365f757f3fSDimitry Andric // Meanwile handle vector type only. 12375f757f3fSDimitry Andric if (!DstTy.isVector()) 12385f757f3fSDimitry Andric return false; 12395f757f3fSDimitry Andric 12405f757f3fSDimitry Andric if (Index % DstTy.getSizeInBits() != 0) 12415f757f3fSDimitry Andric return false; // Not extract subvector. 12425f757f3fSDimitry Andric 12435f757f3fSDimitry Andric if (Index == 0) { 12445f757f3fSDimitry Andric // Replace by extract subreg copy. 12455f757f3fSDimitry Andric if (!emitExtractSubreg(DstReg, SrcReg, I, MRI, MF)) 12465f757f3fSDimitry Andric return false; 12475f757f3fSDimitry Andric 12485f757f3fSDimitry Andric I.eraseFromParent(); 12495f757f3fSDimitry Andric return true; 12505f757f3fSDimitry Andric } 12515f757f3fSDimitry Andric 12525f757f3fSDimitry Andric bool HasAVX = STI.hasAVX(); 12535f757f3fSDimitry Andric bool HasAVX512 = STI.hasAVX512(); 12545f757f3fSDimitry Andric bool HasVLX = STI.hasVLX(); 12555f757f3fSDimitry Andric 12565f757f3fSDimitry Andric if (SrcTy.getSizeInBits() == 256 && DstTy.getSizeInBits() == 128) { 12575f757f3fSDimitry Andric if (HasVLX) 12585f757f3fSDimitry Andric I.setDesc(TII.get(X86::VEXTRACTF32x4Z256rr)); 12595f757f3fSDimitry Andric else if (HasAVX) 12605f757f3fSDimitry Andric I.setDesc(TII.get(X86::VEXTRACTF128rr)); 12615f757f3fSDimitry Andric else 12625f757f3fSDimitry Andric return false; 12635f757f3fSDimitry Andric } else if (SrcTy.getSizeInBits() == 512 && HasAVX512) { 12645f757f3fSDimitry Andric if (DstTy.getSizeInBits() == 128) 12655f757f3fSDimitry Andric I.setDesc(TII.get(X86::VEXTRACTF32x4Zrr)); 12665f757f3fSDimitry Andric else if (DstTy.getSizeInBits() == 256) 12675f757f3fSDimitry Andric I.setDesc(TII.get(X86::VEXTRACTF64x4Zrr)); 12685f757f3fSDimitry Andric else 12695f757f3fSDimitry Andric return false; 12705f757f3fSDimitry Andric } else 12715f757f3fSDimitry Andric return false; 12725f757f3fSDimitry Andric 12735f757f3fSDimitry Andric // Convert to X86 VEXTRACT immediate. 12745f757f3fSDimitry Andric Index = Index / DstTy.getSizeInBits(); 12755f757f3fSDimitry Andric I.getOperand(2).setImm(Index); 12765f757f3fSDimitry Andric 12775f757f3fSDimitry Andric return constrainSelectedInstRegOperands(I, TII, TRI, RBI); 12785f757f3fSDimitry Andric } 12795f757f3fSDimitry Andric 12805f757f3fSDimitry Andric bool X86InstructionSelector::emitExtractSubreg(unsigned DstReg, unsigned SrcReg, 12815f757f3fSDimitry Andric MachineInstr &I, 12825f757f3fSDimitry Andric MachineRegisterInfo &MRI, 12835f757f3fSDimitry Andric MachineFunction &MF) const { 12845f757f3fSDimitry Andric const LLT DstTy = MRI.getType(DstReg); 12855f757f3fSDimitry Andric const LLT SrcTy = MRI.getType(SrcReg); 12865f757f3fSDimitry Andric unsigned SubIdx = X86::NoSubRegister; 12875f757f3fSDimitry Andric 12885f757f3fSDimitry Andric if (!DstTy.isVector() || !SrcTy.isVector()) 12895f757f3fSDimitry Andric return false; 12905f757f3fSDimitry Andric 12915f757f3fSDimitry Andric assert(SrcTy.getSizeInBits() > DstTy.getSizeInBits() && 12925f757f3fSDimitry Andric "Incorrect Src/Dst register size"); 12935f757f3fSDimitry Andric 12945f757f3fSDimitry Andric if (DstTy.getSizeInBits() == 128) 12955f757f3fSDimitry Andric SubIdx = X86::sub_xmm; 12965f757f3fSDimitry Andric else if (DstTy.getSizeInBits() == 256) 12975f757f3fSDimitry Andric SubIdx = X86::sub_ymm; 12985f757f3fSDimitry Andric else 12995f757f3fSDimitry Andric return false; 13005f757f3fSDimitry Andric 13015f757f3fSDimitry Andric const TargetRegisterClass *DstRC = getRegClass(DstTy, DstReg, MRI); 13025f757f3fSDimitry Andric const TargetRegisterClass *SrcRC = getRegClass(SrcTy, SrcReg, MRI); 13035f757f3fSDimitry Andric 13045f757f3fSDimitry Andric SrcRC = TRI.getSubClassWithSubReg(SrcRC, SubIdx); 13055f757f3fSDimitry Andric 13065f757f3fSDimitry Andric if (!RBI.constrainGenericRegister(SrcReg, *SrcRC, MRI) || 13075f757f3fSDimitry Andric !RBI.constrainGenericRegister(DstReg, *DstRC, MRI)) { 13085f757f3fSDimitry Andric LLVM_DEBUG(dbgs() << "Failed to constrain EXTRACT_SUBREG\n"); 13095f757f3fSDimitry Andric return false; 13105f757f3fSDimitry Andric } 13115f757f3fSDimitry Andric 13125f757f3fSDimitry Andric BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(X86::COPY), DstReg) 13135f757f3fSDimitry Andric .addReg(SrcReg, 0, SubIdx); 13145f757f3fSDimitry Andric 13155f757f3fSDimitry Andric return true; 13165f757f3fSDimitry Andric } 13175f757f3fSDimitry Andric 13185f757f3fSDimitry Andric bool X86InstructionSelector::emitInsertSubreg(unsigned DstReg, unsigned SrcReg, 13195f757f3fSDimitry Andric MachineInstr &I, 13205f757f3fSDimitry Andric MachineRegisterInfo &MRI, 13215f757f3fSDimitry Andric MachineFunction &MF) const { 13225f757f3fSDimitry Andric const LLT DstTy = MRI.getType(DstReg); 13235f757f3fSDimitry Andric const LLT SrcTy = MRI.getType(SrcReg); 13245f757f3fSDimitry Andric unsigned SubIdx = X86::NoSubRegister; 13255f757f3fSDimitry Andric 13265f757f3fSDimitry Andric // TODO: support scalar types 13275f757f3fSDimitry Andric if (!DstTy.isVector() || !SrcTy.isVector()) 13285f757f3fSDimitry Andric return false; 13295f757f3fSDimitry Andric 13305f757f3fSDimitry Andric assert(SrcTy.getSizeInBits() < DstTy.getSizeInBits() && 13315f757f3fSDimitry Andric "Incorrect Src/Dst register size"); 13325f757f3fSDimitry Andric 13335f757f3fSDimitry Andric if (SrcTy.getSizeInBits() == 128) 13345f757f3fSDimitry Andric SubIdx = X86::sub_xmm; 13355f757f3fSDimitry Andric else if (SrcTy.getSizeInBits() == 256) 13365f757f3fSDimitry Andric SubIdx = X86::sub_ymm; 13375f757f3fSDimitry Andric else 13385f757f3fSDimitry Andric return false; 13395f757f3fSDimitry Andric 13405f757f3fSDimitry Andric const TargetRegisterClass *SrcRC = getRegClass(SrcTy, SrcReg, MRI); 13415f757f3fSDimitry Andric const TargetRegisterClass *DstRC = getRegClass(DstTy, DstReg, MRI); 13425f757f3fSDimitry Andric 13435f757f3fSDimitry Andric if (!RBI.constrainGenericRegister(SrcReg, *SrcRC, MRI) || 13445f757f3fSDimitry Andric !RBI.constrainGenericRegister(DstReg, *DstRC, MRI)) { 13455f757f3fSDimitry Andric LLVM_DEBUG(dbgs() << "Failed to constrain INSERT_SUBREG\n"); 13465f757f3fSDimitry Andric return false; 13475f757f3fSDimitry Andric } 13485f757f3fSDimitry Andric 13495f757f3fSDimitry Andric BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(X86::COPY)) 13505f757f3fSDimitry Andric .addReg(DstReg, RegState::DefineNoRead, SubIdx) 13515f757f3fSDimitry Andric .addReg(SrcReg); 13525f757f3fSDimitry Andric 13535f757f3fSDimitry Andric return true; 13545f757f3fSDimitry Andric } 13555f757f3fSDimitry Andric 13565f757f3fSDimitry Andric bool X86InstructionSelector::selectInsert(MachineInstr &I, 13575f757f3fSDimitry Andric MachineRegisterInfo &MRI, 13585f757f3fSDimitry Andric MachineFunction &MF) const { 13595f757f3fSDimitry Andric assert((I.getOpcode() == TargetOpcode::G_INSERT) && "unexpected instruction"); 13605f757f3fSDimitry Andric 13615f757f3fSDimitry Andric const Register DstReg = I.getOperand(0).getReg(); 13625f757f3fSDimitry Andric const Register SrcReg = I.getOperand(1).getReg(); 13635f757f3fSDimitry Andric const Register InsertReg = I.getOperand(2).getReg(); 13645f757f3fSDimitry Andric int64_t Index = I.getOperand(3).getImm(); 13655f757f3fSDimitry Andric 13665f757f3fSDimitry Andric const LLT DstTy = MRI.getType(DstReg); 13675f757f3fSDimitry Andric const LLT InsertRegTy = MRI.getType(InsertReg); 13685f757f3fSDimitry Andric 13695f757f3fSDimitry Andric // Meanwile handle vector type only. 13705f757f3fSDimitry Andric if (!DstTy.isVector()) 13715f757f3fSDimitry Andric return false; 13725f757f3fSDimitry Andric 13735f757f3fSDimitry Andric if (Index % InsertRegTy.getSizeInBits() != 0) 13745f757f3fSDimitry Andric return false; // Not insert subvector. 13755f757f3fSDimitry Andric 13765f757f3fSDimitry Andric if (Index == 0 && MRI.getVRegDef(SrcReg)->isImplicitDef()) { 13775f757f3fSDimitry Andric // Replace by subreg copy. 13785f757f3fSDimitry Andric if (!emitInsertSubreg(DstReg, InsertReg, I, MRI, MF)) 13795f757f3fSDimitry Andric return false; 13805f757f3fSDimitry Andric 13815f757f3fSDimitry Andric I.eraseFromParent(); 13825f757f3fSDimitry Andric return true; 13835f757f3fSDimitry Andric } 13845f757f3fSDimitry Andric 13855f757f3fSDimitry Andric bool HasAVX = STI.hasAVX(); 13865f757f3fSDimitry Andric bool HasAVX512 = STI.hasAVX512(); 13875f757f3fSDimitry Andric bool HasVLX = STI.hasVLX(); 13885f757f3fSDimitry Andric 13895f757f3fSDimitry Andric if (DstTy.getSizeInBits() == 256 && InsertRegTy.getSizeInBits() == 128) { 13905f757f3fSDimitry Andric if (HasVLX) 13915f757f3fSDimitry Andric I.setDesc(TII.get(X86::VINSERTF32x4Z256rr)); 13925f757f3fSDimitry Andric else if (HasAVX) 13935f757f3fSDimitry Andric I.setDesc(TII.get(X86::VINSERTF128rr)); 13945f757f3fSDimitry Andric else 13955f757f3fSDimitry Andric return false; 13965f757f3fSDimitry Andric } else if (DstTy.getSizeInBits() == 512 && HasAVX512) { 13975f757f3fSDimitry Andric if (InsertRegTy.getSizeInBits() == 128) 13985f757f3fSDimitry Andric I.setDesc(TII.get(X86::VINSERTF32x4Zrr)); 13995f757f3fSDimitry Andric else if (InsertRegTy.getSizeInBits() == 256) 14005f757f3fSDimitry Andric I.setDesc(TII.get(X86::VINSERTF64x4Zrr)); 14015f757f3fSDimitry Andric else 14025f757f3fSDimitry Andric return false; 14035f757f3fSDimitry Andric } else 14045f757f3fSDimitry Andric return false; 14055f757f3fSDimitry Andric 14065f757f3fSDimitry Andric // Convert to X86 VINSERT immediate. 14075f757f3fSDimitry Andric Index = Index / InsertRegTy.getSizeInBits(); 14085f757f3fSDimitry Andric 14095f757f3fSDimitry Andric I.getOperand(3).setImm(Index); 14105f757f3fSDimitry Andric 14115f757f3fSDimitry Andric return constrainSelectedInstRegOperands(I, TII, TRI, RBI); 14125f757f3fSDimitry Andric } 14135f757f3fSDimitry Andric 14145f757f3fSDimitry Andric bool X86InstructionSelector::selectUnmergeValues( 14155f757f3fSDimitry Andric MachineInstr &I, MachineRegisterInfo &MRI, MachineFunction &MF) { 14165f757f3fSDimitry Andric assert((I.getOpcode() == TargetOpcode::G_UNMERGE_VALUES) && 14175f757f3fSDimitry Andric "unexpected instruction"); 14185f757f3fSDimitry Andric 14195f757f3fSDimitry Andric // Split to extracts. 14205f757f3fSDimitry Andric unsigned NumDefs = I.getNumOperands() - 1; 14215f757f3fSDimitry Andric Register SrcReg = I.getOperand(NumDefs).getReg(); 14225f757f3fSDimitry Andric unsigned DefSize = MRI.getType(I.getOperand(0).getReg()).getSizeInBits(); 14235f757f3fSDimitry Andric 14245f757f3fSDimitry Andric for (unsigned Idx = 0; Idx < NumDefs; ++Idx) { 14255f757f3fSDimitry Andric MachineInstr &ExtrInst = 14265f757f3fSDimitry Andric *BuildMI(*I.getParent(), I, I.getDebugLoc(), 14275f757f3fSDimitry Andric TII.get(TargetOpcode::G_EXTRACT), I.getOperand(Idx).getReg()) 14285f757f3fSDimitry Andric .addReg(SrcReg) 14295f757f3fSDimitry Andric .addImm(Idx * DefSize); 14305f757f3fSDimitry Andric 14315f757f3fSDimitry Andric if (!select(ExtrInst)) 14325f757f3fSDimitry Andric return false; 14335f757f3fSDimitry Andric } 14345f757f3fSDimitry Andric 14355f757f3fSDimitry Andric I.eraseFromParent(); 14365f757f3fSDimitry Andric return true; 14375f757f3fSDimitry Andric } 14385f757f3fSDimitry Andric 14395f757f3fSDimitry Andric bool X86InstructionSelector::selectMergeValues( 14405f757f3fSDimitry Andric MachineInstr &I, MachineRegisterInfo &MRI, MachineFunction &MF) { 14415f757f3fSDimitry Andric assert((I.getOpcode() == TargetOpcode::G_MERGE_VALUES || 14425f757f3fSDimitry Andric I.getOpcode() == TargetOpcode::G_CONCAT_VECTORS) && 14435f757f3fSDimitry Andric "unexpected instruction"); 14445f757f3fSDimitry Andric 14455f757f3fSDimitry Andric // Split to inserts. 14465f757f3fSDimitry Andric Register DstReg = I.getOperand(0).getReg(); 14475f757f3fSDimitry Andric Register SrcReg0 = I.getOperand(1).getReg(); 14485f757f3fSDimitry Andric 14495f757f3fSDimitry Andric const LLT DstTy = MRI.getType(DstReg); 14505f757f3fSDimitry Andric const LLT SrcTy = MRI.getType(SrcReg0); 14515f757f3fSDimitry Andric unsigned SrcSize = SrcTy.getSizeInBits(); 14525f757f3fSDimitry Andric 14535f757f3fSDimitry Andric const RegisterBank &RegBank = *RBI.getRegBank(DstReg, MRI, TRI); 14545f757f3fSDimitry Andric 14555f757f3fSDimitry Andric // For the first src use insertSubReg. 14565f757f3fSDimitry Andric Register DefReg = MRI.createGenericVirtualRegister(DstTy); 14575f757f3fSDimitry Andric MRI.setRegBank(DefReg, RegBank); 14585f757f3fSDimitry Andric if (!emitInsertSubreg(DefReg, I.getOperand(1).getReg(), I, MRI, MF)) 14595f757f3fSDimitry Andric return false; 14605f757f3fSDimitry Andric 14615f757f3fSDimitry Andric for (unsigned Idx = 2; Idx < I.getNumOperands(); ++Idx) { 14625f757f3fSDimitry Andric Register Tmp = MRI.createGenericVirtualRegister(DstTy); 14635f757f3fSDimitry Andric MRI.setRegBank(Tmp, RegBank); 14645f757f3fSDimitry Andric 14655f757f3fSDimitry Andric MachineInstr &InsertInst = *BuildMI(*I.getParent(), I, I.getDebugLoc(), 14665f757f3fSDimitry Andric TII.get(TargetOpcode::G_INSERT), Tmp) 14675f757f3fSDimitry Andric .addReg(DefReg) 14685f757f3fSDimitry Andric .addReg(I.getOperand(Idx).getReg()) 14695f757f3fSDimitry Andric .addImm((Idx - 1) * SrcSize); 14705f757f3fSDimitry Andric 14715f757f3fSDimitry Andric DefReg = Tmp; 14725f757f3fSDimitry Andric 14735f757f3fSDimitry Andric if (!select(InsertInst)) 14745f757f3fSDimitry Andric return false; 14755f757f3fSDimitry Andric } 14765f757f3fSDimitry Andric 14775f757f3fSDimitry Andric MachineInstr &CopyInst = *BuildMI(*I.getParent(), I, I.getDebugLoc(), 14785f757f3fSDimitry Andric TII.get(TargetOpcode::COPY), DstReg) 14795f757f3fSDimitry Andric .addReg(DefReg); 14805f757f3fSDimitry Andric 14815f757f3fSDimitry Andric if (!select(CopyInst)) 14825f757f3fSDimitry Andric return false; 14835f757f3fSDimitry Andric 14845f757f3fSDimitry Andric I.eraseFromParent(); 14855f757f3fSDimitry Andric return true; 14865f757f3fSDimitry Andric } 14875f757f3fSDimitry Andric 14885f757f3fSDimitry Andric bool X86InstructionSelector::selectCondBranch(MachineInstr &I, 14895f757f3fSDimitry Andric MachineRegisterInfo &MRI, 14905f757f3fSDimitry Andric MachineFunction &MF) const { 14915f757f3fSDimitry Andric assert((I.getOpcode() == TargetOpcode::G_BRCOND) && "unexpected instruction"); 14925f757f3fSDimitry Andric 14935f757f3fSDimitry Andric const Register CondReg = I.getOperand(0).getReg(); 14945f757f3fSDimitry Andric MachineBasicBlock *DestMBB = I.getOperand(1).getMBB(); 14955f757f3fSDimitry Andric 14965f757f3fSDimitry Andric MachineInstr &TestInst = 14975f757f3fSDimitry Andric *BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(X86::TEST8ri)) 14985f757f3fSDimitry Andric .addReg(CondReg) 14995f757f3fSDimitry Andric .addImm(1); 15005f757f3fSDimitry Andric BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(X86::JCC_1)) 15015f757f3fSDimitry Andric .addMBB(DestMBB).addImm(X86::COND_NE); 15025f757f3fSDimitry Andric 15035f757f3fSDimitry Andric constrainSelectedInstRegOperands(TestInst, TII, TRI, RBI); 15045f757f3fSDimitry Andric 15055f757f3fSDimitry Andric I.eraseFromParent(); 15065f757f3fSDimitry Andric return true; 15075f757f3fSDimitry Andric } 15085f757f3fSDimitry Andric 15095f757f3fSDimitry Andric bool X86InstructionSelector::materializeFP(MachineInstr &I, 15105f757f3fSDimitry Andric MachineRegisterInfo &MRI, 15115f757f3fSDimitry Andric MachineFunction &MF) const { 15125f757f3fSDimitry Andric assert((I.getOpcode() == TargetOpcode::G_FCONSTANT) && 15135f757f3fSDimitry Andric "unexpected instruction"); 15145f757f3fSDimitry Andric 15155f757f3fSDimitry Andric // Can't handle alternate code models yet. 15165f757f3fSDimitry Andric CodeModel::Model CM = TM.getCodeModel(); 15175f757f3fSDimitry Andric if (CM != CodeModel::Small && CM != CodeModel::Large) 15185f757f3fSDimitry Andric return false; 15195f757f3fSDimitry Andric 15205f757f3fSDimitry Andric const Register DstReg = I.getOperand(0).getReg(); 15215f757f3fSDimitry Andric const LLT DstTy = MRI.getType(DstReg); 15225f757f3fSDimitry Andric const RegisterBank &RegBank = *RBI.getRegBank(DstReg, MRI, TRI); 1523*0fca6ea1SDimitry Andric // Create the load from the constant pool. 1524*0fca6ea1SDimitry Andric const ConstantFP *CFP = I.getOperand(1).getFPImm(); 1525*0fca6ea1SDimitry Andric const auto &DL = MF.getDataLayout(); 1526*0fca6ea1SDimitry Andric Align Alignment = DL.getPrefTypeAlign(CFP->getType()); 15275f757f3fSDimitry Andric const DebugLoc &DbgLoc = I.getDebugLoc(); 15285f757f3fSDimitry Andric 15295f757f3fSDimitry Andric unsigned Opc = 15305f757f3fSDimitry Andric getLoadStoreOp(DstTy, RegBank, TargetOpcode::G_LOAD, Alignment); 15315f757f3fSDimitry Andric 15325f757f3fSDimitry Andric unsigned CPI = MF.getConstantPool()->getConstantPoolIndex(CFP, Alignment); 15335f757f3fSDimitry Andric MachineInstr *LoadInst = nullptr; 15345f757f3fSDimitry Andric unsigned char OpFlag = STI.classifyLocalReference(nullptr); 15355f757f3fSDimitry Andric 15365f757f3fSDimitry Andric if (CM == CodeModel::Large && STI.is64Bit()) { 15375f757f3fSDimitry Andric // Under X86-64 non-small code model, GV (and friends) are 64-bits, so 15385f757f3fSDimitry Andric // they cannot be folded into immediate fields. 15395f757f3fSDimitry Andric 15405f757f3fSDimitry Andric Register AddrReg = MRI.createVirtualRegister(&X86::GR64RegClass); 15415f757f3fSDimitry Andric BuildMI(*I.getParent(), I, DbgLoc, TII.get(X86::MOV64ri), AddrReg) 15425f757f3fSDimitry Andric .addConstantPoolIndex(CPI, 0, OpFlag); 15435f757f3fSDimitry Andric 15445f757f3fSDimitry Andric MachineMemOperand *MMO = MF.getMachineMemOperand( 15455f757f3fSDimitry Andric MachinePointerInfo::getConstantPool(MF), MachineMemOperand::MOLoad, 1546*0fca6ea1SDimitry Andric LLT::pointer(0, DL.getPointerSizeInBits()), Alignment); 15475f757f3fSDimitry Andric 15485f757f3fSDimitry Andric LoadInst = 15495f757f3fSDimitry Andric addDirectMem(BuildMI(*I.getParent(), I, DbgLoc, TII.get(Opc), DstReg), 15505f757f3fSDimitry Andric AddrReg) 15515f757f3fSDimitry Andric .addMemOperand(MMO); 15525f757f3fSDimitry Andric 15535f757f3fSDimitry Andric } else if (CM == CodeModel::Small || !STI.is64Bit()) { 15545f757f3fSDimitry Andric // Handle the case when globals fit in our immediate field. 15555f757f3fSDimitry Andric // This is true for X86-32 always and X86-64 when in -mcmodel=small mode. 15565f757f3fSDimitry Andric 15575f757f3fSDimitry Andric // x86-32 PIC requires a PIC base register for constant pools. 15585f757f3fSDimitry Andric unsigned PICBase = 0; 15595f757f3fSDimitry Andric if (OpFlag == X86II::MO_PIC_BASE_OFFSET || OpFlag == X86II::MO_GOTOFF) { 15605f757f3fSDimitry Andric // PICBase can be allocated by TII.getGlobalBaseReg(&MF). 15615f757f3fSDimitry Andric // In DAGISEL the code that initialize it generated by the CGBR pass. 15625f757f3fSDimitry Andric return false; // TODO support the mode. 15635f757f3fSDimitry Andric } else if (STI.is64Bit() && TM.getCodeModel() == CodeModel::Small) 15645f757f3fSDimitry Andric PICBase = X86::RIP; 15655f757f3fSDimitry Andric 15665f757f3fSDimitry Andric LoadInst = addConstantPoolReference( 15675f757f3fSDimitry Andric BuildMI(*I.getParent(), I, DbgLoc, TII.get(Opc), DstReg), CPI, PICBase, 15685f757f3fSDimitry Andric OpFlag); 15695f757f3fSDimitry Andric } else 15705f757f3fSDimitry Andric return false; 15715f757f3fSDimitry Andric 15725f757f3fSDimitry Andric constrainSelectedInstRegOperands(*LoadInst, TII, TRI, RBI); 15735f757f3fSDimitry Andric I.eraseFromParent(); 15745f757f3fSDimitry Andric return true; 15755f757f3fSDimitry Andric } 15765f757f3fSDimitry Andric 15775f757f3fSDimitry Andric bool X86InstructionSelector::selectImplicitDefOrPHI( 15785f757f3fSDimitry Andric MachineInstr &I, MachineRegisterInfo &MRI) const { 15795f757f3fSDimitry Andric assert((I.getOpcode() == TargetOpcode::G_IMPLICIT_DEF || 15805f757f3fSDimitry Andric I.getOpcode() == TargetOpcode::G_PHI) && 15815f757f3fSDimitry Andric "unexpected instruction"); 15825f757f3fSDimitry Andric 15835f757f3fSDimitry Andric Register DstReg = I.getOperand(0).getReg(); 15845f757f3fSDimitry Andric 15855f757f3fSDimitry Andric if (!MRI.getRegClassOrNull(DstReg)) { 15865f757f3fSDimitry Andric const LLT DstTy = MRI.getType(DstReg); 15875f757f3fSDimitry Andric const TargetRegisterClass *RC = getRegClass(DstTy, DstReg, MRI); 15885f757f3fSDimitry Andric 15895f757f3fSDimitry Andric if (!RBI.constrainGenericRegister(DstReg, *RC, MRI)) { 15905f757f3fSDimitry Andric LLVM_DEBUG(dbgs() << "Failed to constrain " << TII.getName(I.getOpcode()) 15915f757f3fSDimitry Andric << " operand\n"); 15925f757f3fSDimitry Andric return false; 15935f757f3fSDimitry Andric } 15945f757f3fSDimitry Andric } 15955f757f3fSDimitry Andric 15965f757f3fSDimitry Andric if (I.getOpcode() == TargetOpcode::G_IMPLICIT_DEF) 15975f757f3fSDimitry Andric I.setDesc(TII.get(X86::IMPLICIT_DEF)); 15985f757f3fSDimitry Andric else 15995f757f3fSDimitry Andric I.setDesc(TII.get(X86::PHI)); 16005f757f3fSDimitry Andric 16015f757f3fSDimitry Andric return true; 16025f757f3fSDimitry Andric } 16035f757f3fSDimitry Andric 16045f757f3fSDimitry Andric bool X86InstructionSelector::selectMulDivRem(MachineInstr &I, 16055f757f3fSDimitry Andric MachineRegisterInfo &MRI, 16065f757f3fSDimitry Andric MachineFunction &MF) const { 16075f757f3fSDimitry Andric // The implementation of this function is adapted from X86FastISel. 16085f757f3fSDimitry Andric assert((I.getOpcode() == TargetOpcode::G_MUL || 16095f757f3fSDimitry Andric I.getOpcode() == TargetOpcode::G_SMULH || 16105f757f3fSDimitry Andric I.getOpcode() == TargetOpcode::G_UMULH || 16115f757f3fSDimitry Andric I.getOpcode() == TargetOpcode::G_SDIV || 16125f757f3fSDimitry Andric I.getOpcode() == TargetOpcode::G_SREM || 16135f757f3fSDimitry Andric I.getOpcode() == TargetOpcode::G_UDIV || 16145f757f3fSDimitry Andric I.getOpcode() == TargetOpcode::G_UREM) && 16155f757f3fSDimitry Andric "unexpected instruction"); 16165f757f3fSDimitry Andric 16175f757f3fSDimitry Andric const Register DstReg = I.getOperand(0).getReg(); 16185f757f3fSDimitry Andric const Register Op1Reg = I.getOperand(1).getReg(); 16195f757f3fSDimitry Andric const Register Op2Reg = I.getOperand(2).getReg(); 16205f757f3fSDimitry Andric 16215f757f3fSDimitry Andric const LLT RegTy = MRI.getType(DstReg); 16225f757f3fSDimitry Andric assert(RegTy == MRI.getType(Op1Reg) && RegTy == MRI.getType(Op2Reg) && 16235f757f3fSDimitry Andric "Arguments and return value types must match"); 16245f757f3fSDimitry Andric 16255f757f3fSDimitry Andric const RegisterBank *RegRB = RBI.getRegBank(DstReg, MRI, TRI); 16265f757f3fSDimitry Andric if (!RegRB || RegRB->getID() != X86::GPRRegBankID) 16275f757f3fSDimitry Andric return false; 16285f757f3fSDimitry Andric 16295f757f3fSDimitry Andric const static unsigned NumTypes = 4; // i8, i16, i32, i64 16305f757f3fSDimitry Andric const static unsigned NumOps = 7; // SDiv/SRem/UDiv/URem/Mul/SMulH/UMulh 16315f757f3fSDimitry Andric const static bool S = true; // IsSigned 16325f757f3fSDimitry Andric const static bool U = false; // !IsSigned 16335f757f3fSDimitry Andric const static unsigned Copy = TargetOpcode::COPY; 16345f757f3fSDimitry Andric 16355f757f3fSDimitry Andric // For the X86 IDIV instruction, in most cases the dividend 16365f757f3fSDimitry Andric // (numerator) must be in a specific register pair highreg:lowreg, 16375f757f3fSDimitry Andric // producing the quotient in lowreg and the remainder in highreg. 16385f757f3fSDimitry Andric // For most data types, to set up the instruction, the dividend is 16395f757f3fSDimitry Andric // copied into lowreg, and lowreg is sign-extended into highreg. The 16405f757f3fSDimitry Andric // exception is i8, where the dividend is defined as a single register rather 16415f757f3fSDimitry Andric // than a register pair, and we therefore directly sign-extend the dividend 16425f757f3fSDimitry Andric // into lowreg, instead of copying, and ignore the highreg. 16435f757f3fSDimitry Andric const static struct MulDivRemEntry { 16445f757f3fSDimitry Andric // The following portion depends only on the data type. 16455f757f3fSDimitry Andric unsigned SizeInBits; 16465f757f3fSDimitry Andric unsigned LowInReg; // low part of the register pair 16475f757f3fSDimitry Andric unsigned HighInReg; // high part of the register pair 16485f757f3fSDimitry Andric // The following portion depends on both the data type and the operation. 16495f757f3fSDimitry Andric struct MulDivRemResult { 16505f757f3fSDimitry Andric unsigned OpMulDivRem; // The specific MUL/DIV opcode to use. 16515f757f3fSDimitry Andric unsigned OpSignExtend; // Opcode for sign-extending lowreg into 16525f757f3fSDimitry Andric // highreg, or copying a zero into highreg. 16535f757f3fSDimitry Andric unsigned OpCopy; // Opcode for copying dividend into lowreg, or 16545f757f3fSDimitry Andric // zero/sign-extending into lowreg for i8. 16555f757f3fSDimitry Andric unsigned ResultReg; // Register containing the desired result. 16565f757f3fSDimitry Andric bool IsOpSigned; // Whether to use signed or unsigned form. 16575f757f3fSDimitry Andric } ResultTable[NumOps]; 16585f757f3fSDimitry Andric } OpTable[NumTypes] = { 16595f757f3fSDimitry Andric {8, 16605f757f3fSDimitry Andric X86::AX, 16615f757f3fSDimitry Andric 0, 16625f757f3fSDimitry Andric { 16635f757f3fSDimitry Andric {X86::IDIV8r, 0, X86::MOVSX16rr8, X86::AL, S}, // SDiv 16645f757f3fSDimitry Andric {X86::IDIV8r, 0, X86::MOVSX16rr8, X86::AH, S}, // SRem 16655f757f3fSDimitry Andric {X86::DIV8r, 0, X86::MOVZX16rr8, X86::AL, U}, // UDiv 16665f757f3fSDimitry Andric {X86::DIV8r, 0, X86::MOVZX16rr8, X86::AH, U}, // URem 16675f757f3fSDimitry Andric {X86::IMUL8r, 0, X86::MOVSX16rr8, X86::AL, S}, // Mul 16685f757f3fSDimitry Andric {X86::IMUL8r, 0, X86::MOVSX16rr8, X86::AH, S}, // SMulH 16695f757f3fSDimitry Andric {X86::MUL8r, 0, X86::MOVZX16rr8, X86::AH, U}, // UMulH 16705f757f3fSDimitry Andric }}, // i8 16715f757f3fSDimitry Andric {16, 16725f757f3fSDimitry Andric X86::AX, 16735f757f3fSDimitry Andric X86::DX, 16745f757f3fSDimitry Andric { 16755f757f3fSDimitry Andric {X86::IDIV16r, X86::CWD, Copy, X86::AX, S}, // SDiv 16765f757f3fSDimitry Andric {X86::IDIV16r, X86::CWD, Copy, X86::DX, S}, // SRem 16775f757f3fSDimitry Andric {X86::DIV16r, X86::MOV32r0, Copy, X86::AX, U}, // UDiv 16785f757f3fSDimitry Andric {X86::DIV16r, X86::MOV32r0, Copy, X86::DX, U}, // URem 16795f757f3fSDimitry Andric {X86::IMUL16r, X86::MOV32r0, Copy, X86::AX, S}, // Mul 16805f757f3fSDimitry Andric {X86::IMUL16r, X86::MOV32r0, Copy, X86::DX, S}, // SMulH 16815f757f3fSDimitry Andric {X86::MUL16r, X86::MOV32r0, Copy, X86::DX, U}, // UMulH 16825f757f3fSDimitry Andric }}, // i16 16835f757f3fSDimitry Andric {32, 16845f757f3fSDimitry Andric X86::EAX, 16855f757f3fSDimitry Andric X86::EDX, 16865f757f3fSDimitry Andric { 16875f757f3fSDimitry Andric {X86::IDIV32r, X86::CDQ, Copy, X86::EAX, S}, // SDiv 16885f757f3fSDimitry Andric {X86::IDIV32r, X86::CDQ, Copy, X86::EDX, S}, // SRem 16895f757f3fSDimitry Andric {X86::DIV32r, X86::MOV32r0, Copy, X86::EAX, U}, // UDiv 16905f757f3fSDimitry Andric {X86::DIV32r, X86::MOV32r0, Copy, X86::EDX, U}, // URem 16915f757f3fSDimitry Andric {X86::IMUL32r, X86::MOV32r0, Copy, X86::EAX, S}, // Mul 16925f757f3fSDimitry Andric {X86::IMUL32r, X86::MOV32r0, Copy, X86::EDX, S}, // SMulH 16935f757f3fSDimitry Andric {X86::MUL32r, X86::MOV32r0, Copy, X86::EDX, U}, // UMulH 16945f757f3fSDimitry Andric }}, // i32 16955f757f3fSDimitry Andric {64, 16965f757f3fSDimitry Andric X86::RAX, 16975f757f3fSDimitry Andric X86::RDX, 16985f757f3fSDimitry Andric { 16995f757f3fSDimitry Andric {X86::IDIV64r, X86::CQO, Copy, X86::RAX, S}, // SDiv 17005f757f3fSDimitry Andric {X86::IDIV64r, X86::CQO, Copy, X86::RDX, S}, // SRem 17015f757f3fSDimitry Andric {X86::DIV64r, X86::MOV32r0, Copy, X86::RAX, U}, // UDiv 17025f757f3fSDimitry Andric {X86::DIV64r, X86::MOV32r0, Copy, X86::RDX, U}, // URem 17035f757f3fSDimitry Andric {X86::IMUL64r, X86::MOV32r0, Copy, X86::RAX, S}, // Mul 17045f757f3fSDimitry Andric {X86::IMUL64r, X86::MOV32r0, Copy, X86::RDX, S}, // SMulH 17055f757f3fSDimitry Andric {X86::MUL64r, X86::MOV32r0, Copy, X86::RDX, U}, // UMulH 17065f757f3fSDimitry Andric }}, // i64 17075f757f3fSDimitry Andric }; 17085f757f3fSDimitry Andric 17095f757f3fSDimitry Andric auto OpEntryIt = llvm::find_if(OpTable, [RegTy](const MulDivRemEntry &El) { 17105f757f3fSDimitry Andric return El.SizeInBits == RegTy.getSizeInBits(); 17115f757f3fSDimitry Andric }); 17125f757f3fSDimitry Andric if (OpEntryIt == std::end(OpTable)) 17135f757f3fSDimitry Andric return false; 17145f757f3fSDimitry Andric 17155f757f3fSDimitry Andric unsigned OpIndex; 17165f757f3fSDimitry Andric switch (I.getOpcode()) { 17175f757f3fSDimitry Andric default: 17185f757f3fSDimitry Andric llvm_unreachable("Unexpected mul/div/rem opcode"); 17195f757f3fSDimitry Andric case TargetOpcode::G_SDIV: 17205f757f3fSDimitry Andric OpIndex = 0; 17215f757f3fSDimitry Andric break; 17225f757f3fSDimitry Andric case TargetOpcode::G_SREM: 17235f757f3fSDimitry Andric OpIndex = 1; 17245f757f3fSDimitry Andric break; 17255f757f3fSDimitry Andric case TargetOpcode::G_UDIV: 17265f757f3fSDimitry Andric OpIndex = 2; 17275f757f3fSDimitry Andric break; 17285f757f3fSDimitry Andric case TargetOpcode::G_UREM: 17295f757f3fSDimitry Andric OpIndex = 3; 17305f757f3fSDimitry Andric break; 17315f757f3fSDimitry Andric case TargetOpcode::G_MUL: 17325f757f3fSDimitry Andric OpIndex = 4; 17335f757f3fSDimitry Andric break; 17345f757f3fSDimitry Andric case TargetOpcode::G_SMULH: 17355f757f3fSDimitry Andric OpIndex = 5; 17365f757f3fSDimitry Andric break; 17375f757f3fSDimitry Andric case TargetOpcode::G_UMULH: 17385f757f3fSDimitry Andric OpIndex = 6; 17395f757f3fSDimitry Andric break; 17405f757f3fSDimitry Andric } 17415f757f3fSDimitry Andric 17425f757f3fSDimitry Andric const MulDivRemEntry &TypeEntry = *OpEntryIt; 17435f757f3fSDimitry Andric const MulDivRemEntry::MulDivRemResult &OpEntry = 17445f757f3fSDimitry Andric TypeEntry.ResultTable[OpIndex]; 17455f757f3fSDimitry Andric 17465f757f3fSDimitry Andric const TargetRegisterClass *RegRC = getRegClass(RegTy, *RegRB); 17475f757f3fSDimitry Andric if (!RBI.constrainGenericRegister(Op1Reg, *RegRC, MRI) || 17485f757f3fSDimitry Andric !RBI.constrainGenericRegister(Op2Reg, *RegRC, MRI) || 17495f757f3fSDimitry Andric !RBI.constrainGenericRegister(DstReg, *RegRC, MRI)) { 17505f757f3fSDimitry Andric LLVM_DEBUG(dbgs() << "Failed to constrain " << TII.getName(I.getOpcode()) 17515f757f3fSDimitry Andric << " operand\n"); 17525f757f3fSDimitry Andric return false; 17535f757f3fSDimitry Andric } 17545f757f3fSDimitry Andric 17555f757f3fSDimitry Andric // Move op1 into low-order input register. 17565f757f3fSDimitry Andric BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(OpEntry.OpCopy), 17575f757f3fSDimitry Andric TypeEntry.LowInReg) 17585f757f3fSDimitry Andric .addReg(Op1Reg); 17595f757f3fSDimitry Andric 17605f757f3fSDimitry Andric // Zero-extend or sign-extend into high-order input register. 17615f757f3fSDimitry Andric if (OpEntry.OpSignExtend) { 17625f757f3fSDimitry Andric if (OpEntry.IsOpSigned) 17635f757f3fSDimitry Andric BuildMI(*I.getParent(), I, I.getDebugLoc(), 17645f757f3fSDimitry Andric TII.get(OpEntry.OpSignExtend)); 17655f757f3fSDimitry Andric else { 17665f757f3fSDimitry Andric Register Zero32 = MRI.createVirtualRegister(&X86::GR32RegClass); 17675f757f3fSDimitry Andric BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(X86::MOV32r0), 17685f757f3fSDimitry Andric Zero32); 17695f757f3fSDimitry Andric 17705f757f3fSDimitry Andric // Copy the zero into the appropriate sub/super/identical physical 17715f757f3fSDimitry Andric // register. Unfortunately the operations needed are not uniform enough 17725f757f3fSDimitry Andric // to fit neatly into the table above. 17735f757f3fSDimitry Andric if (RegTy.getSizeInBits() == 16) { 17745f757f3fSDimitry Andric BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(Copy), 17755f757f3fSDimitry Andric TypeEntry.HighInReg) 17765f757f3fSDimitry Andric .addReg(Zero32, 0, X86::sub_16bit); 17775f757f3fSDimitry Andric } else if (RegTy.getSizeInBits() == 32) { 17785f757f3fSDimitry Andric BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(Copy), 17795f757f3fSDimitry Andric TypeEntry.HighInReg) 17805f757f3fSDimitry Andric .addReg(Zero32); 17815f757f3fSDimitry Andric } else if (RegTy.getSizeInBits() == 64) { 17825f757f3fSDimitry Andric BuildMI(*I.getParent(), I, I.getDebugLoc(), 17835f757f3fSDimitry Andric TII.get(TargetOpcode::SUBREG_TO_REG), TypeEntry.HighInReg) 17845f757f3fSDimitry Andric .addImm(0) 17855f757f3fSDimitry Andric .addReg(Zero32) 17865f757f3fSDimitry Andric .addImm(X86::sub_32bit); 17875f757f3fSDimitry Andric } 17885f757f3fSDimitry Andric } 17895f757f3fSDimitry Andric } 17905f757f3fSDimitry Andric 17915f757f3fSDimitry Andric // Generate the DIV/IDIV/MUL/IMUL instruction. 17925f757f3fSDimitry Andric BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(OpEntry.OpMulDivRem)) 17935f757f3fSDimitry Andric .addReg(Op2Reg); 17945f757f3fSDimitry Andric 17955f757f3fSDimitry Andric // For i8 remainder, we can't reference ah directly, as we'll end 17965f757f3fSDimitry Andric // up with bogus copies like %r9b = COPY %ah. Reference ax 17975f757f3fSDimitry Andric // instead to prevent ah references in a rex instruction. 17985f757f3fSDimitry Andric // 17995f757f3fSDimitry Andric // The current assumption of the fast register allocator is that isel 18005f757f3fSDimitry Andric // won't generate explicit references to the GR8_NOREX registers. If 18015f757f3fSDimitry Andric // the allocator and/or the backend get enhanced to be more robust in 18025f757f3fSDimitry Andric // that regard, this can be, and should be, removed. 18035f757f3fSDimitry Andric if (OpEntry.ResultReg == X86::AH && STI.is64Bit()) { 18045f757f3fSDimitry Andric Register SourceSuperReg = MRI.createVirtualRegister(&X86::GR16RegClass); 18055f757f3fSDimitry Andric Register ResultSuperReg = MRI.createVirtualRegister(&X86::GR16RegClass); 18065f757f3fSDimitry Andric BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(Copy), SourceSuperReg) 18075f757f3fSDimitry Andric .addReg(X86::AX); 18085f757f3fSDimitry Andric 18095f757f3fSDimitry Andric // Shift AX right by 8 bits instead of using AH. 18105f757f3fSDimitry Andric BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(X86::SHR16ri), 18115f757f3fSDimitry Andric ResultSuperReg) 18125f757f3fSDimitry Andric .addReg(SourceSuperReg) 18135f757f3fSDimitry Andric .addImm(8); 18145f757f3fSDimitry Andric 18155f757f3fSDimitry Andric // Now reference the 8-bit subreg of the result. 1816*0fca6ea1SDimitry Andric BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(TargetOpcode::COPY), 1817*0fca6ea1SDimitry Andric DstReg) 1818*0fca6ea1SDimitry Andric .addReg(ResultSuperReg, 0, X86::sub_8bit); 18195f757f3fSDimitry Andric } else { 18205f757f3fSDimitry Andric BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(TargetOpcode::COPY), 18215f757f3fSDimitry Andric DstReg) 18225f757f3fSDimitry Andric .addReg(OpEntry.ResultReg); 18235f757f3fSDimitry Andric } 18245f757f3fSDimitry Andric I.eraseFromParent(); 18255f757f3fSDimitry Andric 18265f757f3fSDimitry Andric return true; 18275f757f3fSDimitry Andric } 18285f757f3fSDimitry Andric 18295f757f3fSDimitry Andric bool X86InstructionSelector::selectSelect(MachineInstr &I, 18305f757f3fSDimitry Andric MachineRegisterInfo &MRI, 18315f757f3fSDimitry Andric MachineFunction &MF) const { 18325f757f3fSDimitry Andric GSelect &Sel = cast<GSelect>(I); 18335f757f3fSDimitry Andric unsigned DstReg = Sel.getReg(0); 18345f757f3fSDimitry Andric BuildMI(*Sel.getParent(), Sel, Sel.getDebugLoc(), TII.get(X86::TEST32rr)) 18355f757f3fSDimitry Andric .addReg(Sel.getCondReg()) 18365f757f3fSDimitry Andric .addReg(Sel.getCondReg()); 18375f757f3fSDimitry Andric 18385f757f3fSDimitry Andric unsigned OpCmp; 18395f757f3fSDimitry Andric LLT Ty = MRI.getType(DstReg); 18405f757f3fSDimitry Andric switch (Ty.getSizeInBits()) { 18415f757f3fSDimitry Andric default: 18425f757f3fSDimitry Andric return false; 18435f757f3fSDimitry Andric case 8: 18445f757f3fSDimitry Andric OpCmp = X86::CMOV_GR8; 18455f757f3fSDimitry Andric break; 18465f757f3fSDimitry Andric case 16: 18475f757f3fSDimitry Andric OpCmp = STI.canUseCMOV() ? X86::CMOV16rr : X86::CMOV_GR16; 18485f757f3fSDimitry Andric break; 18495f757f3fSDimitry Andric case 32: 18505f757f3fSDimitry Andric OpCmp = STI.canUseCMOV() ? X86::CMOV32rr : X86::CMOV_GR32; 18515f757f3fSDimitry Andric break; 18525f757f3fSDimitry Andric case 64: 18535f757f3fSDimitry Andric assert(STI.is64Bit() && STI.canUseCMOV()); 18545f757f3fSDimitry Andric OpCmp = X86::CMOV64rr; 18555f757f3fSDimitry Andric break; 18565f757f3fSDimitry Andric } 18575f757f3fSDimitry Andric BuildMI(*Sel.getParent(), Sel, Sel.getDebugLoc(), TII.get(OpCmp), DstReg) 18585f757f3fSDimitry Andric .addReg(Sel.getTrueReg()) 18595f757f3fSDimitry Andric .addReg(Sel.getFalseReg()) 18605f757f3fSDimitry Andric .addImm(X86::COND_E); 18615f757f3fSDimitry Andric 18625f757f3fSDimitry Andric const TargetRegisterClass *DstRC = getRegClass(Ty, DstReg, MRI); 18635f757f3fSDimitry Andric if (!RBI.constrainGenericRegister(DstReg, *DstRC, MRI)) { 18645f757f3fSDimitry Andric LLVM_DEBUG(dbgs() << "Failed to constrain CMOV\n"); 18655f757f3fSDimitry Andric return false; 18665f757f3fSDimitry Andric } 18675f757f3fSDimitry Andric 18685f757f3fSDimitry Andric Sel.eraseFromParent(); 18695f757f3fSDimitry Andric return true; 18705f757f3fSDimitry Andric } 18715f757f3fSDimitry Andric 18725f757f3fSDimitry Andric InstructionSelector * 18735f757f3fSDimitry Andric llvm::createX86InstructionSelector(const X86TargetMachine &TM, 1874*0fca6ea1SDimitry Andric const X86Subtarget &Subtarget, 1875*0fca6ea1SDimitry Andric const X86RegisterBankInfo &RBI) { 18765f757f3fSDimitry Andric return new X86InstructionSelector(TM, Subtarget, RBI); 18775f757f3fSDimitry Andric } 1878