xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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