1bdd1243dSDimitry Andric //===-- RISCVInstructionSelector.cpp -----------------------------*- C++ -*-==// 2bdd1243dSDimitry Andric // 3bdd1243dSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4bdd1243dSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5bdd1243dSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6bdd1243dSDimitry Andric // 7bdd1243dSDimitry Andric //===----------------------------------------------------------------------===// 8bdd1243dSDimitry Andric /// \file 9bdd1243dSDimitry Andric /// This file implements the targeting of the InstructionSelector class for 1006c3fb27SDimitry Andric /// RISC-V. 11bdd1243dSDimitry Andric /// \todo This should be generated by TableGen. 12bdd1243dSDimitry Andric //===----------------------------------------------------------------------===// 13bdd1243dSDimitry Andric 145f757f3fSDimitry Andric #include "MCTargetDesc/RISCVMatInt.h" 15bdd1243dSDimitry Andric #include "RISCVRegisterBankInfo.h" 16bdd1243dSDimitry Andric #include "RISCVSubtarget.h" 17bdd1243dSDimitry Andric #include "RISCVTargetMachine.h" 1806c3fb27SDimitry Andric #include "llvm/CodeGen/GlobalISel/GIMatchTableExecutorImpl.h" 197a6dacacSDimitry Andric #include "llvm/CodeGen/GlobalISel/GISelKnownBits.h" 205f757f3fSDimitry Andric #include "llvm/CodeGen/GlobalISel/GenericMachineInstrs.h" 21bdd1243dSDimitry Andric #include "llvm/CodeGen/GlobalISel/InstructionSelector.h" 225f757f3fSDimitry Andric #include "llvm/CodeGen/GlobalISel/MIPatternMatch.h" 235f757f3fSDimitry Andric #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" 245f757f3fSDimitry Andric #include "llvm/CodeGen/MachineJumpTableInfo.h" 25bdd1243dSDimitry Andric #include "llvm/IR/IntrinsicsRISCV.h" 26bdd1243dSDimitry Andric #include "llvm/Support/Debug.h" 27bdd1243dSDimitry Andric 28bdd1243dSDimitry Andric #define DEBUG_TYPE "riscv-isel" 29bdd1243dSDimitry Andric 30bdd1243dSDimitry Andric using namespace llvm; 315f757f3fSDimitry Andric using namespace MIPatternMatch; 32bdd1243dSDimitry Andric 33bdd1243dSDimitry Andric #define GET_GLOBALISEL_PREDICATE_BITSET 34bdd1243dSDimitry Andric #include "RISCVGenGlobalISel.inc" 35bdd1243dSDimitry Andric #undef GET_GLOBALISEL_PREDICATE_BITSET 36bdd1243dSDimitry Andric 37bdd1243dSDimitry Andric namespace { 38bdd1243dSDimitry Andric 39bdd1243dSDimitry Andric class RISCVInstructionSelector : public InstructionSelector { 40bdd1243dSDimitry Andric public: 41bdd1243dSDimitry Andric RISCVInstructionSelector(const RISCVTargetMachine &TM, 42bdd1243dSDimitry Andric const RISCVSubtarget &STI, 43bdd1243dSDimitry Andric const RISCVRegisterBankInfo &RBI); 44bdd1243dSDimitry Andric 455f757f3fSDimitry Andric bool select(MachineInstr &MI) override; 46bdd1243dSDimitry Andric static const char *getName() { return DEBUG_TYPE; } 47bdd1243dSDimitry Andric 48bdd1243dSDimitry Andric private: 495f757f3fSDimitry Andric const TargetRegisterClass * 505f757f3fSDimitry Andric getRegClassForTypeOnBank(LLT Ty, const RegisterBank &RB) const; 515f757f3fSDimitry Andric 525f757f3fSDimitry Andric bool isRegInGprb(Register Reg, MachineRegisterInfo &MRI) const; 535f757f3fSDimitry Andric bool isRegInFprb(Register Reg, MachineRegisterInfo &MRI) const; 545f757f3fSDimitry Andric 555f757f3fSDimitry Andric // tblgen-erated 'select' implementation, used as the initial selector for 565f757f3fSDimitry Andric // the patterns that don't require complex C++. 57bdd1243dSDimitry Andric bool selectImpl(MachineInstr &I, CodeGenCoverage &CoverageInfo) const; 58bdd1243dSDimitry Andric 595f757f3fSDimitry Andric // A lowering phase that runs before any selection attempts. 605f757f3fSDimitry Andric // Returns true if the instruction was modified. 615f757f3fSDimitry Andric void preISelLower(MachineInstr &MI, MachineIRBuilder &MIB, 625f757f3fSDimitry Andric MachineRegisterInfo &MRI); 635f757f3fSDimitry Andric 645f757f3fSDimitry Andric bool replacePtrWithInt(MachineOperand &Op, MachineIRBuilder &MIB, 655f757f3fSDimitry Andric MachineRegisterInfo &MRI); 665f757f3fSDimitry Andric 675f757f3fSDimitry Andric // Custom selection methods 685f757f3fSDimitry Andric bool selectCopy(MachineInstr &MI, MachineRegisterInfo &MRI) const; 695f757f3fSDimitry Andric bool selectImplicitDef(MachineInstr &MI, MachineIRBuilder &MIB, 705f757f3fSDimitry Andric MachineRegisterInfo &MRI) const; 715f757f3fSDimitry Andric bool materializeImm(Register Reg, int64_t Imm, MachineIRBuilder &MIB) const; 725f757f3fSDimitry Andric bool selectAddr(MachineInstr &MI, MachineIRBuilder &MIB, 735f757f3fSDimitry Andric MachineRegisterInfo &MRI, bool IsLocal = true, 745f757f3fSDimitry Andric bool IsExternWeak = false) const; 755f757f3fSDimitry Andric bool selectSExtInreg(MachineInstr &MI, MachineIRBuilder &MIB) const; 765f757f3fSDimitry Andric bool selectSelect(MachineInstr &MI, MachineIRBuilder &MIB, 775f757f3fSDimitry Andric MachineRegisterInfo &MRI) const; 785f757f3fSDimitry Andric bool selectFPCompare(MachineInstr &MI, MachineIRBuilder &MIB, 795f757f3fSDimitry Andric MachineRegisterInfo &MRI) const; 805f757f3fSDimitry Andric void emitFence(AtomicOrdering FenceOrdering, SyncScope::ID FenceSSID, 815f757f3fSDimitry Andric MachineIRBuilder &MIB) const; 825f757f3fSDimitry Andric bool selectMergeValues(MachineInstr &MI, MachineIRBuilder &MIB, 835f757f3fSDimitry Andric MachineRegisterInfo &MRI) const; 845f757f3fSDimitry Andric bool selectUnmergeValues(MachineInstr &MI, MachineIRBuilder &MIB, 855f757f3fSDimitry Andric MachineRegisterInfo &MRI) const; 865f757f3fSDimitry Andric 875f757f3fSDimitry Andric ComplexRendererFns selectShiftMask(MachineOperand &Root) const; 885f757f3fSDimitry Andric ComplexRendererFns selectAddrRegImm(MachineOperand &Root) const; 895f757f3fSDimitry Andric 905f757f3fSDimitry Andric ComplexRendererFns selectSHXADDOp(MachineOperand &Root, unsigned ShAmt) const; 915f757f3fSDimitry Andric template <unsigned ShAmt> 925f757f3fSDimitry Andric ComplexRendererFns selectSHXADDOp(MachineOperand &Root) const { 935f757f3fSDimitry Andric return selectSHXADDOp(Root, ShAmt); 945f757f3fSDimitry Andric } 955f757f3fSDimitry Andric 965f757f3fSDimitry Andric ComplexRendererFns selectSHXADD_UWOp(MachineOperand &Root, 975f757f3fSDimitry Andric unsigned ShAmt) const; 985f757f3fSDimitry Andric template <unsigned ShAmt> 995f757f3fSDimitry Andric ComplexRendererFns selectSHXADD_UWOp(MachineOperand &Root) const { 1005f757f3fSDimitry Andric return selectSHXADD_UWOp(Root, ShAmt); 1015f757f3fSDimitry Andric } 1025f757f3fSDimitry Andric 1035f757f3fSDimitry Andric // Custom renderers for tablegen 1045f757f3fSDimitry Andric void renderNegImm(MachineInstrBuilder &MIB, const MachineInstr &MI, 1055f757f3fSDimitry Andric int OpIdx) const; 1065f757f3fSDimitry Andric void renderImmSubFromXLen(MachineInstrBuilder &MIB, const MachineInstr &MI, 1075f757f3fSDimitry Andric int OpIdx) const; 1085f757f3fSDimitry Andric void renderImmSubFrom32(MachineInstrBuilder &MIB, const MachineInstr &MI, 1095f757f3fSDimitry Andric int OpIdx) const; 1105f757f3fSDimitry Andric void renderImmPlus1(MachineInstrBuilder &MIB, const MachineInstr &MI, 1115f757f3fSDimitry Andric int OpIdx) const; 1125f757f3fSDimitry Andric void renderImm(MachineInstrBuilder &MIB, const MachineInstr &MI, 1135f757f3fSDimitry Andric int OpIdx) const; 1145f757f3fSDimitry Andric 1155f757f3fSDimitry Andric void renderTrailingZeros(MachineInstrBuilder &MIB, const MachineInstr &MI, 1165f757f3fSDimitry Andric int OpIdx) const; 1175f757f3fSDimitry Andric 118bdd1243dSDimitry Andric const RISCVSubtarget &STI; 119bdd1243dSDimitry Andric const RISCVInstrInfo &TII; 120bdd1243dSDimitry Andric const RISCVRegisterInfo &TRI; 121bdd1243dSDimitry Andric const RISCVRegisterBankInfo &RBI; 1225f757f3fSDimitry Andric const RISCVTargetMachine &TM; 123bdd1243dSDimitry Andric 124bdd1243dSDimitry Andric // FIXME: This is necessary because DAGISel uses "Subtarget->" and GlobalISel 125bdd1243dSDimitry Andric // uses "STI." in the code generated by TableGen. We need to unify the name of 126bdd1243dSDimitry Andric // Subtarget variable. 127bdd1243dSDimitry Andric const RISCVSubtarget *Subtarget = &STI; 128bdd1243dSDimitry Andric 129bdd1243dSDimitry Andric #define GET_GLOBALISEL_PREDICATES_DECL 130bdd1243dSDimitry Andric #include "RISCVGenGlobalISel.inc" 131bdd1243dSDimitry Andric #undef GET_GLOBALISEL_PREDICATES_DECL 132bdd1243dSDimitry Andric 133bdd1243dSDimitry Andric #define GET_GLOBALISEL_TEMPORARIES_DECL 134bdd1243dSDimitry Andric #include "RISCVGenGlobalISel.inc" 135bdd1243dSDimitry Andric #undef GET_GLOBALISEL_TEMPORARIES_DECL 136bdd1243dSDimitry Andric }; 137bdd1243dSDimitry Andric 138bdd1243dSDimitry Andric } // end anonymous namespace 139bdd1243dSDimitry Andric 140bdd1243dSDimitry Andric #define GET_GLOBALISEL_IMPL 141bdd1243dSDimitry Andric #include "RISCVGenGlobalISel.inc" 142bdd1243dSDimitry Andric #undef GET_GLOBALISEL_IMPL 143bdd1243dSDimitry Andric 144bdd1243dSDimitry Andric RISCVInstructionSelector::RISCVInstructionSelector( 145bdd1243dSDimitry Andric const RISCVTargetMachine &TM, const RISCVSubtarget &STI, 146bdd1243dSDimitry Andric const RISCVRegisterBankInfo &RBI) 147bdd1243dSDimitry Andric : STI(STI), TII(*STI.getInstrInfo()), TRI(*STI.getRegisterInfo()), RBI(RBI), 1485f757f3fSDimitry Andric TM(TM), 149bdd1243dSDimitry Andric 150bdd1243dSDimitry Andric #define GET_GLOBALISEL_PREDICATES_INIT 151bdd1243dSDimitry Andric #include "RISCVGenGlobalISel.inc" 152bdd1243dSDimitry Andric #undef GET_GLOBALISEL_PREDICATES_INIT 153bdd1243dSDimitry Andric #define GET_GLOBALISEL_TEMPORARIES_INIT 154bdd1243dSDimitry Andric #include "RISCVGenGlobalISel.inc" 155bdd1243dSDimitry Andric #undef GET_GLOBALISEL_TEMPORARIES_INIT 156bdd1243dSDimitry Andric { 157bdd1243dSDimitry Andric } 158bdd1243dSDimitry Andric 1595f757f3fSDimitry Andric InstructionSelector::ComplexRendererFns 1605f757f3fSDimitry Andric RISCVInstructionSelector::selectShiftMask(MachineOperand &Root) const { 1617a6dacacSDimitry Andric if (!Root.isReg()) 1627a6dacacSDimitry Andric return std::nullopt; 1637a6dacacSDimitry Andric 1647a6dacacSDimitry Andric using namespace llvm::MIPatternMatch; 1657a6dacacSDimitry Andric MachineRegisterInfo &MRI = MF->getRegInfo(); 1667a6dacacSDimitry Andric 1677a6dacacSDimitry Andric Register RootReg = Root.getReg(); 1687a6dacacSDimitry Andric Register ShAmtReg = RootReg; 1697a6dacacSDimitry Andric const LLT ShiftLLT = MRI.getType(RootReg); 1707a6dacacSDimitry Andric unsigned ShiftWidth = ShiftLLT.getSizeInBits(); 1717a6dacacSDimitry Andric assert(isPowerOf2_32(ShiftWidth) && "Unexpected max shift amount!"); 1727a6dacacSDimitry Andric // Peek through zext. 1737a6dacacSDimitry Andric Register ZExtSrcReg; 1747a6dacacSDimitry Andric if (mi_match(ShAmtReg, MRI, m_GZExt(m_Reg(ZExtSrcReg)))) { 1757a6dacacSDimitry Andric ShAmtReg = ZExtSrcReg; 1767a6dacacSDimitry Andric } 1777a6dacacSDimitry Andric 1787a6dacacSDimitry Andric APInt AndMask; 1797a6dacacSDimitry Andric Register AndSrcReg; 180*0fca6ea1SDimitry Andric // Try to combine the following pattern (applicable to other shift 181*0fca6ea1SDimitry Andric // instructions as well as 32-bit ones): 182*0fca6ea1SDimitry Andric // 183*0fca6ea1SDimitry Andric // %4:gprb(s64) = G_AND %3, %2 184*0fca6ea1SDimitry Andric // %5:gprb(s64) = G_LSHR %1, %4(s64) 185*0fca6ea1SDimitry Andric // 186*0fca6ea1SDimitry Andric // According to RISC-V's ISA manual, SLL, SRL, and SRA ignore other bits than 187*0fca6ea1SDimitry Andric // the lowest log2(XLEN) bits of register rs2. As for the above pattern, if 188*0fca6ea1SDimitry Andric // the lowest log2(XLEN) bits of register rd and rs2 of G_AND are the same, 189*0fca6ea1SDimitry Andric // then it can be eliminated. Given register rs1 or rs2 holding a constant 190*0fca6ea1SDimitry Andric // (the and mask), there are two cases G_AND can be erased: 191*0fca6ea1SDimitry Andric // 192*0fca6ea1SDimitry Andric // 1. the lowest log2(XLEN) bits of the and mask are all set 193*0fca6ea1SDimitry Andric // 2. the bits of the register being masked are already unset (zero set) 1947a6dacacSDimitry Andric if (mi_match(ShAmtReg, MRI, m_GAnd(m_Reg(AndSrcReg), m_ICst(AndMask)))) { 1957a6dacacSDimitry Andric APInt ShMask(AndMask.getBitWidth(), ShiftWidth - 1); 1967a6dacacSDimitry Andric if (ShMask.isSubsetOf(AndMask)) { 1977a6dacacSDimitry Andric ShAmtReg = AndSrcReg; 1987a6dacacSDimitry Andric } else { 1997a6dacacSDimitry Andric // SimplifyDemandedBits may have optimized the mask so try restoring any 2007a6dacacSDimitry Andric // bits that are known zero. 201*0fca6ea1SDimitry Andric KnownBits Known = KB->getKnownBits(AndSrcReg); 2027a6dacacSDimitry Andric if (ShMask.isSubsetOf(AndMask | Known.Zero)) 2037a6dacacSDimitry Andric ShAmtReg = AndSrcReg; 2047a6dacacSDimitry Andric } 2057a6dacacSDimitry Andric } 2067a6dacacSDimitry Andric 2077a6dacacSDimitry Andric APInt Imm; 2087a6dacacSDimitry Andric Register Reg; 2097a6dacacSDimitry Andric if (mi_match(ShAmtReg, MRI, m_GAdd(m_Reg(Reg), m_ICst(Imm)))) { 2107a6dacacSDimitry Andric if (Imm != 0 && Imm.urem(ShiftWidth) == 0) 2117a6dacacSDimitry Andric // If we are shifting by X+N where N == 0 mod Size, then just shift by X 2127a6dacacSDimitry Andric // to avoid the ADD. 2137a6dacacSDimitry Andric ShAmtReg = Reg; 2147a6dacacSDimitry Andric } else if (mi_match(ShAmtReg, MRI, m_GSub(m_ICst(Imm), m_Reg(Reg)))) { 2157a6dacacSDimitry Andric if (Imm != 0 && Imm.urem(ShiftWidth) == 0) { 2167a6dacacSDimitry Andric // If we are shifting by N-X where N == 0 mod Size, then just shift by -X 2177a6dacacSDimitry Andric // to generate a NEG instead of a SUB of a constant. 2187a6dacacSDimitry Andric ShAmtReg = MRI.createVirtualRegister(&RISCV::GPRRegClass); 2197a6dacacSDimitry Andric unsigned NegOpc = Subtarget->is64Bit() ? RISCV::SUBW : RISCV::SUB; 2207a6dacacSDimitry Andric return {{[=](MachineInstrBuilder &MIB) { 2217a6dacacSDimitry Andric MachineIRBuilder(*MIB.getInstr()) 2227a6dacacSDimitry Andric .buildInstr(NegOpc, {ShAmtReg}, {Register(RISCV::X0), Reg}); 2237a6dacacSDimitry Andric MIB.addReg(ShAmtReg); 2247a6dacacSDimitry Andric }}}; 2257a6dacacSDimitry Andric } 2267a6dacacSDimitry Andric if (Imm.urem(ShiftWidth) == ShiftWidth - 1) { 2277a6dacacSDimitry Andric // If we are shifting by N-X where N == -1 mod Size, then just shift by ~X 2287a6dacacSDimitry Andric // to generate a NOT instead of a SUB of a constant. 2297a6dacacSDimitry Andric ShAmtReg = MRI.createVirtualRegister(&RISCV::GPRRegClass); 2307a6dacacSDimitry Andric return {{[=](MachineInstrBuilder &MIB) { 2317a6dacacSDimitry Andric MachineIRBuilder(*MIB.getInstr()) 2327a6dacacSDimitry Andric .buildInstr(RISCV::XORI, {ShAmtReg}, {Reg}) 2337a6dacacSDimitry Andric .addImm(-1); 2347a6dacacSDimitry Andric MIB.addReg(ShAmtReg); 2357a6dacacSDimitry Andric }}}; 2367a6dacacSDimitry Andric } 2377a6dacacSDimitry Andric } 2387a6dacacSDimitry Andric 2397a6dacacSDimitry Andric return {{[=](MachineInstrBuilder &MIB) { MIB.addReg(ShAmtReg); }}}; 2405f757f3fSDimitry Andric } 241bdd1243dSDimitry Andric 2425f757f3fSDimitry Andric InstructionSelector::ComplexRendererFns 2435f757f3fSDimitry Andric RISCVInstructionSelector::selectSHXADDOp(MachineOperand &Root, 2445f757f3fSDimitry Andric unsigned ShAmt) const { 2455f757f3fSDimitry Andric using namespace llvm::MIPatternMatch; 2465f757f3fSDimitry Andric MachineFunction &MF = *Root.getParent()->getParent()->getParent(); 2475f757f3fSDimitry Andric MachineRegisterInfo &MRI = MF.getRegInfo(); 2485f757f3fSDimitry Andric 2495f757f3fSDimitry Andric if (!Root.isReg()) 2505f757f3fSDimitry Andric return std::nullopt; 2515f757f3fSDimitry Andric Register RootReg = Root.getReg(); 2525f757f3fSDimitry Andric 2535f757f3fSDimitry Andric const unsigned XLen = STI.getXLen(); 2545f757f3fSDimitry Andric APInt Mask, C2; 2555f757f3fSDimitry Andric Register RegY; 2565f757f3fSDimitry Andric std::optional<bool> LeftShift; 2575f757f3fSDimitry Andric // (and (shl y, c2), mask) 2585f757f3fSDimitry Andric if (mi_match(RootReg, MRI, 2595f757f3fSDimitry Andric m_GAnd(m_GShl(m_Reg(RegY), m_ICst(C2)), m_ICst(Mask)))) 2605f757f3fSDimitry Andric LeftShift = true; 2615f757f3fSDimitry Andric // (and (lshr y, c2), mask) 2625f757f3fSDimitry Andric else if (mi_match(RootReg, MRI, 2635f757f3fSDimitry Andric m_GAnd(m_GLShr(m_Reg(RegY), m_ICst(C2)), m_ICst(Mask)))) 2645f757f3fSDimitry Andric LeftShift = false; 2655f757f3fSDimitry Andric 2665f757f3fSDimitry Andric if (LeftShift.has_value()) { 2675f757f3fSDimitry Andric if (*LeftShift) 2685f757f3fSDimitry Andric Mask &= maskTrailingZeros<uint64_t>(C2.getLimitedValue()); 2695f757f3fSDimitry Andric else 2705f757f3fSDimitry Andric Mask &= maskTrailingOnes<uint64_t>(XLen - C2.getLimitedValue()); 2715f757f3fSDimitry Andric 2725f757f3fSDimitry Andric if (Mask.isShiftedMask()) { 2735f757f3fSDimitry Andric unsigned Leading = XLen - Mask.getActiveBits(); 2745f757f3fSDimitry Andric unsigned Trailing = Mask.countr_zero(); 2755f757f3fSDimitry Andric // Given (and (shl y, c2), mask) in which mask has no leading zeros and 2765f757f3fSDimitry Andric // c3 trailing zeros. We can use an SRLI by c3 - c2 followed by a SHXADD. 2775f757f3fSDimitry Andric if (*LeftShift && Leading == 0 && C2.ult(Trailing) && Trailing == ShAmt) { 2787a6dacacSDimitry Andric Register DstReg = MRI.createVirtualRegister(&RISCV::GPRRegClass); 2795f757f3fSDimitry Andric return {{[=](MachineInstrBuilder &MIB) { 2805f757f3fSDimitry Andric MachineIRBuilder(*MIB.getInstr()) 2815f757f3fSDimitry Andric .buildInstr(RISCV::SRLI, {DstReg}, {RegY}) 2825f757f3fSDimitry Andric .addImm(Trailing - C2.getLimitedValue()); 2835f757f3fSDimitry Andric MIB.addReg(DstReg); 2845f757f3fSDimitry Andric }}}; 2855f757f3fSDimitry Andric } 2865f757f3fSDimitry Andric 2875f757f3fSDimitry Andric // Given (and (lshr y, c2), mask) in which mask has c2 leading zeros and 2885f757f3fSDimitry Andric // c3 trailing zeros. We can use an SRLI by c2 + c3 followed by a SHXADD. 2895f757f3fSDimitry Andric if (!*LeftShift && Leading == C2 && Trailing == ShAmt) { 2907a6dacacSDimitry Andric Register DstReg = MRI.createVirtualRegister(&RISCV::GPRRegClass); 2915f757f3fSDimitry Andric return {{[=](MachineInstrBuilder &MIB) { 2925f757f3fSDimitry Andric MachineIRBuilder(*MIB.getInstr()) 2935f757f3fSDimitry Andric .buildInstr(RISCV::SRLI, {DstReg}, {RegY}) 2945f757f3fSDimitry Andric .addImm(Leading + Trailing); 2955f757f3fSDimitry Andric MIB.addReg(DstReg); 2965f757f3fSDimitry Andric }}}; 2975f757f3fSDimitry Andric } 2985f757f3fSDimitry Andric } 2995f757f3fSDimitry Andric } 3005f757f3fSDimitry Andric 3015f757f3fSDimitry Andric LeftShift.reset(); 3025f757f3fSDimitry Andric 3035f757f3fSDimitry Andric // (shl (and y, mask), c2) 3045f757f3fSDimitry Andric if (mi_match(RootReg, MRI, 3055f757f3fSDimitry Andric m_GShl(m_OneNonDBGUse(m_GAnd(m_Reg(RegY), m_ICst(Mask))), 3065f757f3fSDimitry Andric m_ICst(C2)))) 3075f757f3fSDimitry Andric LeftShift = true; 3085f757f3fSDimitry Andric // (lshr (and y, mask), c2) 3095f757f3fSDimitry Andric else if (mi_match(RootReg, MRI, 3105f757f3fSDimitry Andric m_GLShr(m_OneNonDBGUse(m_GAnd(m_Reg(RegY), m_ICst(Mask))), 3115f757f3fSDimitry Andric m_ICst(C2)))) 3125f757f3fSDimitry Andric LeftShift = false; 3135f757f3fSDimitry Andric 3145f757f3fSDimitry Andric if (LeftShift.has_value() && Mask.isShiftedMask()) { 3155f757f3fSDimitry Andric unsigned Leading = XLen - Mask.getActiveBits(); 3165f757f3fSDimitry Andric unsigned Trailing = Mask.countr_zero(); 3175f757f3fSDimitry Andric 3185f757f3fSDimitry Andric // Given (shl (and y, mask), c2) in which mask has 32 leading zeros and 3195f757f3fSDimitry Andric // c3 trailing zeros. If c1 + c3 == ShAmt, we can emit SRLIW + SHXADD. 3205f757f3fSDimitry Andric bool Cond = *LeftShift && Leading == 32 && Trailing > 0 && 3215f757f3fSDimitry Andric (Trailing + C2.getLimitedValue()) == ShAmt; 3225f757f3fSDimitry Andric if (!Cond) 3235f757f3fSDimitry Andric // Given (lshr (and y, mask), c2) in which mask has 32 leading zeros and 3245f757f3fSDimitry Andric // c3 trailing zeros. If c3 - c1 == ShAmt, we can emit SRLIW + SHXADD. 3255f757f3fSDimitry Andric Cond = !*LeftShift && Leading == 32 && C2.ult(Trailing) && 3265f757f3fSDimitry Andric (Trailing - C2.getLimitedValue()) == ShAmt; 3275f757f3fSDimitry Andric 3285f757f3fSDimitry Andric if (Cond) { 3297a6dacacSDimitry Andric Register DstReg = MRI.createVirtualRegister(&RISCV::GPRRegClass); 3305f757f3fSDimitry Andric return {{[=](MachineInstrBuilder &MIB) { 3315f757f3fSDimitry Andric MachineIRBuilder(*MIB.getInstr()) 3325f757f3fSDimitry Andric .buildInstr(RISCV::SRLIW, {DstReg}, {RegY}) 3335f757f3fSDimitry Andric .addImm(Trailing); 3345f757f3fSDimitry Andric MIB.addReg(DstReg); 3355f757f3fSDimitry Andric }}}; 3365f757f3fSDimitry Andric } 3375f757f3fSDimitry Andric } 3385f757f3fSDimitry Andric 3395f757f3fSDimitry Andric return std::nullopt; 3405f757f3fSDimitry Andric } 3415f757f3fSDimitry Andric 3425f757f3fSDimitry Andric InstructionSelector::ComplexRendererFns 3435f757f3fSDimitry Andric RISCVInstructionSelector::selectSHXADD_UWOp(MachineOperand &Root, 3445f757f3fSDimitry Andric unsigned ShAmt) const { 3455f757f3fSDimitry Andric using namespace llvm::MIPatternMatch; 3465f757f3fSDimitry Andric MachineFunction &MF = *Root.getParent()->getParent()->getParent(); 3475f757f3fSDimitry Andric MachineRegisterInfo &MRI = MF.getRegInfo(); 3485f757f3fSDimitry Andric 3495f757f3fSDimitry Andric if (!Root.isReg()) 3505f757f3fSDimitry Andric return std::nullopt; 3515f757f3fSDimitry Andric Register RootReg = Root.getReg(); 3525f757f3fSDimitry Andric 3535f757f3fSDimitry Andric // Given (and (shl x, c2), mask) in which mask is a shifted mask with 3545f757f3fSDimitry Andric // 32 - ShAmt leading zeros and c2 trailing zeros. We can use SLLI by 3555f757f3fSDimitry Andric // c2 - ShAmt followed by SHXADD_UW with ShAmt for x amount. 3565f757f3fSDimitry Andric APInt Mask, C2; 3575f757f3fSDimitry Andric Register RegX; 3585f757f3fSDimitry Andric if (mi_match( 3595f757f3fSDimitry Andric RootReg, MRI, 3605f757f3fSDimitry Andric m_OneNonDBGUse(m_GAnd(m_OneNonDBGUse(m_GShl(m_Reg(RegX), m_ICst(C2))), 3615f757f3fSDimitry Andric m_ICst(Mask))))) { 3625f757f3fSDimitry Andric Mask &= maskTrailingZeros<uint64_t>(C2.getLimitedValue()); 3635f757f3fSDimitry Andric 3645f757f3fSDimitry Andric if (Mask.isShiftedMask()) { 3655f757f3fSDimitry Andric unsigned Leading = Mask.countl_zero(); 3665f757f3fSDimitry Andric unsigned Trailing = Mask.countr_zero(); 3675f757f3fSDimitry Andric if (Leading == 32 - ShAmt && C2 == Trailing && Trailing > ShAmt) { 3687a6dacacSDimitry Andric Register DstReg = MRI.createVirtualRegister(&RISCV::GPRRegClass); 3695f757f3fSDimitry Andric return {{[=](MachineInstrBuilder &MIB) { 3705f757f3fSDimitry Andric MachineIRBuilder(*MIB.getInstr()) 3715f757f3fSDimitry Andric .buildInstr(RISCV::SLLI, {DstReg}, {RegX}) 3725f757f3fSDimitry Andric .addImm(C2.getLimitedValue() - ShAmt); 3735f757f3fSDimitry Andric MIB.addReg(DstReg); 3745f757f3fSDimitry Andric }}}; 3755f757f3fSDimitry Andric } 3765f757f3fSDimitry Andric } 3775f757f3fSDimitry Andric } 3785f757f3fSDimitry Andric 3795f757f3fSDimitry Andric return std::nullopt; 3805f757f3fSDimitry Andric } 3815f757f3fSDimitry Andric 3825f757f3fSDimitry Andric InstructionSelector::ComplexRendererFns 3835f757f3fSDimitry Andric RISCVInstructionSelector::selectAddrRegImm(MachineOperand &Root) const { 3845f757f3fSDimitry Andric MachineFunction &MF = *Root.getParent()->getParent()->getParent(); 3855f757f3fSDimitry Andric MachineRegisterInfo &MRI = MF.getRegInfo(); 3865f757f3fSDimitry Andric 3875f757f3fSDimitry Andric if (!Root.isReg()) 3885f757f3fSDimitry Andric return std::nullopt; 3895f757f3fSDimitry Andric 3905f757f3fSDimitry Andric MachineInstr *RootDef = MRI.getVRegDef(Root.getReg()); 3915f757f3fSDimitry Andric if (RootDef->getOpcode() == TargetOpcode::G_FRAME_INDEX) { 3925f757f3fSDimitry Andric return {{ 3935f757f3fSDimitry Andric [=](MachineInstrBuilder &MIB) { MIB.add(RootDef->getOperand(1)); }, 3945f757f3fSDimitry Andric [=](MachineInstrBuilder &MIB) { MIB.addImm(0); }, 3955f757f3fSDimitry Andric }}; 3965f757f3fSDimitry Andric } 3975f757f3fSDimitry Andric 3985f757f3fSDimitry Andric if (isBaseWithConstantOffset(Root, MRI)) { 3995f757f3fSDimitry Andric MachineOperand &LHS = RootDef->getOperand(1); 4005f757f3fSDimitry Andric MachineOperand &RHS = RootDef->getOperand(2); 4015f757f3fSDimitry Andric MachineInstr *LHSDef = MRI.getVRegDef(LHS.getReg()); 4025f757f3fSDimitry Andric MachineInstr *RHSDef = MRI.getVRegDef(RHS.getReg()); 4035f757f3fSDimitry Andric 4045f757f3fSDimitry Andric int64_t RHSC = RHSDef->getOperand(1).getCImm()->getSExtValue(); 4055f757f3fSDimitry Andric if (isInt<12>(RHSC)) { 4065f757f3fSDimitry Andric if (LHSDef->getOpcode() == TargetOpcode::G_FRAME_INDEX) 4075f757f3fSDimitry Andric return {{ 4085f757f3fSDimitry Andric [=](MachineInstrBuilder &MIB) { MIB.add(LHSDef->getOperand(1)); }, 4095f757f3fSDimitry Andric [=](MachineInstrBuilder &MIB) { MIB.addImm(RHSC); }, 4105f757f3fSDimitry Andric }}; 4115f757f3fSDimitry Andric 4125f757f3fSDimitry Andric return {{[=](MachineInstrBuilder &MIB) { MIB.add(LHS); }, 4135f757f3fSDimitry Andric [=](MachineInstrBuilder &MIB) { MIB.addImm(RHSC); }}}; 4145f757f3fSDimitry Andric } 4155f757f3fSDimitry Andric } 4165f757f3fSDimitry Andric 4175f757f3fSDimitry Andric // TODO: Need to get the immediate from a G_PTR_ADD. Should this be done in 4185f757f3fSDimitry Andric // the combiner? 4195f757f3fSDimitry Andric return {{[=](MachineInstrBuilder &MIB) { MIB.addReg(Root.getReg()); }, 4205f757f3fSDimitry Andric [=](MachineInstrBuilder &MIB) { MIB.addImm(0); }}}; 4215f757f3fSDimitry Andric } 4225f757f3fSDimitry Andric 4235f757f3fSDimitry Andric /// Returns the RISCVCC::CondCode that corresponds to the CmpInst::Predicate CC. 4245f757f3fSDimitry Andric /// CC Must be an ICMP Predicate. 4255f757f3fSDimitry Andric static RISCVCC::CondCode getRISCVCCFromICmp(CmpInst::Predicate CC) { 4265f757f3fSDimitry Andric switch (CC) { 4275f757f3fSDimitry Andric default: 4285f757f3fSDimitry Andric llvm_unreachable("Expected ICMP CmpInst::Predicate."); 4295f757f3fSDimitry Andric case CmpInst::Predicate::ICMP_EQ: 4305f757f3fSDimitry Andric return RISCVCC::COND_EQ; 4315f757f3fSDimitry Andric case CmpInst::Predicate::ICMP_NE: 4325f757f3fSDimitry Andric return RISCVCC::COND_NE; 4335f757f3fSDimitry Andric case CmpInst::Predicate::ICMP_ULT: 4345f757f3fSDimitry Andric return RISCVCC::COND_LTU; 4355f757f3fSDimitry Andric case CmpInst::Predicate::ICMP_SLT: 4365f757f3fSDimitry Andric return RISCVCC::COND_LT; 4375f757f3fSDimitry Andric case CmpInst::Predicate::ICMP_UGE: 4385f757f3fSDimitry Andric return RISCVCC::COND_GEU; 4395f757f3fSDimitry Andric case CmpInst::Predicate::ICMP_SGE: 4405f757f3fSDimitry Andric return RISCVCC::COND_GE; 4415f757f3fSDimitry Andric } 4425f757f3fSDimitry Andric } 4435f757f3fSDimitry Andric 4445f757f3fSDimitry Andric static void getOperandsForBranch(Register CondReg, MachineRegisterInfo &MRI, 4455f757f3fSDimitry Andric RISCVCC::CondCode &CC, Register &LHS, 4465f757f3fSDimitry Andric Register &RHS) { 4475f757f3fSDimitry Andric // Try to fold an ICmp. If that fails, use a NE compare with X0. 4485f757f3fSDimitry Andric CmpInst::Predicate Pred = CmpInst::BAD_ICMP_PREDICATE; 4495f757f3fSDimitry Andric if (!mi_match(CondReg, MRI, m_GICmp(m_Pred(Pred), m_Reg(LHS), m_Reg(RHS)))) { 4505f757f3fSDimitry Andric LHS = CondReg; 4515f757f3fSDimitry Andric RHS = RISCV::X0; 4525f757f3fSDimitry Andric CC = RISCVCC::COND_NE; 4535f757f3fSDimitry Andric return; 4545f757f3fSDimitry Andric } 4555f757f3fSDimitry Andric 4565f757f3fSDimitry Andric // We found an ICmp, do some canonicalizations. 4575f757f3fSDimitry Andric 4585f757f3fSDimitry Andric // Adjust comparisons to use comparison with 0 if possible. 4595f757f3fSDimitry Andric if (auto Constant = getIConstantVRegSExtVal(RHS, MRI)) { 4605f757f3fSDimitry Andric switch (Pred) { 4615f757f3fSDimitry Andric case CmpInst::Predicate::ICMP_SGT: 4625f757f3fSDimitry Andric // Convert X > -1 to X >= 0 4635f757f3fSDimitry Andric if (*Constant == -1) { 4645f757f3fSDimitry Andric CC = RISCVCC::COND_GE; 4655f757f3fSDimitry Andric RHS = RISCV::X0; 4665f757f3fSDimitry Andric return; 4675f757f3fSDimitry Andric } 4685f757f3fSDimitry Andric break; 4695f757f3fSDimitry Andric case CmpInst::Predicate::ICMP_SLT: 4705f757f3fSDimitry Andric // Convert X < 1 to 0 >= X 4715f757f3fSDimitry Andric if (*Constant == 1) { 4725f757f3fSDimitry Andric CC = RISCVCC::COND_GE; 4735f757f3fSDimitry Andric RHS = LHS; 4745f757f3fSDimitry Andric LHS = RISCV::X0; 4755f757f3fSDimitry Andric return; 4765f757f3fSDimitry Andric } 4775f757f3fSDimitry Andric break; 4785f757f3fSDimitry Andric default: 4795f757f3fSDimitry Andric break; 4805f757f3fSDimitry Andric } 4815f757f3fSDimitry Andric } 4825f757f3fSDimitry Andric 4835f757f3fSDimitry Andric switch (Pred) { 4845f757f3fSDimitry Andric default: 4855f757f3fSDimitry Andric llvm_unreachable("Expected ICMP CmpInst::Predicate."); 4865f757f3fSDimitry Andric case CmpInst::Predicate::ICMP_EQ: 4875f757f3fSDimitry Andric case CmpInst::Predicate::ICMP_NE: 4885f757f3fSDimitry Andric case CmpInst::Predicate::ICMP_ULT: 4895f757f3fSDimitry Andric case CmpInst::Predicate::ICMP_SLT: 4905f757f3fSDimitry Andric case CmpInst::Predicate::ICMP_UGE: 4915f757f3fSDimitry Andric case CmpInst::Predicate::ICMP_SGE: 4925f757f3fSDimitry Andric // These CCs are supported directly by RISC-V branches. 4935f757f3fSDimitry Andric break; 4945f757f3fSDimitry Andric case CmpInst::Predicate::ICMP_SGT: 4955f757f3fSDimitry Andric case CmpInst::Predicate::ICMP_SLE: 4965f757f3fSDimitry Andric case CmpInst::Predicate::ICMP_UGT: 4975f757f3fSDimitry Andric case CmpInst::Predicate::ICMP_ULE: 4985f757f3fSDimitry Andric // These CCs are not supported directly by RISC-V branches, but changing the 4995f757f3fSDimitry Andric // direction of the CC and swapping LHS and RHS are. 5005f757f3fSDimitry Andric Pred = CmpInst::getSwappedPredicate(Pred); 5015f757f3fSDimitry Andric std::swap(LHS, RHS); 5025f757f3fSDimitry Andric break; 5035f757f3fSDimitry Andric } 5045f757f3fSDimitry Andric 5055f757f3fSDimitry Andric CC = getRISCVCCFromICmp(Pred); 5065f757f3fSDimitry Andric return; 5075f757f3fSDimitry Andric } 5085f757f3fSDimitry Andric 5095f757f3fSDimitry Andric bool RISCVInstructionSelector::select(MachineInstr &MI) { 5105f757f3fSDimitry Andric MachineBasicBlock &MBB = *MI.getParent(); 5115f757f3fSDimitry Andric MachineFunction &MF = *MBB.getParent(); 5125f757f3fSDimitry Andric MachineRegisterInfo &MRI = MF.getRegInfo(); 5135f757f3fSDimitry Andric MachineIRBuilder MIB(MI); 5145f757f3fSDimitry Andric 5155f757f3fSDimitry Andric preISelLower(MI, MIB, MRI); 5165f757f3fSDimitry Andric const unsigned Opc = MI.getOpcode(); 5175f757f3fSDimitry Andric 5185f757f3fSDimitry Andric if (!MI.isPreISelOpcode() || Opc == TargetOpcode::G_PHI) { 5195f757f3fSDimitry Andric if (Opc == TargetOpcode::PHI || Opc == TargetOpcode::G_PHI) { 5205f757f3fSDimitry Andric const Register DefReg = MI.getOperand(0).getReg(); 5215f757f3fSDimitry Andric const LLT DefTy = MRI.getType(DefReg); 5225f757f3fSDimitry Andric 5235f757f3fSDimitry Andric const RegClassOrRegBank &RegClassOrBank = 5245f757f3fSDimitry Andric MRI.getRegClassOrRegBank(DefReg); 5255f757f3fSDimitry Andric 5265f757f3fSDimitry Andric const TargetRegisterClass *DefRC = 5275f757f3fSDimitry Andric RegClassOrBank.dyn_cast<const TargetRegisterClass *>(); 5285f757f3fSDimitry Andric if (!DefRC) { 5295f757f3fSDimitry Andric if (!DefTy.isValid()) { 5305f757f3fSDimitry Andric LLVM_DEBUG(dbgs() << "PHI operand has no type, not a gvreg?\n"); 5315f757f3fSDimitry Andric return false; 5325f757f3fSDimitry Andric } 5335f757f3fSDimitry Andric 5345f757f3fSDimitry Andric const RegisterBank &RB = *RegClassOrBank.get<const RegisterBank *>(); 5355f757f3fSDimitry Andric DefRC = getRegClassForTypeOnBank(DefTy, RB); 5365f757f3fSDimitry Andric if (!DefRC) { 5375f757f3fSDimitry Andric LLVM_DEBUG(dbgs() << "PHI operand has unexpected size/bank\n"); 5385f757f3fSDimitry Andric return false; 5395f757f3fSDimitry Andric } 5405f757f3fSDimitry Andric } 5415f757f3fSDimitry Andric 5425f757f3fSDimitry Andric MI.setDesc(TII.get(TargetOpcode::PHI)); 5435f757f3fSDimitry Andric return RBI.constrainGenericRegister(DefReg, *DefRC, MRI); 5445f757f3fSDimitry Andric } 5455f757f3fSDimitry Andric 546bdd1243dSDimitry Andric // Certain non-generic instructions also need some special handling. 5475f757f3fSDimitry Andric if (MI.isCopy()) 5485f757f3fSDimitry Andric return selectCopy(MI, MRI); 5495f757f3fSDimitry Andric 550bdd1243dSDimitry Andric return true; 551bdd1243dSDimitry Andric } 552bdd1243dSDimitry Andric 5535f757f3fSDimitry Andric if (selectImpl(MI, *CoverageInfo)) 554bdd1243dSDimitry Andric return true; 555bdd1243dSDimitry Andric 5565f757f3fSDimitry Andric switch (Opc) { 5575f757f3fSDimitry Andric case TargetOpcode::G_ANYEXT: 5585f757f3fSDimitry Andric case TargetOpcode::G_PTRTOINT: 5595f757f3fSDimitry Andric case TargetOpcode::G_INTTOPTR: 5605f757f3fSDimitry Andric case TargetOpcode::G_TRUNC: 561*0fca6ea1SDimitry Andric case TargetOpcode::G_FREEZE: 5625f757f3fSDimitry Andric return selectCopy(MI, MRI); 5635f757f3fSDimitry Andric case TargetOpcode::G_CONSTANT: { 5645f757f3fSDimitry Andric Register DstReg = MI.getOperand(0).getReg(); 5655f757f3fSDimitry Andric int64_t Imm = MI.getOperand(1).getCImm()->getSExtValue(); 5665f757f3fSDimitry Andric 5675f757f3fSDimitry Andric if (!materializeImm(DstReg, Imm, MIB)) 568bdd1243dSDimitry Andric return false; 5695f757f3fSDimitry Andric 5705f757f3fSDimitry Andric MI.eraseFromParent(); 5715f757f3fSDimitry Andric return true; 5725f757f3fSDimitry Andric } 5735f757f3fSDimitry Andric case TargetOpcode::G_FCONSTANT: { 5745f757f3fSDimitry Andric // TODO: Use constant pool for complext constants. 5755f757f3fSDimitry Andric // TODO: Optimize +0.0 to use fcvt.d.w for s64 on rv32. 5765f757f3fSDimitry Andric Register DstReg = MI.getOperand(0).getReg(); 5775f757f3fSDimitry Andric const APFloat &FPimm = MI.getOperand(1).getFPImm()->getValueAPF(); 5785f757f3fSDimitry Andric APInt Imm = FPimm.bitcastToAPInt(); 5795f757f3fSDimitry Andric unsigned Size = MRI.getType(DstReg).getSizeInBits(); 580*0fca6ea1SDimitry Andric if (Size == 16 || Size == 32 || (Size == 64 && Subtarget->is64Bit())) { 5815f757f3fSDimitry Andric Register GPRReg = MRI.createVirtualRegister(&RISCV::GPRRegClass); 5825f757f3fSDimitry Andric if (!materializeImm(GPRReg, Imm.getSExtValue(), MIB)) 5835f757f3fSDimitry Andric return false; 5845f757f3fSDimitry Andric 585*0fca6ea1SDimitry Andric unsigned Opcode = Size == 64 ? RISCV::FMV_D_X 586*0fca6ea1SDimitry Andric : Size == 32 ? RISCV::FMV_W_X 587*0fca6ea1SDimitry Andric : RISCV::FMV_H_X; 5885f757f3fSDimitry Andric auto FMV = MIB.buildInstr(Opcode, {DstReg}, {GPRReg}); 5895f757f3fSDimitry Andric if (!FMV.constrainAllUses(TII, TRI, RBI)) 5905f757f3fSDimitry Andric return false; 5915f757f3fSDimitry Andric } else { 5925f757f3fSDimitry Andric assert(Size == 64 && !Subtarget->is64Bit() && 5935f757f3fSDimitry Andric "Unexpected size or subtarget"); 5945f757f3fSDimitry Andric // Split into two pieces and build through the stack. 5955f757f3fSDimitry Andric Register GPRRegHigh = MRI.createVirtualRegister(&RISCV::GPRRegClass); 5965f757f3fSDimitry Andric Register GPRRegLow = MRI.createVirtualRegister(&RISCV::GPRRegClass); 5975f757f3fSDimitry Andric if (!materializeImm(GPRRegHigh, Imm.extractBits(32, 32).getSExtValue(), 5985f757f3fSDimitry Andric MIB)) 5995f757f3fSDimitry Andric return false; 6005f757f3fSDimitry Andric if (!materializeImm(GPRRegLow, Imm.trunc(32).getSExtValue(), MIB)) 6015f757f3fSDimitry Andric return false; 6025f757f3fSDimitry Andric MachineInstrBuilder PairF64 = MIB.buildInstr( 6035f757f3fSDimitry Andric RISCV::BuildPairF64Pseudo, {DstReg}, {GPRRegLow, GPRRegHigh}); 6045f757f3fSDimitry Andric if (!PairF64.constrainAllUses(TII, TRI, RBI)) 6055f757f3fSDimitry Andric return false; 6065f757f3fSDimitry Andric } 6075f757f3fSDimitry Andric 6085f757f3fSDimitry Andric MI.eraseFromParent(); 6095f757f3fSDimitry Andric return true; 6105f757f3fSDimitry Andric } 6115f757f3fSDimitry Andric case TargetOpcode::G_GLOBAL_VALUE: { 6125f757f3fSDimitry Andric auto *GV = MI.getOperand(1).getGlobal(); 6135f757f3fSDimitry Andric if (GV->isThreadLocal()) { 6145f757f3fSDimitry Andric // TODO: implement this case. 6155f757f3fSDimitry Andric return false; 6165f757f3fSDimitry Andric } 6175f757f3fSDimitry Andric 6185f757f3fSDimitry Andric return selectAddr(MI, MIB, MRI, GV->isDSOLocal(), 6195f757f3fSDimitry Andric GV->hasExternalWeakLinkage()); 6205f757f3fSDimitry Andric } 6215f757f3fSDimitry Andric case TargetOpcode::G_JUMP_TABLE: 6225f757f3fSDimitry Andric case TargetOpcode::G_CONSTANT_POOL: 6235f757f3fSDimitry Andric return selectAddr(MI, MIB, MRI); 6245f757f3fSDimitry Andric case TargetOpcode::G_BRCOND: { 6255f757f3fSDimitry Andric Register LHS, RHS; 6265f757f3fSDimitry Andric RISCVCC::CondCode CC; 6275f757f3fSDimitry Andric getOperandsForBranch(MI.getOperand(0).getReg(), MRI, CC, LHS, RHS); 6285f757f3fSDimitry Andric 6295f757f3fSDimitry Andric auto Bcc = MIB.buildInstr(RISCVCC::getBrCond(CC), {}, {LHS, RHS}) 6305f757f3fSDimitry Andric .addMBB(MI.getOperand(1).getMBB()); 6315f757f3fSDimitry Andric MI.eraseFromParent(); 6325f757f3fSDimitry Andric return constrainSelectedInstRegOperands(*Bcc, TII, TRI, RBI); 6335f757f3fSDimitry Andric } 6345f757f3fSDimitry Andric case TargetOpcode::G_BRJT: { 6355f757f3fSDimitry Andric // FIXME: Move to legalization? 6365f757f3fSDimitry Andric const MachineJumpTableInfo *MJTI = MF.getJumpTableInfo(); 6375f757f3fSDimitry Andric unsigned EntrySize = MJTI->getEntrySize(MF.getDataLayout()); 6385f757f3fSDimitry Andric assert((EntrySize == 4 || (Subtarget->is64Bit() && EntrySize == 8)) && 6395f757f3fSDimitry Andric "Unsupported jump-table entry size"); 6405f757f3fSDimitry Andric assert( 6415f757f3fSDimitry Andric (MJTI->getEntryKind() == MachineJumpTableInfo::EK_LabelDifference32 || 6425f757f3fSDimitry Andric MJTI->getEntryKind() == MachineJumpTableInfo::EK_Custom32 || 6435f757f3fSDimitry Andric MJTI->getEntryKind() == MachineJumpTableInfo::EK_BlockAddress) && 6445f757f3fSDimitry Andric "Unexpected jump-table entry kind"); 6455f757f3fSDimitry Andric 6465f757f3fSDimitry Andric auto SLL = 6475f757f3fSDimitry Andric MIB.buildInstr(RISCV::SLLI, {&RISCV::GPRRegClass}, {MI.getOperand(2)}) 6485f757f3fSDimitry Andric .addImm(Log2_32(EntrySize)); 6495f757f3fSDimitry Andric if (!SLL.constrainAllUses(TII, TRI, RBI)) 6505f757f3fSDimitry Andric return false; 6515f757f3fSDimitry Andric 6525f757f3fSDimitry Andric // TODO: Use SHXADD. Moving to legalization would fix this automatically. 6535f757f3fSDimitry Andric auto ADD = MIB.buildInstr(RISCV::ADD, {&RISCV::GPRRegClass}, 6545f757f3fSDimitry Andric {MI.getOperand(0), SLL.getReg(0)}); 6555f757f3fSDimitry Andric if (!ADD.constrainAllUses(TII, TRI, RBI)) 6565f757f3fSDimitry Andric return false; 6575f757f3fSDimitry Andric 6585f757f3fSDimitry Andric unsigned LdOpc = EntrySize == 8 ? RISCV::LD : RISCV::LW; 6595f757f3fSDimitry Andric auto Dest = 6605f757f3fSDimitry Andric MIB.buildInstr(LdOpc, {&RISCV::GPRRegClass}, {ADD.getReg(0)}) 6615f757f3fSDimitry Andric .addImm(0) 6625f757f3fSDimitry Andric .addMemOperand(MF.getMachineMemOperand( 6635f757f3fSDimitry Andric MachinePointerInfo::getJumpTable(MF), MachineMemOperand::MOLoad, 6645f757f3fSDimitry Andric EntrySize, Align(MJTI->getEntryAlignment(MF.getDataLayout())))); 6655f757f3fSDimitry Andric if (!Dest.constrainAllUses(TII, TRI, RBI)) 6665f757f3fSDimitry Andric return false; 6675f757f3fSDimitry Andric 6685f757f3fSDimitry Andric // If the Kind is EK_LabelDifference32, the table stores an offset from 6695f757f3fSDimitry Andric // the location of the table. Add the table address to get an absolute 6705f757f3fSDimitry Andric // address. 6715f757f3fSDimitry Andric if (MJTI->getEntryKind() == MachineJumpTableInfo::EK_LabelDifference32) { 6725f757f3fSDimitry Andric Dest = MIB.buildInstr(RISCV::ADD, {&RISCV::GPRRegClass}, 6735f757f3fSDimitry Andric {Dest.getReg(0), MI.getOperand(0)}); 6745f757f3fSDimitry Andric if (!Dest.constrainAllUses(TII, TRI, RBI)) 6755f757f3fSDimitry Andric return false; 6765f757f3fSDimitry Andric } 6775f757f3fSDimitry Andric 6785f757f3fSDimitry Andric auto Branch = 6795f757f3fSDimitry Andric MIB.buildInstr(RISCV::PseudoBRIND, {}, {Dest.getReg(0)}).addImm(0); 6805f757f3fSDimitry Andric if (!Branch.constrainAllUses(TII, TRI, RBI)) 6815f757f3fSDimitry Andric return false; 6825f757f3fSDimitry Andric 6835f757f3fSDimitry Andric MI.eraseFromParent(); 6845f757f3fSDimitry Andric return true; 6855f757f3fSDimitry Andric } 6865f757f3fSDimitry Andric case TargetOpcode::G_BRINDIRECT: 6875f757f3fSDimitry Andric MI.setDesc(TII.get(RISCV::PseudoBRIND)); 6885f757f3fSDimitry Andric MI.addOperand(MachineOperand::CreateImm(0)); 6895f757f3fSDimitry Andric return constrainSelectedInstRegOperands(MI, TII, TRI, RBI); 6905f757f3fSDimitry Andric case TargetOpcode::G_SEXT_INREG: 6915f757f3fSDimitry Andric return selectSExtInreg(MI, MIB); 6925f757f3fSDimitry Andric case TargetOpcode::G_FRAME_INDEX: { 6935f757f3fSDimitry Andric // TODO: We may want to replace this code with the SelectionDAG patterns, 6945f757f3fSDimitry Andric // which fail to get imported because it uses FrameAddrRegImm, which is a 6955f757f3fSDimitry Andric // ComplexPattern 6965f757f3fSDimitry Andric MI.setDesc(TII.get(RISCV::ADDI)); 6975f757f3fSDimitry Andric MI.addOperand(MachineOperand::CreateImm(0)); 6985f757f3fSDimitry Andric return constrainSelectedInstRegOperands(MI, TII, TRI, RBI); 6995f757f3fSDimitry Andric } 7005f757f3fSDimitry Andric case TargetOpcode::G_SELECT: 7015f757f3fSDimitry Andric return selectSelect(MI, MIB, MRI); 7025f757f3fSDimitry Andric case TargetOpcode::G_FCMP: 7035f757f3fSDimitry Andric return selectFPCompare(MI, MIB, MRI); 7045f757f3fSDimitry Andric case TargetOpcode::G_FENCE: { 7055f757f3fSDimitry Andric AtomicOrdering FenceOrdering = 7065f757f3fSDimitry Andric static_cast<AtomicOrdering>(MI.getOperand(0).getImm()); 7075f757f3fSDimitry Andric SyncScope::ID FenceSSID = 7085f757f3fSDimitry Andric static_cast<SyncScope::ID>(MI.getOperand(1).getImm()); 7095f757f3fSDimitry Andric emitFence(FenceOrdering, FenceSSID, MIB); 7105f757f3fSDimitry Andric MI.eraseFromParent(); 7115f757f3fSDimitry Andric return true; 7125f757f3fSDimitry Andric } 7135f757f3fSDimitry Andric case TargetOpcode::G_IMPLICIT_DEF: 7145f757f3fSDimitry Andric return selectImplicitDef(MI, MIB, MRI); 7155f757f3fSDimitry Andric case TargetOpcode::G_MERGE_VALUES: 7165f757f3fSDimitry Andric return selectMergeValues(MI, MIB, MRI); 7175f757f3fSDimitry Andric case TargetOpcode::G_UNMERGE_VALUES: 7185f757f3fSDimitry Andric return selectUnmergeValues(MI, MIB, MRI); 7195f757f3fSDimitry Andric default: 7205f757f3fSDimitry Andric return false; 7215f757f3fSDimitry Andric } 7225f757f3fSDimitry Andric } 7235f757f3fSDimitry Andric 7245f757f3fSDimitry Andric bool RISCVInstructionSelector::selectMergeValues( 7255f757f3fSDimitry Andric MachineInstr &MI, MachineIRBuilder &MIB, MachineRegisterInfo &MRI) const { 7265f757f3fSDimitry Andric assert(MI.getOpcode() == TargetOpcode::G_MERGE_VALUES); 7275f757f3fSDimitry Andric 7285f757f3fSDimitry Andric // Build a F64 Pair from operands 7295f757f3fSDimitry Andric if (MI.getNumOperands() != 3) 7305f757f3fSDimitry Andric return false; 7315f757f3fSDimitry Andric Register Dst = MI.getOperand(0).getReg(); 7325f757f3fSDimitry Andric Register Lo = MI.getOperand(1).getReg(); 7335f757f3fSDimitry Andric Register Hi = MI.getOperand(2).getReg(); 7345f757f3fSDimitry Andric if (!isRegInFprb(Dst, MRI) || !isRegInGprb(Lo, MRI) || !isRegInGprb(Hi, MRI)) 7355f757f3fSDimitry Andric return false; 7365f757f3fSDimitry Andric MI.setDesc(TII.get(RISCV::BuildPairF64Pseudo)); 7375f757f3fSDimitry Andric return constrainSelectedInstRegOperands(MI, TII, TRI, RBI); 7385f757f3fSDimitry Andric } 7395f757f3fSDimitry Andric 7405f757f3fSDimitry Andric bool RISCVInstructionSelector::selectUnmergeValues( 7415f757f3fSDimitry Andric MachineInstr &MI, MachineIRBuilder &MIB, MachineRegisterInfo &MRI) const { 7425f757f3fSDimitry Andric assert(MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES); 7435f757f3fSDimitry Andric 7445f757f3fSDimitry Andric // Split F64 Src into two s32 parts 7455f757f3fSDimitry Andric if (MI.getNumOperands() != 3) 7465f757f3fSDimitry Andric return false; 7475f757f3fSDimitry Andric Register Src = MI.getOperand(2).getReg(); 7485f757f3fSDimitry Andric Register Lo = MI.getOperand(0).getReg(); 7495f757f3fSDimitry Andric Register Hi = MI.getOperand(1).getReg(); 7505f757f3fSDimitry Andric if (!isRegInFprb(Src, MRI) || !isRegInGprb(Lo, MRI) || !isRegInGprb(Hi, MRI)) 7515f757f3fSDimitry Andric return false; 7525f757f3fSDimitry Andric MI.setDesc(TII.get(RISCV::SplitF64Pseudo)); 7535f757f3fSDimitry Andric return constrainSelectedInstRegOperands(MI, TII, TRI, RBI); 7545f757f3fSDimitry Andric } 7555f757f3fSDimitry Andric 7565f757f3fSDimitry Andric bool RISCVInstructionSelector::replacePtrWithInt(MachineOperand &Op, 7575f757f3fSDimitry Andric MachineIRBuilder &MIB, 7585f757f3fSDimitry Andric MachineRegisterInfo &MRI) { 7595f757f3fSDimitry Andric Register PtrReg = Op.getReg(); 7605f757f3fSDimitry Andric assert(MRI.getType(PtrReg).isPointer() && "Operand is not a pointer!"); 7615f757f3fSDimitry Andric 7625f757f3fSDimitry Andric const LLT sXLen = LLT::scalar(STI.getXLen()); 7635f757f3fSDimitry Andric auto PtrToInt = MIB.buildPtrToInt(sXLen, PtrReg); 7645f757f3fSDimitry Andric MRI.setRegBank(PtrToInt.getReg(0), RBI.getRegBank(RISCV::GPRBRegBankID)); 7655f757f3fSDimitry Andric Op.setReg(PtrToInt.getReg(0)); 7665f757f3fSDimitry Andric return select(*PtrToInt); 7675f757f3fSDimitry Andric } 7685f757f3fSDimitry Andric 7695f757f3fSDimitry Andric void RISCVInstructionSelector::preISelLower(MachineInstr &MI, 7705f757f3fSDimitry Andric MachineIRBuilder &MIB, 7715f757f3fSDimitry Andric MachineRegisterInfo &MRI) { 7725f757f3fSDimitry Andric switch (MI.getOpcode()) { 7735f757f3fSDimitry Andric case TargetOpcode::G_PTR_ADD: { 7745f757f3fSDimitry Andric Register DstReg = MI.getOperand(0).getReg(); 7755f757f3fSDimitry Andric const LLT sXLen = LLT::scalar(STI.getXLen()); 7765f757f3fSDimitry Andric 7775f757f3fSDimitry Andric replacePtrWithInt(MI.getOperand(1), MIB, MRI); 7785f757f3fSDimitry Andric MI.setDesc(TII.get(TargetOpcode::G_ADD)); 7795f757f3fSDimitry Andric MRI.setType(DstReg, sXLen); 7805f757f3fSDimitry Andric break; 7815f757f3fSDimitry Andric } 7825f757f3fSDimitry Andric case TargetOpcode::G_PTRMASK: { 7835f757f3fSDimitry Andric Register DstReg = MI.getOperand(0).getReg(); 7845f757f3fSDimitry Andric const LLT sXLen = LLT::scalar(STI.getXLen()); 7855f757f3fSDimitry Andric replacePtrWithInt(MI.getOperand(1), MIB, MRI); 7865f757f3fSDimitry Andric MI.setDesc(TII.get(TargetOpcode::G_AND)); 7875f757f3fSDimitry Andric MRI.setType(DstReg, sXLen); 7885f757f3fSDimitry Andric } 7895f757f3fSDimitry Andric } 7905f757f3fSDimitry Andric } 7915f757f3fSDimitry Andric 7925f757f3fSDimitry Andric void RISCVInstructionSelector::renderNegImm(MachineInstrBuilder &MIB, 7935f757f3fSDimitry Andric const MachineInstr &MI, 7945f757f3fSDimitry Andric int OpIdx) const { 7955f757f3fSDimitry Andric assert(MI.getOpcode() == TargetOpcode::G_CONSTANT && OpIdx == -1 && 7965f757f3fSDimitry Andric "Expected G_CONSTANT"); 7975f757f3fSDimitry Andric int64_t CstVal = MI.getOperand(1).getCImm()->getSExtValue(); 7985f757f3fSDimitry Andric MIB.addImm(-CstVal); 7995f757f3fSDimitry Andric } 8005f757f3fSDimitry Andric 8015f757f3fSDimitry Andric void RISCVInstructionSelector::renderImmSubFromXLen(MachineInstrBuilder &MIB, 8025f757f3fSDimitry Andric const MachineInstr &MI, 8035f757f3fSDimitry Andric int OpIdx) const { 8045f757f3fSDimitry Andric assert(MI.getOpcode() == TargetOpcode::G_CONSTANT && OpIdx == -1 && 8055f757f3fSDimitry Andric "Expected G_CONSTANT"); 8065f757f3fSDimitry Andric uint64_t CstVal = MI.getOperand(1).getCImm()->getZExtValue(); 8075f757f3fSDimitry Andric MIB.addImm(STI.getXLen() - CstVal); 8085f757f3fSDimitry Andric } 8095f757f3fSDimitry Andric 8105f757f3fSDimitry Andric void RISCVInstructionSelector::renderImmSubFrom32(MachineInstrBuilder &MIB, 8115f757f3fSDimitry Andric const MachineInstr &MI, 8125f757f3fSDimitry Andric int OpIdx) const { 8135f757f3fSDimitry Andric assert(MI.getOpcode() == TargetOpcode::G_CONSTANT && OpIdx == -1 && 8145f757f3fSDimitry Andric "Expected G_CONSTANT"); 8155f757f3fSDimitry Andric uint64_t CstVal = MI.getOperand(1).getCImm()->getZExtValue(); 8165f757f3fSDimitry Andric MIB.addImm(32 - CstVal); 8175f757f3fSDimitry Andric } 8185f757f3fSDimitry Andric 8195f757f3fSDimitry Andric void RISCVInstructionSelector::renderImmPlus1(MachineInstrBuilder &MIB, 8205f757f3fSDimitry Andric const MachineInstr &MI, 8215f757f3fSDimitry Andric int OpIdx) const { 8225f757f3fSDimitry Andric assert(MI.getOpcode() == TargetOpcode::G_CONSTANT && OpIdx == -1 && 8235f757f3fSDimitry Andric "Expected G_CONSTANT"); 8245f757f3fSDimitry Andric int64_t CstVal = MI.getOperand(1).getCImm()->getSExtValue(); 8255f757f3fSDimitry Andric MIB.addImm(CstVal + 1); 8265f757f3fSDimitry Andric } 8275f757f3fSDimitry Andric 8285f757f3fSDimitry Andric void RISCVInstructionSelector::renderImm(MachineInstrBuilder &MIB, 8295f757f3fSDimitry Andric const MachineInstr &MI, 8305f757f3fSDimitry Andric int OpIdx) const { 8315f757f3fSDimitry Andric assert(MI.getOpcode() == TargetOpcode::G_CONSTANT && OpIdx == -1 && 8325f757f3fSDimitry Andric "Expected G_CONSTANT"); 8335f757f3fSDimitry Andric int64_t CstVal = MI.getOperand(1).getCImm()->getSExtValue(); 8345f757f3fSDimitry Andric MIB.addImm(CstVal); 8355f757f3fSDimitry Andric } 8365f757f3fSDimitry Andric 8375f757f3fSDimitry Andric void RISCVInstructionSelector::renderTrailingZeros(MachineInstrBuilder &MIB, 8385f757f3fSDimitry Andric const MachineInstr &MI, 8395f757f3fSDimitry Andric int OpIdx) const { 8405f757f3fSDimitry Andric assert(MI.getOpcode() == TargetOpcode::G_CONSTANT && OpIdx == -1 && 8415f757f3fSDimitry Andric "Expected G_CONSTANT"); 8425f757f3fSDimitry Andric uint64_t C = MI.getOperand(1).getCImm()->getZExtValue(); 8435f757f3fSDimitry Andric MIB.addImm(llvm::countr_zero(C)); 8445f757f3fSDimitry Andric } 8455f757f3fSDimitry Andric 8465f757f3fSDimitry Andric const TargetRegisterClass *RISCVInstructionSelector::getRegClassForTypeOnBank( 8475f757f3fSDimitry Andric LLT Ty, const RegisterBank &RB) const { 8485f757f3fSDimitry Andric if (RB.getID() == RISCV::GPRBRegBankID) { 8495f757f3fSDimitry Andric if (Ty.getSizeInBits() <= 32 || (STI.is64Bit() && Ty.getSizeInBits() == 64)) 8505f757f3fSDimitry Andric return &RISCV::GPRRegClass; 8515f757f3fSDimitry Andric } 8525f757f3fSDimitry Andric 8535f757f3fSDimitry Andric if (RB.getID() == RISCV::FPRBRegBankID) { 854*0fca6ea1SDimitry Andric if (Ty.getSizeInBits() == 16) 855*0fca6ea1SDimitry Andric return &RISCV::FPR16RegClass; 8565f757f3fSDimitry Andric if (Ty.getSizeInBits() == 32) 8575f757f3fSDimitry Andric return &RISCV::FPR32RegClass; 8585f757f3fSDimitry Andric if (Ty.getSizeInBits() == 64) 8595f757f3fSDimitry Andric return &RISCV::FPR64RegClass; 8605f757f3fSDimitry Andric } 8615f757f3fSDimitry Andric 862*0fca6ea1SDimitry Andric if (RB.getID() == RISCV::VRBRegBankID) { 863*0fca6ea1SDimitry Andric if (Ty.getSizeInBits().getKnownMinValue() <= 64) 864*0fca6ea1SDimitry Andric return &RISCV::VRRegClass; 865*0fca6ea1SDimitry Andric 866*0fca6ea1SDimitry Andric if (Ty.getSizeInBits().getKnownMinValue() == 128) 867*0fca6ea1SDimitry Andric return &RISCV::VRM2RegClass; 868*0fca6ea1SDimitry Andric 869*0fca6ea1SDimitry Andric if (Ty.getSizeInBits().getKnownMinValue() == 256) 870*0fca6ea1SDimitry Andric return &RISCV::VRM4RegClass; 871*0fca6ea1SDimitry Andric 872*0fca6ea1SDimitry Andric if (Ty.getSizeInBits().getKnownMinValue() == 512) 873*0fca6ea1SDimitry Andric return &RISCV::VRM8RegClass; 874*0fca6ea1SDimitry Andric } 875*0fca6ea1SDimitry Andric 8765f757f3fSDimitry Andric return nullptr; 8775f757f3fSDimitry Andric } 8785f757f3fSDimitry Andric 8795f757f3fSDimitry Andric bool RISCVInstructionSelector::isRegInGprb(Register Reg, 8805f757f3fSDimitry Andric MachineRegisterInfo &MRI) const { 8815f757f3fSDimitry Andric return RBI.getRegBank(Reg, MRI, TRI)->getID() == RISCV::GPRBRegBankID; 8825f757f3fSDimitry Andric } 8835f757f3fSDimitry Andric 8845f757f3fSDimitry Andric bool RISCVInstructionSelector::isRegInFprb(Register Reg, 8855f757f3fSDimitry Andric MachineRegisterInfo &MRI) const { 8865f757f3fSDimitry Andric return RBI.getRegBank(Reg, MRI, TRI)->getID() == RISCV::FPRBRegBankID; 8875f757f3fSDimitry Andric } 8885f757f3fSDimitry Andric 8895f757f3fSDimitry Andric bool RISCVInstructionSelector::selectCopy(MachineInstr &MI, 8905f757f3fSDimitry Andric MachineRegisterInfo &MRI) const { 8915f757f3fSDimitry Andric Register DstReg = MI.getOperand(0).getReg(); 8925f757f3fSDimitry Andric 8935f757f3fSDimitry Andric if (DstReg.isPhysical()) 8945f757f3fSDimitry Andric return true; 8955f757f3fSDimitry Andric 8965f757f3fSDimitry Andric const TargetRegisterClass *DstRC = getRegClassForTypeOnBank( 8975f757f3fSDimitry Andric MRI.getType(DstReg), *RBI.getRegBank(DstReg, MRI, TRI)); 8985f757f3fSDimitry Andric assert(DstRC && 8995f757f3fSDimitry Andric "Register class not available for LLT, register bank combination"); 9005f757f3fSDimitry Andric 9015f757f3fSDimitry Andric // No need to constrain SrcReg. It will get constrained when 9025f757f3fSDimitry Andric // we hit another of its uses or its defs. 9035f757f3fSDimitry Andric // Copies do not have constraints. 9045f757f3fSDimitry Andric if (!RBI.constrainGenericRegister(DstReg, *DstRC, MRI)) { 9055f757f3fSDimitry Andric LLVM_DEBUG(dbgs() << "Failed to constrain " << TII.getName(MI.getOpcode()) 9065f757f3fSDimitry Andric << " operand\n"); 9075f757f3fSDimitry Andric return false; 9085f757f3fSDimitry Andric } 9095f757f3fSDimitry Andric 9105f757f3fSDimitry Andric MI.setDesc(TII.get(RISCV::COPY)); 9115f757f3fSDimitry Andric return true; 9125f757f3fSDimitry Andric } 9135f757f3fSDimitry Andric 9145f757f3fSDimitry Andric bool RISCVInstructionSelector::selectImplicitDef( 9155f757f3fSDimitry Andric MachineInstr &MI, MachineIRBuilder &MIB, MachineRegisterInfo &MRI) const { 9165f757f3fSDimitry Andric assert(MI.getOpcode() == TargetOpcode::G_IMPLICIT_DEF); 9175f757f3fSDimitry Andric 9185f757f3fSDimitry Andric const Register DstReg = MI.getOperand(0).getReg(); 9195f757f3fSDimitry Andric const TargetRegisterClass *DstRC = getRegClassForTypeOnBank( 9205f757f3fSDimitry Andric MRI.getType(DstReg), *RBI.getRegBank(DstReg, MRI, TRI)); 9215f757f3fSDimitry Andric 9225f757f3fSDimitry Andric assert(DstRC && 9235f757f3fSDimitry Andric "Register class not available for LLT, register bank combination"); 9245f757f3fSDimitry Andric 9255f757f3fSDimitry Andric if (!RBI.constrainGenericRegister(DstReg, *DstRC, MRI)) { 9265f757f3fSDimitry Andric LLVM_DEBUG(dbgs() << "Failed to constrain " << TII.getName(MI.getOpcode()) 9275f757f3fSDimitry Andric << " operand\n"); 9285f757f3fSDimitry Andric } 9295f757f3fSDimitry Andric MI.setDesc(TII.get(TargetOpcode::IMPLICIT_DEF)); 9305f757f3fSDimitry Andric return true; 9315f757f3fSDimitry Andric } 9325f757f3fSDimitry Andric 9335f757f3fSDimitry Andric bool RISCVInstructionSelector::materializeImm(Register DstReg, int64_t Imm, 9345f757f3fSDimitry Andric MachineIRBuilder &MIB) const { 9355f757f3fSDimitry Andric MachineRegisterInfo &MRI = *MIB.getMRI(); 9365f757f3fSDimitry Andric 9375f757f3fSDimitry Andric if (Imm == 0) { 9385f757f3fSDimitry Andric MIB.buildCopy(DstReg, Register(RISCV::X0)); 9395f757f3fSDimitry Andric RBI.constrainGenericRegister(DstReg, RISCV::GPRRegClass, MRI); 9405f757f3fSDimitry Andric return true; 9415f757f3fSDimitry Andric } 9425f757f3fSDimitry Andric 9435f757f3fSDimitry Andric RISCVMatInt::InstSeq Seq = RISCVMatInt::generateInstSeq(Imm, *Subtarget); 9445f757f3fSDimitry Andric unsigned NumInsts = Seq.size(); 9455f757f3fSDimitry Andric Register SrcReg = RISCV::X0; 9465f757f3fSDimitry Andric 9475f757f3fSDimitry Andric for (unsigned i = 0; i < NumInsts; i++) { 9485f757f3fSDimitry Andric Register TmpReg = i < NumInsts - 1 9495f757f3fSDimitry Andric ? MRI.createVirtualRegister(&RISCV::GPRRegClass) 9505f757f3fSDimitry Andric : DstReg; 9515f757f3fSDimitry Andric const RISCVMatInt::Inst &I = Seq[i]; 9525f757f3fSDimitry Andric MachineInstr *Result; 9535f757f3fSDimitry Andric 9545f757f3fSDimitry Andric switch (I.getOpndKind()) { 9555f757f3fSDimitry Andric case RISCVMatInt::Imm: 9565f757f3fSDimitry Andric // clang-format off 9575f757f3fSDimitry Andric Result = MIB.buildInstr(I.getOpcode(), {TmpReg}, {}) 9585f757f3fSDimitry Andric .addImm(I.getImm()); 9595f757f3fSDimitry Andric // clang-format on 9605f757f3fSDimitry Andric break; 9615f757f3fSDimitry Andric case RISCVMatInt::RegX0: 9625f757f3fSDimitry Andric Result = MIB.buildInstr(I.getOpcode(), {TmpReg}, 9635f757f3fSDimitry Andric {SrcReg, Register(RISCV::X0)}); 9645f757f3fSDimitry Andric break; 9655f757f3fSDimitry Andric case RISCVMatInt::RegReg: 9665f757f3fSDimitry Andric Result = MIB.buildInstr(I.getOpcode(), {TmpReg}, {SrcReg, SrcReg}); 9675f757f3fSDimitry Andric break; 9685f757f3fSDimitry Andric case RISCVMatInt::RegImm: 9695f757f3fSDimitry Andric Result = 9705f757f3fSDimitry Andric MIB.buildInstr(I.getOpcode(), {TmpReg}, {SrcReg}).addImm(I.getImm()); 9715f757f3fSDimitry Andric break; 9725f757f3fSDimitry Andric } 9735f757f3fSDimitry Andric 9745f757f3fSDimitry Andric if (!constrainSelectedInstRegOperands(*Result, TII, TRI, RBI)) 9755f757f3fSDimitry Andric return false; 9765f757f3fSDimitry Andric 9775f757f3fSDimitry Andric SrcReg = TmpReg; 9785f757f3fSDimitry Andric } 9795f757f3fSDimitry Andric 9805f757f3fSDimitry Andric return true; 9815f757f3fSDimitry Andric } 9825f757f3fSDimitry Andric 9835f757f3fSDimitry Andric bool RISCVInstructionSelector::selectAddr(MachineInstr &MI, 9845f757f3fSDimitry Andric MachineIRBuilder &MIB, 9855f757f3fSDimitry Andric MachineRegisterInfo &MRI, 9865f757f3fSDimitry Andric bool IsLocal, 9875f757f3fSDimitry Andric bool IsExternWeak) const { 9885f757f3fSDimitry Andric assert((MI.getOpcode() == TargetOpcode::G_GLOBAL_VALUE || 9895f757f3fSDimitry Andric MI.getOpcode() == TargetOpcode::G_JUMP_TABLE || 9905f757f3fSDimitry Andric MI.getOpcode() == TargetOpcode::G_CONSTANT_POOL) && 9915f757f3fSDimitry Andric "Unexpected opcode"); 9925f757f3fSDimitry Andric 9935f757f3fSDimitry Andric const MachineOperand &DispMO = MI.getOperand(1); 9945f757f3fSDimitry Andric 9955f757f3fSDimitry Andric Register DefReg = MI.getOperand(0).getReg(); 9965f757f3fSDimitry Andric const LLT DefTy = MRI.getType(DefReg); 9975f757f3fSDimitry Andric 9985f757f3fSDimitry Andric // When HWASAN is used and tagging of global variables is enabled 9995f757f3fSDimitry Andric // they should be accessed via the GOT, since the tagged address of a global 10005f757f3fSDimitry Andric // is incompatible with existing code models. This also applies to non-pic 10015f757f3fSDimitry Andric // mode. 10025f757f3fSDimitry Andric if (TM.isPositionIndependent() || Subtarget->allowTaggedGlobals()) { 10035f757f3fSDimitry Andric if (IsLocal && !Subtarget->allowTaggedGlobals()) { 10045f757f3fSDimitry Andric // Use PC-relative addressing to access the symbol. This generates the 10055f757f3fSDimitry Andric // pattern (PseudoLLA sym), which expands to (addi (auipc %pcrel_hi(sym)) 10065f757f3fSDimitry Andric // %pcrel_lo(auipc)). 10075f757f3fSDimitry Andric MI.setDesc(TII.get(RISCV::PseudoLLA)); 10085f757f3fSDimitry Andric return constrainSelectedInstRegOperands(MI, TII, TRI, RBI); 10095f757f3fSDimitry Andric } 10105f757f3fSDimitry Andric 10115f757f3fSDimitry Andric // Use PC-relative addressing to access the GOT for this symbol, then 10125f757f3fSDimitry Andric // load the address from the GOT. This generates the pattern (PseudoLGA 10135f757f3fSDimitry Andric // sym), which expands to (ld (addi (auipc %got_pcrel_hi(sym)) 10145f757f3fSDimitry Andric // %pcrel_lo(auipc))). 10155f757f3fSDimitry Andric MachineFunction &MF = *MI.getParent()->getParent(); 10165f757f3fSDimitry Andric MachineMemOperand *MemOp = MF.getMachineMemOperand( 10175f757f3fSDimitry Andric MachinePointerInfo::getGOT(MF), 10185f757f3fSDimitry Andric MachineMemOperand::MOLoad | MachineMemOperand::MODereferenceable | 10195f757f3fSDimitry Andric MachineMemOperand::MOInvariant, 10205f757f3fSDimitry Andric DefTy, Align(DefTy.getSizeInBits() / 8)); 10215f757f3fSDimitry Andric 10225f757f3fSDimitry Andric auto Result = MIB.buildInstr(RISCV::PseudoLGA, {DefReg}, {}) 10235f757f3fSDimitry Andric .addDisp(DispMO, 0) 10245f757f3fSDimitry Andric .addMemOperand(MemOp); 10255f757f3fSDimitry Andric 10265f757f3fSDimitry Andric if (!constrainSelectedInstRegOperands(*Result, TII, TRI, RBI)) 10275f757f3fSDimitry Andric return false; 10285f757f3fSDimitry Andric 10295f757f3fSDimitry Andric MI.eraseFromParent(); 10305f757f3fSDimitry Andric return true; 10315f757f3fSDimitry Andric } 10325f757f3fSDimitry Andric 10335f757f3fSDimitry Andric switch (TM.getCodeModel()) { 10345f757f3fSDimitry Andric default: { 10355f757f3fSDimitry Andric reportGISelFailure(const_cast<MachineFunction &>(*MF), *TPC, *MORE, 10365f757f3fSDimitry Andric getName(), "Unsupported code model for lowering", MI); 10375f757f3fSDimitry Andric return false; 10385f757f3fSDimitry Andric } 10395f757f3fSDimitry Andric case CodeModel::Small: { 10405f757f3fSDimitry Andric // Must lie within a single 2 GiB address range and must lie between 10415f757f3fSDimitry Andric // absolute addresses -2 GiB and +2 GiB. This generates the pattern (addi 10425f757f3fSDimitry Andric // (lui %hi(sym)) %lo(sym)). 10435f757f3fSDimitry Andric Register AddrHiDest = MRI.createVirtualRegister(&RISCV::GPRRegClass); 10445f757f3fSDimitry Andric MachineInstr *AddrHi = MIB.buildInstr(RISCV::LUI, {AddrHiDest}, {}) 10455f757f3fSDimitry Andric .addDisp(DispMO, 0, RISCVII::MO_HI); 10465f757f3fSDimitry Andric 10475f757f3fSDimitry Andric if (!constrainSelectedInstRegOperands(*AddrHi, TII, TRI, RBI)) 10485f757f3fSDimitry Andric return false; 10495f757f3fSDimitry Andric 10505f757f3fSDimitry Andric auto Result = MIB.buildInstr(RISCV::ADDI, {DefReg}, {AddrHiDest}) 10515f757f3fSDimitry Andric .addDisp(DispMO, 0, RISCVII::MO_LO); 10525f757f3fSDimitry Andric 10535f757f3fSDimitry Andric if (!constrainSelectedInstRegOperands(*Result, TII, TRI, RBI)) 10545f757f3fSDimitry Andric return false; 10555f757f3fSDimitry Andric 10565f757f3fSDimitry Andric MI.eraseFromParent(); 10575f757f3fSDimitry Andric return true; 10585f757f3fSDimitry Andric } 10595f757f3fSDimitry Andric case CodeModel::Medium: 10605f757f3fSDimitry Andric // Emit LGA/LLA instead of the sequence it expands to because the pcrel_lo 10615f757f3fSDimitry Andric // relocation needs to reference a label that points to the auipc 10625f757f3fSDimitry Andric // instruction itself, not the global. This cannot be done inside the 10635f757f3fSDimitry Andric // instruction selector. 10645f757f3fSDimitry Andric if (IsExternWeak) { 10655f757f3fSDimitry Andric // An extern weak symbol may be undefined, i.e. have value 0, which may 10665f757f3fSDimitry Andric // not be within 2GiB of PC, so use GOT-indirect addressing to access the 10675f757f3fSDimitry Andric // symbol. This generates the pattern (PseudoLGA sym), which expands to 10685f757f3fSDimitry Andric // (ld (addi (auipc %got_pcrel_hi(sym)) %pcrel_lo(auipc))). 10695f757f3fSDimitry Andric MachineFunction &MF = *MI.getParent()->getParent(); 10705f757f3fSDimitry Andric MachineMemOperand *MemOp = MF.getMachineMemOperand( 10715f757f3fSDimitry Andric MachinePointerInfo::getGOT(MF), 10725f757f3fSDimitry Andric MachineMemOperand::MOLoad | MachineMemOperand::MODereferenceable | 10735f757f3fSDimitry Andric MachineMemOperand::MOInvariant, 10745f757f3fSDimitry Andric DefTy, Align(DefTy.getSizeInBits() / 8)); 10755f757f3fSDimitry Andric 10765f757f3fSDimitry Andric auto Result = MIB.buildInstr(RISCV::PseudoLGA, {DefReg}, {}) 10775f757f3fSDimitry Andric .addDisp(DispMO, 0) 10785f757f3fSDimitry Andric .addMemOperand(MemOp); 10795f757f3fSDimitry Andric 10805f757f3fSDimitry Andric if (!constrainSelectedInstRegOperands(*Result, TII, TRI, RBI)) 10815f757f3fSDimitry Andric return false; 10825f757f3fSDimitry Andric 10835f757f3fSDimitry Andric MI.eraseFromParent(); 10845f757f3fSDimitry Andric return true; 10855f757f3fSDimitry Andric } 10865f757f3fSDimitry Andric 10875f757f3fSDimitry Andric // Generate a sequence for accessing addresses within any 2GiB range 10885f757f3fSDimitry Andric // within the address space. This generates the pattern (PseudoLLA sym), 10895f757f3fSDimitry Andric // which expands to (addi (auipc %pcrel_hi(sym)) %pcrel_lo(auipc)). 10905f757f3fSDimitry Andric MI.setDesc(TII.get(RISCV::PseudoLLA)); 10915f757f3fSDimitry Andric return constrainSelectedInstRegOperands(MI, TII, TRI, RBI); 10925f757f3fSDimitry Andric } 10935f757f3fSDimitry Andric 10945f757f3fSDimitry Andric return false; 10955f757f3fSDimitry Andric } 10965f757f3fSDimitry Andric 10975f757f3fSDimitry Andric bool RISCVInstructionSelector::selectSExtInreg(MachineInstr &MI, 10985f757f3fSDimitry Andric MachineIRBuilder &MIB) const { 10995f757f3fSDimitry Andric if (!STI.isRV64()) 11005f757f3fSDimitry Andric return false; 11015f757f3fSDimitry Andric 11025f757f3fSDimitry Andric const MachineOperand &Size = MI.getOperand(2); 11035f757f3fSDimitry Andric // Only Size == 32 (i.e. shift by 32 bits) is acceptable at this point. 11045f757f3fSDimitry Andric if (!Size.isImm() || Size.getImm() != 32) 11055f757f3fSDimitry Andric return false; 11065f757f3fSDimitry Andric 11075f757f3fSDimitry Andric const MachineOperand &Src = MI.getOperand(1); 11085f757f3fSDimitry Andric const MachineOperand &Dst = MI.getOperand(0); 11095f757f3fSDimitry Andric // addiw rd, rs, 0 (i.e. sext.w rd, rs) 11105f757f3fSDimitry Andric MachineInstr *NewMI = 11115f757f3fSDimitry Andric MIB.buildInstr(RISCV::ADDIW, {Dst.getReg()}, {Src.getReg()}).addImm(0U); 11125f757f3fSDimitry Andric 11135f757f3fSDimitry Andric if (!constrainSelectedInstRegOperands(*NewMI, TII, TRI, RBI)) 11145f757f3fSDimitry Andric return false; 11155f757f3fSDimitry Andric 11165f757f3fSDimitry Andric MI.eraseFromParent(); 11175f757f3fSDimitry Andric return true; 11185f757f3fSDimitry Andric } 11195f757f3fSDimitry Andric 11205f757f3fSDimitry Andric bool RISCVInstructionSelector::selectSelect(MachineInstr &MI, 11215f757f3fSDimitry Andric MachineIRBuilder &MIB, 11225f757f3fSDimitry Andric MachineRegisterInfo &MRI) const { 11235f757f3fSDimitry Andric auto &SelectMI = cast<GSelect>(MI); 11245f757f3fSDimitry Andric 11255f757f3fSDimitry Andric Register LHS, RHS; 11265f757f3fSDimitry Andric RISCVCC::CondCode CC; 11275f757f3fSDimitry Andric getOperandsForBranch(SelectMI.getCondReg(), MRI, CC, LHS, RHS); 11285f757f3fSDimitry Andric 11295f757f3fSDimitry Andric Register DstReg = SelectMI.getReg(0); 11305f757f3fSDimitry Andric 11315f757f3fSDimitry Andric unsigned Opc = RISCV::Select_GPR_Using_CC_GPR; 11325f757f3fSDimitry Andric if (RBI.getRegBank(DstReg, MRI, TRI)->getID() == RISCV::FPRBRegBankID) { 11335f757f3fSDimitry Andric unsigned Size = MRI.getType(DstReg).getSizeInBits(); 11345f757f3fSDimitry Andric Opc = Size == 32 ? RISCV::Select_FPR32_Using_CC_GPR 11355f757f3fSDimitry Andric : RISCV::Select_FPR64_Using_CC_GPR; 11365f757f3fSDimitry Andric } 11375f757f3fSDimitry Andric 11385f757f3fSDimitry Andric MachineInstr *Result = MIB.buildInstr(Opc) 11395f757f3fSDimitry Andric .addDef(DstReg) 11405f757f3fSDimitry Andric .addReg(LHS) 11415f757f3fSDimitry Andric .addReg(RHS) 11425f757f3fSDimitry Andric .addImm(CC) 11435f757f3fSDimitry Andric .addReg(SelectMI.getTrueReg()) 11445f757f3fSDimitry Andric .addReg(SelectMI.getFalseReg()); 11455f757f3fSDimitry Andric MI.eraseFromParent(); 11465f757f3fSDimitry Andric return constrainSelectedInstRegOperands(*Result, TII, TRI, RBI); 11475f757f3fSDimitry Andric } 11485f757f3fSDimitry Andric 11495f757f3fSDimitry Andric // Convert an FCMP predicate to one of the supported F or D instructions. 11505f757f3fSDimitry Andric static unsigned getFCmpOpcode(CmpInst::Predicate Pred, unsigned Size) { 1151*0fca6ea1SDimitry Andric assert((Size == 16 || Size == 32 || Size == 64) && "Unsupported size"); 11525f757f3fSDimitry Andric switch (Pred) { 11535f757f3fSDimitry Andric default: 11545f757f3fSDimitry Andric llvm_unreachable("Unsupported predicate"); 11555f757f3fSDimitry Andric case CmpInst::FCMP_OLT: 1156*0fca6ea1SDimitry Andric return Size == 16 ? RISCV::FLT_H : Size == 32 ? RISCV::FLT_S : RISCV::FLT_D; 11575f757f3fSDimitry Andric case CmpInst::FCMP_OLE: 1158*0fca6ea1SDimitry Andric return Size == 16 ? RISCV::FLE_H : Size == 32 ? RISCV::FLE_S : RISCV::FLE_D; 11595f757f3fSDimitry Andric case CmpInst::FCMP_OEQ: 1160*0fca6ea1SDimitry Andric return Size == 16 ? RISCV::FEQ_H : Size == 32 ? RISCV::FEQ_S : RISCV::FEQ_D; 11615f757f3fSDimitry Andric } 11625f757f3fSDimitry Andric } 11635f757f3fSDimitry Andric 11645f757f3fSDimitry Andric // Try legalizing an FCMP by swapping or inverting the predicate to one that 11655f757f3fSDimitry Andric // is supported. 11665f757f3fSDimitry Andric static bool legalizeFCmpPredicate(Register &LHS, Register &RHS, 11675f757f3fSDimitry Andric CmpInst::Predicate &Pred, bool &NeedInvert) { 11685f757f3fSDimitry Andric auto isLegalFCmpPredicate = [](CmpInst::Predicate Pred) { 11695f757f3fSDimitry Andric return Pred == CmpInst::FCMP_OLT || Pred == CmpInst::FCMP_OLE || 11705f757f3fSDimitry Andric Pred == CmpInst::FCMP_OEQ; 11715f757f3fSDimitry Andric }; 11725f757f3fSDimitry Andric 11735f757f3fSDimitry Andric assert(!isLegalFCmpPredicate(Pred) && "Predicate already legal?"); 11745f757f3fSDimitry Andric 11755f757f3fSDimitry Andric CmpInst::Predicate InvPred = CmpInst::getSwappedPredicate(Pred); 11765f757f3fSDimitry Andric if (isLegalFCmpPredicate(InvPred)) { 11775f757f3fSDimitry Andric Pred = InvPred; 11785f757f3fSDimitry Andric std::swap(LHS, RHS); 11795f757f3fSDimitry Andric return true; 11805f757f3fSDimitry Andric } 11815f757f3fSDimitry Andric 11825f757f3fSDimitry Andric InvPred = CmpInst::getInversePredicate(Pred); 11835f757f3fSDimitry Andric NeedInvert = true; 11845f757f3fSDimitry Andric if (isLegalFCmpPredicate(InvPred)) { 11855f757f3fSDimitry Andric Pred = InvPred; 11865f757f3fSDimitry Andric return true; 11875f757f3fSDimitry Andric } 11885f757f3fSDimitry Andric InvPred = CmpInst::getSwappedPredicate(InvPred); 11895f757f3fSDimitry Andric if (isLegalFCmpPredicate(InvPred)) { 11905f757f3fSDimitry Andric Pred = InvPred; 11915f757f3fSDimitry Andric std::swap(LHS, RHS); 11925f757f3fSDimitry Andric return true; 11935f757f3fSDimitry Andric } 11945f757f3fSDimitry Andric 11955f757f3fSDimitry Andric return false; 11965f757f3fSDimitry Andric } 11975f757f3fSDimitry Andric 11985f757f3fSDimitry Andric // Emit a sequence of instructions to compare LHS and RHS using Pred. Return 11995f757f3fSDimitry Andric // the result in DstReg. 12005f757f3fSDimitry Andric // FIXME: Maybe we should expand this earlier. 12015f757f3fSDimitry Andric bool RISCVInstructionSelector::selectFPCompare(MachineInstr &MI, 12025f757f3fSDimitry Andric MachineIRBuilder &MIB, 12035f757f3fSDimitry Andric MachineRegisterInfo &MRI) const { 12045f757f3fSDimitry Andric auto &CmpMI = cast<GFCmp>(MI); 12055f757f3fSDimitry Andric CmpInst::Predicate Pred = CmpMI.getCond(); 12065f757f3fSDimitry Andric 12075f757f3fSDimitry Andric Register DstReg = CmpMI.getReg(0); 12085f757f3fSDimitry Andric Register LHS = CmpMI.getLHSReg(); 12095f757f3fSDimitry Andric Register RHS = CmpMI.getRHSReg(); 12105f757f3fSDimitry Andric 12115f757f3fSDimitry Andric unsigned Size = MRI.getType(LHS).getSizeInBits(); 1212*0fca6ea1SDimitry Andric assert((Size == 16 || Size == 32 || Size == 64) && "Unexpected size"); 12135f757f3fSDimitry Andric 12145f757f3fSDimitry Andric Register TmpReg = DstReg; 12155f757f3fSDimitry Andric 12165f757f3fSDimitry Andric bool NeedInvert = false; 12175f757f3fSDimitry Andric // First try swapping operands or inverting. 12185f757f3fSDimitry Andric if (legalizeFCmpPredicate(LHS, RHS, Pred, NeedInvert)) { 12195f757f3fSDimitry Andric if (NeedInvert) 12205f757f3fSDimitry Andric TmpReg = MRI.createVirtualRegister(&RISCV::GPRRegClass); 12215f757f3fSDimitry Andric auto Cmp = MIB.buildInstr(getFCmpOpcode(Pred, Size), {TmpReg}, {LHS, RHS}); 12225f757f3fSDimitry Andric if (!Cmp.constrainAllUses(TII, TRI, RBI)) 12235f757f3fSDimitry Andric return false; 12245f757f3fSDimitry Andric } else if (Pred == CmpInst::FCMP_ONE || Pred == CmpInst::FCMP_UEQ) { 12255f757f3fSDimitry Andric // fcmp one LHS, RHS => (OR (FLT LHS, RHS), (FLT RHS, LHS)) 12265f757f3fSDimitry Andric NeedInvert = Pred == CmpInst::FCMP_UEQ; 12275f757f3fSDimitry Andric auto Cmp1 = MIB.buildInstr(getFCmpOpcode(CmpInst::FCMP_OLT, Size), 12285f757f3fSDimitry Andric {&RISCV::GPRRegClass}, {LHS, RHS}); 12295f757f3fSDimitry Andric if (!Cmp1.constrainAllUses(TII, TRI, RBI)) 12305f757f3fSDimitry Andric return false; 12315f757f3fSDimitry Andric auto Cmp2 = MIB.buildInstr(getFCmpOpcode(CmpInst::FCMP_OLT, Size), 12325f757f3fSDimitry Andric {&RISCV::GPRRegClass}, {RHS, LHS}); 12335f757f3fSDimitry Andric if (!Cmp2.constrainAllUses(TII, TRI, RBI)) 12345f757f3fSDimitry Andric return false; 12355f757f3fSDimitry Andric if (NeedInvert) 12365f757f3fSDimitry Andric TmpReg = MRI.createVirtualRegister(&RISCV::GPRRegClass); 12375f757f3fSDimitry Andric auto Or = 12385f757f3fSDimitry Andric MIB.buildInstr(RISCV::OR, {TmpReg}, {Cmp1.getReg(0), Cmp2.getReg(0)}); 12395f757f3fSDimitry Andric if (!Or.constrainAllUses(TII, TRI, RBI)) 12405f757f3fSDimitry Andric return false; 12415f757f3fSDimitry Andric } else if (Pred == CmpInst::FCMP_ORD || Pred == CmpInst::FCMP_UNO) { 12425f757f3fSDimitry Andric // fcmp ord LHS, RHS => (AND (FEQ LHS, LHS), (FEQ RHS, RHS)) 12435f757f3fSDimitry Andric // FIXME: If LHS and RHS are the same we can use a single FEQ. 12445f757f3fSDimitry Andric NeedInvert = Pred == CmpInst::FCMP_UNO; 12455f757f3fSDimitry Andric auto Cmp1 = MIB.buildInstr(getFCmpOpcode(CmpInst::FCMP_OEQ, Size), 12465f757f3fSDimitry Andric {&RISCV::GPRRegClass}, {LHS, LHS}); 12475f757f3fSDimitry Andric if (!Cmp1.constrainAllUses(TII, TRI, RBI)) 12485f757f3fSDimitry Andric return false; 12495f757f3fSDimitry Andric auto Cmp2 = MIB.buildInstr(getFCmpOpcode(CmpInst::FCMP_OEQ, Size), 12505f757f3fSDimitry Andric {&RISCV::GPRRegClass}, {RHS, RHS}); 12515f757f3fSDimitry Andric if (!Cmp2.constrainAllUses(TII, TRI, RBI)) 12525f757f3fSDimitry Andric return false; 12535f757f3fSDimitry Andric if (NeedInvert) 12545f757f3fSDimitry Andric TmpReg = MRI.createVirtualRegister(&RISCV::GPRRegClass); 12555f757f3fSDimitry Andric auto And = 12565f757f3fSDimitry Andric MIB.buildInstr(RISCV::AND, {TmpReg}, {Cmp1.getReg(0), Cmp2.getReg(0)}); 12575f757f3fSDimitry Andric if (!And.constrainAllUses(TII, TRI, RBI)) 12585f757f3fSDimitry Andric return false; 12595f757f3fSDimitry Andric } else 12605f757f3fSDimitry Andric llvm_unreachable("Unhandled predicate"); 12615f757f3fSDimitry Andric 12625f757f3fSDimitry Andric // Emit an XORI to invert the result if needed. 12635f757f3fSDimitry Andric if (NeedInvert) { 12645f757f3fSDimitry Andric auto Xor = MIB.buildInstr(RISCV::XORI, {DstReg}, {TmpReg}).addImm(1); 12655f757f3fSDimitry Andric if (!Xor.constrainAllUses(TII, TRI, RBI)) 12665f757f3fSDimitry Andric return false; 12675f757f3fSDimitry Andric } 12685f757f3fSDimitry Andric 12695f757f3fSDimitry Andric MI.eraseFromParent(); 12705f757f3fSDimitry Andric return true; 12715f757f3fSDimitry Andric } 12725f757f3fSDimitry Andric 12735f757f3fSDimitry Andric void RISCVInstructionSelector::emitFence(AtomicOrdering FenceOrdering, 12745f757f3fSDimitry Andric SyncScope::ID FenceSSID, 12755f757f3fSDimitry Andric MachineIRBuilder &MIB) const { 12765f757f3fSDimitry Andric if (STI.hasStdExtZtso()) { 12775f757f3fSDimitry Andric // The only fence that needs an instruction is a sequentially-consistent 12785f757f3fSDimitry Andric // cross-thread fence. 12795f757f3fSDimitry Andric if (FenceOrdering == AtomicOrdering::SequentiallyConsistent && 12805f757f3fSDimitry Andric FenceSSID == SyncScope::System) { 12815f757f3fSDimitry Andric // fence rw, rw 12825f757f3fSDimitry Andric MIB.buildInstr(RISCV::FENCE, {}, {}) 12835f757f3fSDimitry Andric .addImm(RISCVFenceField::R | RISCVFenceField::W) 12845f757f3fSDimitry Andric .addImm(RISCVFenceField::R | RISCVFenceField::W); 12855f757f3fSDimitry Andric return; 12865f757f3fSDimitry Andric } 12875f757f3fSDimitry Andric 12885f757f3fSDimitry Andric // MEMBARRIER is a compiler barrier; it codegens to a no-op. 12895f757f3fSDimitry Andric MIB.buildInstr(TargetOpcode::MEMBARRIER, {}, {}); 12905f757f3fSDimitry Andric return; 12915f757f3fSDimitry Andric } 12925f757f3fSDimitry Andric 12935f757f3fSDimitry Andric // singlethread fences only synchronize with signal handlers on the same 12945f757f3fSDimitry Andric // thread and thus only need to preserve instruction order, not actually 12955f757f3fSDimitry Andric // enforce memory ordering. 12965f757f3fSDimitry Andric if (FenceSSID == SyncScope::SingleThread) { 12975f757f3fSDimitry Andric MIB.buildInstr(TargetOpcode::MEMBARRIER, {}, {}); 12985f757f3fSDimitry Andric return; 12995f757f3fSDimitry Andric } 13005f757f3fSDimitry Andric 13015f757f3fSDimitry Andric // Refer to Table A.6 in the version 2.3 draft of the RISC-V Instruction Set 13025f757f3fSDimitry Andric // Manual: Volume I. 13035f757f3fSDimitry Andric unsigned Pred, Succ; 13045f757f3fSDimitry Andric switch (FenceOrdering) { 13055f757f3fSDimitry Andric default: 13065f757f3fSDimitry Andric llvm_unreachable("Unexpected ordering"); 13075f757f3fSDimitry Andric case AtomicOrdering::AcquireRelease: 13085f757f3fSDimitry Andric // fence acq_rel -> fence.tso 13095f757f3fSDimitry Andric MIB.buildInstr(RISCV::FENCE_TSO, {}, {}); 13105f757f3fSDimitry Andric return; 13115f757f3fSDimitry Andric case AtomicOrdering::Acquire: 13125f757f3fSDimitry Andric // fence acquire -> fence r, rw 13135f757f3fSDimitry Andric Pred = RISCVFenceField::R; 13145f757f3fSDimitry Andric Succ = RISCVFenceField::R | RISCVFenceField::W; 13155f757f3fSDimitry Andric break; 13165f757f3fSDimitry Andric case AtomicOrdering::Release: 13175f757f3fSDimitry Andric // fence release -> fence rw, w 13185f757f3fSDimitry Andric Pred = RISCVFenceField::R | RISCVFenceField::W; 13195f757f3fSDimitry Andric Succ = RISCVFenceField::W; 13205f757f3fSDimitry Andric break; 13215f757f3fSDimitry Andric case AtomicOrdering::SequentiallyConsistent: 13225f757f3fSDimitry Andric // fence seq_cst -> fence rw, rw 13235f757f3fSDimitry Andric Pred = RISCVFenceField::R | RISCVFenceField::W; 13245f757f3fSDimitry Andric Succ = RISCVFenceField::R | RISCVFenceField::W; 13255f757f3fSDimitry Andric break; 13265f757f3fSDimitry Andric } 13275f757f3fSDimitry Andric MIB.buildInstr(RISCV::FENCE, {}, {}).addImm(Pred).addImm(Succ); 1328bdd1243dSDimitry Andric } 1329bdd1243dSDimitry Andric 1330bdd1243dSDimitry Andric namespace llvm { 1331bdd1243dSDimitry Andric InstructionSelector * 1332bdd1243dSDimitry Andric createRISCVInstructionSelector(const RISCVTargetMachine &TM, 1333*0fca6ea1SDimitry Andric const RISCVSubtarget &Subtarget, 1334*0fca6ea1SDimitry Andric const RISCVRegisterBankInfo &RBI) { 1335bdd1243dSDimitry Andric return new RISCVInstructionSelector(TM, Subtarget, RBI); 1336bdd1243dSDimitry Andric } 1337bdd1243dSDimitry Andric } // end namespace llvm 1338