Path: blob/main/contrib/llvm-project/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
35294 views
//===-- RISCVInstructionSelector.cpp -----------------------------*- C++ -*-==//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7/// \file8/// This file implements the targeting of the InstructionSelector class for9/// RISC-V.10/// \todo This should be generated by TableGen.11//===----------------------------------------------------------------------===//1213#include "MCTargetDesc/RISCVMatInt.h"14#include "RISCVRegisterBankInfo.h"15#include "RISCVSubtarget.h"16#include "RISCVTargetMachine.h"17#include "llvm/CodeGen/GlobalISel/GIMatchTableExecutorImpl.h"18#include "llvm/CodeGen/GlobalISel/GISelKnownBits.h"19#include "llvm/CodeGen/GlobalISel/GenericMachineInstrs.h"20#include "llvm/CodeGen/GlobalISel/InstructionSelector.h"21#include "llvm/CodeGen/GlobalISel/MIPatternMatch.h"22#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"23#include "llvm/CodeGen/MachineJumpTableInfo.h"24#include "llvm/IR/IntrinsicsRISCV.h"25#include "llvm/Support/Debug.h"2627#define DEBUG_TYPE "riscv-isel"2829using namespace llvm;30using namespace MIPatternMatch;3132#define GET_GLOBALISEL_PREDICATE_BITSET33#include "RISCVGenGlobalISel.inc"34#undef GET_GLOBALISEL_PREDICATE_BITSET3536namespace {3738class RISCVInstructionSelector : public InstructionSelector {39public:40RISCVInstructionSelector(const RISCVTargetMachine &TM,41const RISCVSubtarget &STI,42const RISCVRegisterBankInfo &RBI);4344bool select(MachineInstr &MI) override;45static const char *getName() { return DEBUG_TYPE; }4647private:48const TargetRegisterClass *49getRegClassForTypeOnBank(LLT Ty, const RegisterBank &RB) const;5051bool isRegInGprb(Register Reg, MachineRegisterInfo &MRI) const;52bool isRegInFprb(Register Reg, MachineRegisterInfo &MRI) const;5354// tblgen-erated 'select' implementation, used as the initial selector for55// the patterns that don't require complex C++.56bool selectImpl(MachineInstr &I, CodeGenCoverage &CoverageInfo) const;5758// A lowering phase that runs before any selection attempts.59// Returns true if the instruction was modified.60void preISelLower(MachineInstr &MI, MachineIRBuilder &MIB,61MachineRegisterInfo &MRI);6263bool replacePtrWithInt(MachineOperand &Op, MachineIRBuilder &MIB,64MachineRegisterInfo &MRI);6566// Custom selection methods67bool selectCopy(MachineInstr &MI, MachineRegisterInfo &MRI) const;68bool selectImplicitDef(MachineInstr &MI, MachineIRBuilder &MIB,69MachineRegisterInfo &MRI) const;70bool materializeImm(Register Reg, int64_t Imm, MachineIRBuilder &MIB) const;71bool selectAddr(MachineInstr &MI, MachineIRBuilder &MIB,72MachineRegisterInfo &MRI, bool IsLocal = true,73bool IsExternWeak = false) const;74bool selectSExtInreg(MachineInstr &MI, MachineIRBuilder &MIB) const;75bool selectSelect(MachineInstr &MI, MachineIRBuilder &MIB,76MachineRegisterInfo &MRI) const;77bool selectFPCompare(MachineInstr &MI, MachineIRBuilder &MIB,78MachineRegisterInfo &MRI) const;79void emitFence(AtomicOrdering FenceOrdering, SyncScope::ID FenceSSID,80MachineIRBuilder &MIB) const;81bool selectMergeValues(MachineInstr &MI, MachineIRBuilder &MIB,82MachineRegisterInfo &MRI) const;83bool selectUnmergeValues(MachineInstr &MI, MachineIRBuilder &MIB,84MachineRegisterInfo &MRI) const;8586ComplexRendererFns selectShiftMask(MachineOperand &Root) const;87ComplexRendererFns selectAddrRegImm(MachineOperand &Root) const;8889ComplexRendererFns selectSHXADDOp(MachineOperand &Root, unsigned ShAmt) const;90template <unsigned ShAmt>91ComplexRendererFns selectSHXADDOp(MachineOperand &Root) const {92return selectSHXADDOp(Root, ShAmt);93}9495ComplexRendererFns selectSHXADD_UWOp(MachineOperand &Root,96unsigned ShAmt) const;97template <unsigned ShAmt>98ComplexRendererFns selectSHXADD_UWOp(MachineOperand &Root) const {99return selectSHXADD_UWOp(Root, ShAmt);100}101102// Custom renderers for tablegen103void renderNegImm(MachineInstrBuilder &MIB, const MachineInstr &MI,104int OpIdx) const;105void renderImmSubFromXLen(MachineInstrBuilder &MIB, const MachineInstr &MI,106int OpIdx) const;107void renderImmSubFrom32(MachineInstrBuilder &MIB, const MachineInstr &MI,108int OpIdx) const;109void renderImmPlus1(MachineInstrBuilder &MIB, const MachineInstr &MI,110int OpIdx) const;111void renderImm(MachineInstrBuilder &MIB, const MachineInstr &MI,112int OpIdx) const;113114void renderTrailingZeros(MachineInstrBuilder &MIB, const MachineInstr &MI,115int OpIdx) const;116117const RISCVSubtarget &STI;118const RISCVInstrInfo &TII;119const RISCVRegisterInfo &TRI;120const RISCVRegisterBankInfo &RBI;121const RISCVTargetMachine &TM;122123// FIXME: This is necessary because DAGISel uses "Subtarget->" and GlobalISel124// uses "STI." in the code generated by TableGen. We need to unify the name of125// Subtarget variable.126const RISCVSubtarget *Subtarget = &STI;127128#define GET_GLOBALISEL_PREDICATES_DECL129#include "RISCVGenGlobalISel.inc"130#undef GET_GLOBALISEL_PREDICATES_DECL131132#define GET_GLOBALISEL_TEMPORARIES_DECL133#include "RISCVGenGlobalISel.inc"134#undef GET_GLOBALISEL_TEMPORARIES_DECL135};136137} // end anonymous namespace138139#define GET_GLOBALISEL_IMPL140#include "RISCVGenGlobalISel.inc"141#undef GET_GLOBALISEL_IMPL142143RISCVInstructionSelector::RISCVInstructionSelector(144const RISCVTargetMachine &TM, const RISCVSubtarget &STI,145const RISCVRegisterBankInfo &RBI)146: STI(STI), TII(*STI.getInstrInfo()), TRI(*STI.getRegisterInfo()), RBI(RBI),147TM(TM),148149#define GET_GLOBALISEL_PREDICATES_INIT150#include "RISCVGenGlobalISel.inc"151#undef GET_GLOBALISEL_PREDICATES_INIT152#define GET_GLOBALISEL_TEMPORARIES_INIT153#include "RISCVGenGlobalISel.inc"154#undef GET_GLOBALISEL_TEMPORARIES_INIT155{156}157158InstructionSelector::ComplexRendererFns159RISCVInstructionSelector::selectShiftMask(MachineOperand &Root) const {160if (!Root.isReg())161return std::nullopt;162163using namespace llvm::MIPatternMatch;164MachineRegisterInfo &MRI = MF->getRegInfo();165166Register RootReg = Root.getReg();167Register ShAmtReg = RootReg;168const LLT ShiftLLT = MRI.getType(RootReg);169unsigned ShiftWidth = ShiftLLT.getSizeInBits();170assert(isPowerOf2_32(ShiftWidth) && "Unexpected max shift amount!");171// Peek through zext.172Register ZExtSrcReg;173if (mi_match(ShAmtReg, MRI, m_GZExt(m_Reg(ZExtSrcReg)))) {174ShAmtReg = ZExtSrcReg;175}176177APInt AndMask;178Register AndSrcReg;179// Try to combine the following pattern (applicable to other shift180// instructions as well as 32-bit ones):181//182// %4:gprb(s64) = G_AND %3, %2183// %5:gprb(s64) = G_LSHR %1, %4(s64)184//185// According to RISC-V's ISA manual, SLL, SRL, and SRA ignore other bits than186// the lowest log2(XLEN) bits of register rs2. As for the above pattern, if187// the lowest log2(XLEN) bits of register rd and rs2 of G_AND are the same,188// then it can be eliminated. Given register rs1 or rs2 holding a constant189// (the and mask), there are two cases G_AND can be erased:190//191// 1. the lowest log2(XLEN) bits of the and mask are all set192// 2. the bits of the register being masked are already unset (zero set)193if (mi_match(ShAmtReg, MRI, m_GAnd(m_Reg(AndSrcReg), m_ICst(AndMask)))) {194APInt ShMask(AndMask.getBitWidth(), ShiftWidth - 1);195if (ShMask.isSubsetOf(AndMask)) {196ShAmtReg = AndSrcReg;197} else {198// SimplifyDemandedBits may have optimized the mask so try restoring any199// bits that are known zero.200KnownBits Known = KB->getKnownBits(AndSrcReg);201if (ShMask.isSubsetOf(AndMask | Known.Zero))202ShAmtReg = AndSrcReg;203}204}205206APInt Imm;207Register Reg;208if (mi_match(ShAmtReg, MRI, m_GAdd(m_Reg(Reg), m_ICst(Imm)))) {209if (Imm != 0 && Imm.urem(ShiftWidth) == 0)210// If we are shifting by X+N where N == 0 mod Size, then just shift by X211// to avoid the ADD.212ShAmtReg = Reg;213} else if (mi_match(ShAmtReg, MRI, m_GSub(m_ICst(Imm), m_Reg(Reg)))) {214if (Imm != 0 && Imm.urem(ShiftWidth) == 0) {215// If we are shifting by N-X where N == 0 mod Size, then just shift by -X216// to generate a NEG instead of a SUB of a constant.217ShAmtReg = MRI.createVirtualRegister(&RISCV::GPRRegClass);218unsigned NegOpc = Subtarget->is64Bit() ? RISCV::SUBW : RISCV::SUB;219return {{[=](MachineInstrBuilder &MIB) {220MachineIRBuilder(*MIB.getInstr())221.buildInstr(NegOpc, {ShAmtReg}, {Register(RISCV::X0), Reg});222MIB.addReg(ShAmtReg);223}}};224}225if (Imm.urem(ShiftWidth) == ShiftWidth - 1) {226// If we are shifting by N-X where N == -1 mod Size, then just shift by ~X227// to generate a NOT instead of a SUB of a constant.228ShAmtReg = MRI.createVirtualRegister(&RISCV::GPRRegClass);229return {{[=](MachineInstrBuilder &MIB) {230MachineIRBuilder(*MIB.getInstr())231.buildInstr(RISCV::XORI, {ShAmtReg}, {Reg})232.addImm(-1);233MIB.addReg(ShAmtReg);234}}};235}236}237238return {{[=](MachineInstrBuilder &MIB) { MIB.addReg(ShAmtReg); }}};239}240241InstructionSelector::ComplexRendererFns242RISCVInstructionSelector::selectSHXADDOp(MachineOperand &Root,243unsigned ShAmt) const {244using namespace llvm::MIPatternMatch;245MachineFunction &MF = *Root.getParent()->getParent()->getParent();246MachineRegisterInfo &MRI = MF.getRegInfo();247248if (!Root.isReg())249return std::nullopt;250Register RootReg = Root.getReg();251252const unsigned XLen = STI.getXLen();253APInt Mask, C2;254Register RegY;255std::optional<bool> LeftShift;256// (and (shl y, c2), mask)257if (mi_match(RootReg, MRI,258m_GAnd(m_GShl(m_Reg(RegY), m_ICst(C2)), m_ICst(Mask))))259LeftShift = true;260// (and (lshr y, c2), mask)261else if (mi_match(RootReg, MRI,262m_GAnd(m_GLShr(m_Reg(RegY), m_ICst(C2)), m_ICst(Mask))))263LeftShift = false;264265if (LeftShift.has_value()) {266if (*LeftShift)267Mask &= maskTrailingZeros<uint64_t>(C2.getLimitedValue());268else269Mask &= maskTrailingOnes<uint64_t>(XLen - C2.getLimitedValue());270271if (Mask.isShiftedMask()) {272unsigned Leading = XLen - Mask.getActiveBits();273unsigned Trailing = Mask.countr_zero();274// Given (and (shl y, c2), mask) in which mask has no leading zeros and275// c3 trailing zeros. We can use an SRLI by c3 - c2 followed by a SHXADD.276if (*LeftShift && Leading == 0 && C2.ult(Trailing) && Trailing == ShAmt) {277Register DstReg = MRI.createVirtualRegister(&RISCV::GPRRegClass);278return {{[=](MachineInstrBuilder &MIB) {279MachineIRBuilder(*MIB.getInstr())280.buildInstr(RISCV::SRLI, {DstReg}, {RegY})281.addImm(Trailing - C2.getLimitedValue());282MIB.addReg(DstReg);283}}};284}285286// Given (and (lshr y, c2), mask) in which mask has c2 leading zeros and287// c3 trailing zeros. We can use an SRLI by c2 + c3 followed by a SHXADD.288if (!*LeftShift && Leading == C2 && Trailing == ShAmt) {289Register DstReg = MRI.createVirtualRegister(&RISCV::GPRRegClass);290return {{[=](MachineInstrBuilder &MIB) {291MachineIRBuilder(*MIB.getInstr())292.buildInstr(RISCV::SRLI, {DstReg}, {RegY})293.addImm(Leading + Trailing);294MIB.addReg(DstReg);295}}};296}297}298}299300LeftShift.reset();301302// (shl (and y, mask), c2)303if (mi_match(RootReg, MRI,304m_GShl(m_OneNonDBGUse(m_GAnd(m_Reg(RegY), m_ICst(Mask))),305m_ICst(C2))))306LeftShift = true;307// (lshr (and y, mask), c2)308else if (mi_match(RootReg, MRI,309m_GLShr(m_OneNonDBGUse(m_GAnd(m_Reg(RegY), m_ICst(Mask))),310m_ICst(C2))))311LeftShift = false;312313if (LeftShift.has_value() && Mask.isShiftedMask()) {314unsigned Leading = XLen - Mask.getActiveBits();315unsigned Trailing = Mask.countr_zero();316317// Given (shl (and y, mask), c2) in which mask has 32 leading zeros and318// c3 trailing zeros. If c1 + c3 == ShAmt, we can emit SRLIW + SHXADD.319bool Cond = *LeftShift && Leading == 32 && Trailing > 0 &&320(Trailing + C2.getLimitedValue()) == ShAmt;321if (!Cond)322// Given (lshr (and y, mask), c2) in which mask has 32 leading zeros and323// c3 trailing zeros. If c3 - c1 == ShAmt, we can emit SRLIW + SHXADD.324Cond = !*LeftShift && Leading == 32 && C2.ult(Trailing) &&325(Trailing - C2.getLimitedValue()) == ShAmt;326327if (Cond) {328Register DstReg = MRI.createVirtualRegister(&RISCV::GPRRegClass);329return {{[=](MachineInstrBuilder &MIB) {330MachineIRBuilder(*MIB.getInstr())331.buildInstr(RISCV::SRLIW, {DstReg}, {RegY})332.addImm(Trailing);333MIB.addReg(DstReg);334}}};335}336}337338return std::nullopt;339}340341InstructionSelector::ComplexRendererFns342RISCVInstructionSelector::selectSHXADD_UWOp(MachineOperand &Root,343unsigned ShAmt) const {344using namespace llvm::MIPatternMatch;345MachineFunction &MF = *Root.getParent()->getParent()->getParent();346MachineRegisterInfo &MRI = MF.getRegInfo();347348if (!Root.isReg())349return std::nullopt;350Register RootReg = Root.getReg();351352// Given (and (shl x, c2), mask) in which mask is a shifted mask with353// 32 - ShAmt leading zeros and c2 trailing zeros. We can use SLLI by354// c2 - ShAmt followed by SHXADD_UW with ShAmt for x amount.355APInt Mask, C2;356Register RegX;357if (mi_match(358RootReg, MRI,359m_OneNonDBGUse(m_GAnd(m_OneNonDBGUse(m_GShl(m_Reg(RegX), m_ICst(C2))),360m_ICst(Mask))))) {361Mask &= maskTrailingZeros<uint64_t>(C2.getLimitedValue());362363if (Mask.isShiftedMask()) {364unsigned Leading = Mask.countl_zero();365unsigned Trailing = Mask.countr_zero();366if (Leading == 32 - ShAmt && C2 == Trailing && Trailing > ShAmt) {367Register DstReg = MRI.createVirtualRegister(&RISCV::GPRRegClass);368return {{[=](MachineInstrBuilder &MIB) {369MachineIRBuilder(*MIB.getInstr())370.buildInstr(RISCV::SLLI, {DstReg}, {RegX})371.addImm(C2.getLimitedValue() - ShAmt);372MIB.addReg(DstReg);373}}};374}375}376}377378return std::nullopt;379}380381InstructionSelector::ComplexRendererFns382RISCVInstructionSelector::selectAddrRegImm(MachineOperand &Root) const {383MachineFunction &MF = *Root.getParent()->getParent()->getParent();384MachineRegisterInfo &MRI = MF.getRegInfo();385386if (!Root.isReg())387return std::nullopt;388389MachineInstr *RootDef = MRI.getVRegDef(Root.getReg());390if (RootDef->getOpcode() == TargetOpcode::G_FRAME_INDEX) {391return {{392[=](MachineInstrBuilder &MIB) { MIB.add(RootDef->getOperand(1)); },393[=](MachineInstrBuilder &MIB) { MIB.addImm(0); },394}};395}396397if (isBaseWithConstantOffset(Root, MRI)) {398MachineOperand &LHS = RootDef->getOperand(1);399MachineOperand &RHS = RootDef->getOperand(2);400MachineInstr *LHSDef = MRI.getVRegDef(LHS.getReg());401MachineInstr *RHSDef = MRI.getVRegDef(RHS.getReg());402403int64_t RHSC = RHSDef->getOperand(1).getCImm()->getSExtValue();404if (isInt<12>(RHSC)) {405if (LHSDef->getOpcode() == TargetOpcode::G_FRAME_INDEX)406return {{407[=](MachineInstrBuilder &MIB) { MIB.add(LHSDef->getOperand(1)); },408[=](MachineInstrBuilder &MIB) { MIB.addImm(RHSC); },409}};410411return {{[=](MachineInstrBuilder &MIB) { MIB.add(LHS); },412[=](MachineInstrBuilder &MIB) { MIB.addImm(RHSC); }}};413}414}415416// TODO: Need to get the immediate from a G_PTR_ADD. Should this be done in417// the combiner?418return {{[=](MachineInstrBuilder &MIB) { MIB.addReg(Root.getReg()); },419[=](MachineInstrBuilder &MIB) { MIB.addImm(0); }}};420}421422/// Returns the RISCVCC::CondCode that corresponds to the CmpInst::Predicate CC.423/// CC Must be an ICMP Predicate.424static RISCVCC::CondCode getRISCVCCFromICmp(CmpInst::Predicate CC) {425switch (CC) {426default:427llvm_unreachable("Expected ICMP CmpInst::Predicate.");428case CmpInst::Predicate::ICMP_EQ:429return RISCVCC::COND_EQ;430case CmpInst::Predicate::ICMP_NE:431return RISCVCC::COND_NE;432case CmpInst::Predicate::ICMP_ULT:433return RISCVCC::COND_LTU;434case CmpInst::Predicate::ICMP_SLT:435return RISCVCC::COND_LT;436case CmpInst::Predicate::ICMP_UGE:437return RISCVCC::COND_GEU;438case CmpInst::Predicate::ICMP_SGE:439return RISCVCC::COND_GE;440}441}442443static void getOperandsForBranch(Register CondReg, MachineRegisterInfo &MRI,444RISCVCC::CondCode &CC, Register &LHS,445Register &RHS) {446// Try to fold an ICmp. If that fails, use a NE compare with X0.447CmpInst::Predicate Pred = CmpInst::BAD_ICMP_PREDICATE;448if (!mi_match(CondReg, MRI, m_GICmp(m_Pred(Pred), m_Reg(LHS), m_Reg(RHS)))) {449LHS = CondReg;450RHS = RISCV::X0;451CC = RISCVCC::COND_NE;452return;453}454455// We found an ICmp, do some canonicalizations.456457// Adjust comparisons to use comparison with 0 if possible.458if (auto Constant = getIConstantVRegSExtVal(RHS, MRI)) {459switch (Pred) {460case CmpInst::Predicate::ICMP_SGT:461// Convert X > -1 to X >= 0462if (*Constant == -1) {463CC = RISCVCC::COND_GE;464RHS = RISCV::X0;465return;466}467break;468case CmpInst::Predicate::ICMP_SLT:469// Convert X < 1 to 0 >= X470if (*Constant == 1) {471CC = RISCVCC::COND_GE;472RHS = LHS;473LHS = RISCV::X0;474return;475}476break;477default:478break;479}480}481482switch (Pred) {483default:484llvm_unreachable("Expected ICMP CmpInst::Predicate.");485case CmpInst::Predicate::ICMP_EQ:486case CmpInst::Predicate::ICMP_NE:487case CmpInst::Predicate::ICMP_ULT:488case CmpInst::Predicate::ICMP_SLT:489case CmpInst::Predicate::ICMP_UGE:490case CmpInst::Predicate::ICMP_SGE:491// These CCs are supported directly by RISC-V branches.492break;493case CmpInst::Predicate::ICMP_SGT:494case CmpInst::Predicate::ICMP_SLE:495case CmpInst::Predicate::ICMP_UGT:496case CmpInst::Predicate::ICMP_ULE:497// These CCs are not supported directly by RISC-V branches, but changing the498// direction of the CC and swapping LHS and RHS are.499Pred = CmpInst::getSwappedPredicate(Pred);500std::swap(LHS, RHS);501break;502}503504CC = getRISCVCCFromICmp(Pred);505return;506}507508bool RISCVInstructionSelector::select(MachineInstr &MI) {509MachineBasicBlock &MBB = *MI.getParent();510MachineFunction &MF = *MBB.getParent();511MachineRegisterInfo &MRI = MF.getRegInfo();512MachineIRBuilder MIB(MI);513514preISelLower(MI, MIB, MRI);515const unsigned Opc = MI.getOpcode();516517if (!MI.isPreISelOpcode() || Opc == TargetOpcode::G_PHI) {518if (Opc == TargetOpcode::PHI || Opc == TargetOpcode::G_PHI) {519const Register DefReg = MI.getOperand(0).getReg();520const LLT DefTy = MRI.getType(DefReg);521522const RegClassOrRegBank &RegClassOrBank =523MRI.getRegClassOrRegBank(DefReg);524525const TargetRegisterClass *DefRC =526RegClassOrBank.dyn_cast<const TargetRegisterClass *>();527if (!DefRC) {528if (!DefTy.isValid()) {529LLVM_DEBUG(dbgs() << "PHI operand has no type, not a gvreg?\n");530return false;531}532533const RegisterBank &RB = *RegClassOrBank.get<const RegisterBank *>();534DefRC = getRegClassForTypeOnBank(DefTy, RB);535if (!DefRC) {536LLVM_DEBUG(dbgs() << "PHI operand has unexpected size/bank\n");537return false;538}539}540541MI.setDesc(TII.get(TargetOpcode::PHI));542return RBI.constrainGenericRegister(DefReg, *DefRC, MRI);543}544545// Certain non-generic instructions also need some special handling.546if (MI.isCopy())547return selectCopy(MI, MRI);548549return true;550}551552if (selectImpl(MI, *CoverageInfo))553return true;554555switch (Opc) {556case TargetOpcode::G_ANYEXT:557case TargetOpcode::G_PTRTOINT:558case TargetOpcode::G_INTTOPTR:559case TargetOpcode::G_TRUNC:560case TargetOpcode::G_FREEZE:561return selectCopy(MI, MRI);562case TargetOpcode::G_CONSTANT: {563Register DstReg = MI.getOperand(0).getReg();564int64_t Imm = MI.getOperand(1).getCImm()->getSExtValue();565566if (!materializeImm(DstReg, Imm, MIB))567return false;568569MI.eraseFromParent();570return true;571}572case TargetOpcode::G_FCONSTANT: {573// TODO: Use constant pool for complext constants.574// TODO: Optimize +0.0 to use fcvt.d.w for s64 on rv32.575Register DstReg = MI.getOperand(0).getReg();576const APFloat &FPimm = MI.getOperand(1).getFPImm()->getValueAPF();577APInt Imm = FPimm.bitcastToAPInt();578unsigned Size = MRI.getType(DstReg).getSizeInBits();579if (Size == 16 || Size == 32 || (Size == 64 && Subtarget->is64Bit())) {580Register GPRReg = MRI.createVirtualRegister(&RISCV::GPRRegClass);581if (!materializeImm(GPRReg, Imm.getSExtValue(), MIB))582return false;583584unsigned Opcode = Size == 64 ? RISCV::FMV_D_X585: Size == 32 ? RISCV::FMV_W_X586: RISCV::FMV_H_X;587auto FMV = MIB.buildInstr(Opcode, {DstReg}, {GPRReg});588if (!FMV.constrainAllUses(TII, TRI, RBI))589return false;590} else {591assert(Size == 64 && !Subtarget->is64Bit() &&592"Unexpected size or subtarget");593// Split into two pieces and build through the stack.594Register GPRRegHigh = MRI.createVirtualRegister(&RISCV::GPRRegClass);595Register GPRRegLow = MRI.createVirtualRegister(&RISCV::GPRRegClass);596if (!materializeImm(GPRRegHigh, Imm.extractBits(32, 32).getSExtValue(),597MIB))598return false;599if (!materializeImm(GPRRegLow, Imm.trunc(32).getSExtValue(), MIB))600return false;601MachineInstrBuilder PairF64 = MIB.buildInstr(602RISCV::BuildPairF64Pseudo, {DstReg}, {GPRRegLow, GPRRegHigh});603if (!PairF64.constrainAllUses(TII, TRI, RBI))604return false;605}606607MI.eraseFromParent();608return true;609}610case TargetOpcode::G_GLOBAL_VALUE: {611auto *GV = MI.getOperand(1).getGlobal();612if (GV->isThreadLocal()) {613// TODO: implement this case.614return false;615}616617return selectAddr(MI, MIB, MRI, GV->isDSOLocal(),618GV->hasExternalWeakLinkage());619}620case TargetOpcode::G_JUMP_TABLE:621case TargetOpcode::G_CONSTANT_POOL:622return selectAddr(MI, MIB, MRI);623case TargetOpcode::G_BRCOND: {624Register LHS, RHS;625RISCVCC::CondCode CC;626getOperandsForBranch(MI.getOperand(0).getReg(), MRI, CC, LHS, RHS);627628auto Bcc = MIB.buildInstr(RISCVCC::getBrCond(CC), {}, {LHS, RHS})629.addMBB(MI.getOperand(1).getMBB());630MI.eraseFromParent();631return constrainSelectedInstRegOperands(*Bcc, TII, TRI, RBI);632}633case TargetOpcode::G_BRJT: {634// FIXME: Move to legalization?635const MachineJumpTableInfo *MJTI = MF.getJumpTableInfo();636unsigned EntrySize = MJTI->getEntrySize(MF.getDataLayout());637assert((EntrySize == 4 || (Subtarget->is64Bit() && EntrySize == 8)) &&638"Unsupported jump-table entry size");639assert(640(MJTI->getEntryKind() == MachineJumpTableInfo::EK_LabelDifference32 ||641MJTI->getEntryKind() == MachineJumpTableInfo::EK_Custom32 ||642MJTI->getEntryKind() == MachineJumpTableInfo::EK_BlockAddress) &&643"Unexpected jump-table entry kind");644645auto SLL =646MIB.buildInstr(RISCV::SLLI, {&RISCV::GPRRegClass}, {MI.getOperand(2)})647.addImm(Log2_32(EntrySize));648if (!SLL.constrainAllUses(TII, TRI, RBI))649return false;650651// TODO: Use SHXADD. Moving to legalization would fix this automatically.652auto ADD = MIB.buildInstr(RISCV::ADD, {&RISCV::GPRRegClass},653{MI.getOperand(0), SLL.getReg(0)});654if (!ADD.constrainAllUses(TII, TRI, RBI))655return false;656657unsigned LdOpc = EntrySize == 8 ? RISCV::LD : RISCV::LW;658auto Dest =659MIB.buildInstr(LdOpc, {&RISCV::GPRRegClass}, {ADD.getReg(0)})660.addImm(0)661.addMemOperand(MF.getMachineMemOperand(662MachinePointerInfo::getJumpTable(MF), MachineMemOperand::MOLoad,663EntrySize, Align(MJTI->getEntryAlignment(MF.getDataLayout()))));664if (!Dest.constrainAllUses(TII, TRI, RBI))665return false;666667// If the Kind is EK_LabelDifference32, the table stores an offset from668// the location of the table. Add the table address to get an absolute669// address.670if (MJTI->getEntryKind() == MachineJumpTableInfo::EK_LabelDifference32) {671Dest = MIB.buildInstr(RISCV::ADD, {&RISCV::GPRRegClass},672{Dest.getReg(0), MI.getOperand(0)});673if (!Dest.constrainAllUses(TII, TRI, RBI))674return false;675}676677auto Branch =678MIB.buildInstr(RISCV::PseudoBRIND, {}, {Dest.getReg(0)}).addImm(0);679if (!Branch.constrainAllUses(TII, TRI, RBI))680return false;681682MI.eraseFromParent();683return true;684}685case TargetOpcode::G_BRINDIRECT:686MI.setDesc(TII.get(RISCV::PseudoBRIND));687MI.addOperand(MachineOperand::CreateImm(0));688return constrainSelectedInstRegOperands(MI, TII, TRI, RBI);689case TargetOpcode::G_SEXT_INREG:690return selectSExtInreg(MI, MIB);691case TargetOpcode::G_FRAME_INDEX: {692// TODO: We may want to replace this code with the SelectionDAG patterns,693// which fail to get imported because it uses FrameAddrRegImm, which is a694// ComplexPattern695MI.setDesc(TII.get(RISCV::ADDI));696MI.addOperand(MachineOperand::CreateImm(0));697return constrainSelectedInstRegOperands(MI, TII, TRI, RBI);698}699case TargetOpcode::G_SELECT:700return selectSelect(MI, MIB, MRI);701case TargetOpcode::G_FCMP:702return selectFPCompare(MI, MIB, MRI);703case TargetOpcode::G_FENCE: {704AtomicOrdering FenceOrdering =705static_cast<AtomicOrdering>(MI.getOperand(0).getImm());706SyncScope::ID FenceSSID =707static_cast<SyncScope::ID>(MI.getOperand(1).getImm());708emitFence(FenceOrdering, FenceSSID, MIB);709MI.eraseFromParent();710return true;711}712case TargetOpcode::G_IMPLICIT_DEF:713return selectImplicitDef(MI, MIB, MRI);714case TargetOpcode::G_MERGE_VALUES:715return selectMergeValues(MI, MIB, MRI);716case TargetOpcode::G_UNMERGE_VALUES:717return selectUnmergeValues(MI, MIB, MRI);718default:719return false;720}721}722723bool RISCVInstructionSelector::selectMergeValues(724MachineInstr &MI, MachineIRBuilder &MIB, MachineRegisterInfo &MRI) const {725assert(MI.getOpcode() == TargetOpcode::G_MERGE_VALUES);726727// Build a F64 Pair from operands728if (MI.getNumOperands() != 3)729return false;730Register Dst = MI.getOperand(0).getReg();731Register Lo = MI.getOperand(1).getReg();732Register Hi = MI.getOperand(2).getReg();733if (!isRegInFprb(Dst, MRI) || !isRegInGprb(Lo, MRI) || !isRegInGprb(Hi, MRI))734return false;735MI.setDesc(TII.get(RISCV::BuildPairF64Pseudo));736return constrainSelectedInstRegOperands(MI, TII, TRI, RBI);737}738739bool RISCVInstructionSelector::selectUnmergeValues(740MachineInstr &MI, MachineIRBuilder &MIB, MachineRegisterInfo &MRI) const {741assert(MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES);742743// Split F64 Src into two s32 parts744if (MI.getNumOperands() != 3)745return false;746Register Src = MI.getOperand(2).getReg();747Register Lo = MI.getOperand(0).getReg();748Register Hi = MI.getOperand(1).getReg();749if (!isRegInFprb(Src, MRI) || !isRegInGprb(Lo, MRI) || !isRegInGprb(Hi, MRI))750return false;751MI.setDesc(TII.get(RISCV::SplitF64Pseudo));752return constrainSelectedInstRegOperands(MI, TII, TRI, RBI);753}754755bool RISCVInstructionSelector::replacePtrWithInt(MachineOperand &Op,756MachineIRBuilder &MIB,757MachineRegisterInfo &MRI) {758Register PtrReg = Op.getReg();759assert(MRI.getType(PtrReg).isPointer() && "Operand is not a pointer!");760761const LLT sXLen = LLT::scalar(STI.getXLen());762auto PtrToInt = MIB.buildPtrToInt(sXLen, PtrReg);763MRI.setRegBank(PtrToInt.getReg(0), RBI.getRegBank(RISCV::GPRBRegBankID));764Op.setReg(PtrToInt.getReg(0));765return select(*PtrToInt);766}767768void RISCVInstructionSelector::preISelLower(MachineInstr &MI,769MachineIRBuilder &MIB,770MachineRegisterInfo &MRI) {771switch (MI.getOpcode()) {772case TargetOpcode::G_PTR_ADD: {773Register DstReg = MI.getOperand(0).getReg();774const LLT sXLen = LLT::scalar(STI.getXLen());775776replacePtrWithInt(MI.getOperand(1), MIB, MRI);777MI.setDesc(TII.get(TargetOpcode::G_ADD));778MRI.setType(DstReg, sXLen);779break;780}781case TargetOpcode::G_PTRMASK: {782Register DstReg = MI.getOperand(0).getReg();783const LLT sXLen = LLT::scalar(STI.getXLen());784replacePtrWithInt(MI.getOperand(1), MIB, MRI);785MI.setDesc(TII.get(TargetOpcode::G_AND));786MRI.setType(DstReg, sXLen);787}788}789}790791void RISCVInstructionSelector::renderNegImm(MachineInstrBuilder &MIB,792const MachineInstr &MI,793int OpIdx) const {794assert(MI.getOpcode() == TargetOpcode::G_CONSTANT && OpIdx == -1 &&795"Expected G_CONSTANT");796int64_t CstVal = MI.getOperand(1).getCImm()->getSExtValue();797MIB.addImm(-CstVal);798}799800void RISCVInstructionSelector::renderImmSubFromXLen(MachineInstrBuilder &MIB,801const MachineInstr &MI,802int OpIdx) const {803assert(MI.getOpcode() == TargetOpcode::G_CONSTANT && OpIdx == -1 &&804"Expected G_CONSTANT");805uint64_t CstVal = MI.getOperand(1).getCImm()->getZExtValue();806MIB.addImm(STI.getXLen() - CstVal);807}808809void RISCVInstructionSelector::renderImmSubFrom32(MachineInstrBuilder &MIB,810const MachineInstr &MI,811int OpIdx) const {812assert(MI.getOpcode() == TargetOpcode::G_CONSTANT && OpIdx == -1 &&813"Expected G_CONSTANT");814uint64_t CstVal = MI.getOperand(1).getCImm()->getZExtValue();815MIB.addImm(32 - CstVal);816}817818void RISCVInstructionSelector::renderImmPlus1(MachineInstrBuilder &MIB,819const MachineInstr &MI,820int OpIdx) const {821assert(MI.getOpcode() == TargetOpcode::G_CONSTANT && OpIdx == -1 &&822"Expected G_CONSTANT");823int64_t CstVal = MI.getOperand(1).getCImm()->getSExtValue();824MIB.addImm(CstVal + 1);825}826827void RISCVInstructionSelector::renderImm(MachineInstrBuilder &MIB,828const MachineInstr &MI,829int OpIdx) const {830assert(MI.getOpcode() == TargetOpcode::G_CONSTANT && OpIdx == -1 &&831"Expected G_CONSTANT");832int64_t CstVal = MI.getOperand(1).getCImm()->getSExtValue();833MIB.addImm(CstVal);834}835836void RISCVInstructionSelector::renderTrailingZeros(MachineInstrBuilder &MIB,837const MachineInstr &MI,838int OpIdx) const {839assert(MI.getOpcode() == TargetOpcode::G_CONSTANT && OpIdx == -1 &&840"Expected G_CONSTANT");841uint64_t C = MI.getOperand(1).getCImm()->getZExtValue();842MIB.addImm(llvm::countr_zero(C));843}844845const TargetRegisterClass *RISCVInstructionSelector::getRegClassForTypeOnBank(846LLT Ty, const RegisterBank &RB) const {847if (RB.getID() == RISCV::GPRBRegBankID) {848if (Ty.getSizeInBits() <= 32 || (STI.is64Bit() && Ty.getSizeInBits() == 64))849return &RISCV::GPRRegClass;850}851852if (RB.getID() == RISCV::FPRBRegBankID) {853if (Ty.getSizeInBits() == 16)854return &RISCV::FPR16RegClass;855if (Ty.getSizeInBits() == 32)856return &RISCV::FPR32RegClass;857if (Ty.getSizeInBits() == 64)858return &RISCV::FPR64RegClass;859}860861if (RB.getID() == RISCV::VRBRegBankID) {862if (Ty.getSizeInBits().getKnownMinValue() <= 64)863return &RISCV::VRRegClass;864865if (Ty.getSizeInBits().getKnownMinValue() == 128)866return &RISCV::VRM2RegClass;867868if (Ty.getSizeInBits().getKnownMinValue() == 256)869return &RISCV::VRM4RegClass;870871if (Ty.getSizeInBits().getKnownMinValue() == 512)872return &RISCV::VRM8RegClass;873}874875return nullptr;876}877878bool RISCVInstructionSelector::isRegInGprb(Register Reg,879MachineRegisterInfo &MRI) const {880return RBI.getRegBank(Reg, MRI, TRI)->getID() == RISCV::GPRBRegBankID;881}882883bool RISCVInstructionSelector::isRegInFprb(Register Reg,884MachineRegisterInfo &MRI) const {885return RBI.getRegBank(Reg, MRI, TRI)->getID() == RISCV::FPRBRegBankID;886}887888bool RISCVInstructionSelector::selectCopy(MachineInstr &MI,889MachineRegisterInfo &MRI) const {890Register DstReg = MI.getOperand(0).getReg();891892if (DstReg.isPhysical())893return true;894895const TargetRegisterClass *DstRC = getRegClassForTypeOnBank(896MRI.getType(DstReg), *RBI.getRegBank(DstReg, MRI, TRI));897assert(DstRC &&898"Register class not available for LLT, register bank combination");899900// No need to constrain SrcReg. It will get constrained when901// we hit another of its uses or its defs.902// Copies do not have constraints.903if (!RBI.constrainGenericRegister(DstReg, *DstRC, MRI)) {904LLVM_DEBUG(dbgs() << "Failed to constrain " << TII.getName(MI.getOpcode())905<< " operand\n");906return false;907}908909MI.setDesc(TII.get(RISCV::COPY));910return true;911}912913bool RISCVInstructionSelector::selectImplicitDef(914MachineInstr &MI, MachineIRBuilder &MIB, MachineRegisterInfo &MRI) const {915assert(MI.getOpcode() == TargetOpcode::G_IMPLICIT_DEF);916917const Register DstReg = MI.getOperand(0).getReg();918const TargetRegisterClass *DstRC = getRegClassForTypeOnBank(919MRI.getType(DstReg), *RBI.getRegBank(DstReg, MRI, TRI));920921assert(DstRC &&922"Register class not available for LLT, register bank combination");923924if (!RBI.constrainGenericRegister(DstReg, *DstRC, MRI)) {925LLVM_DEBUG(dbgs() << "Failed to constrain " << TII.getName(MI.getOpcode())926<< " operand\n");927}928MI.setDesc(TII.get(TargetOpcode::IMPLICIT_DEF));929return true;930}931932bool RISCVInstructionSelector::materializeImm(Register DstReg, int64_t Imm,933MachineIRBuilder &MIB) const {934MachineRegisterInfo &MRI = *MIB.getMRI();935936if (Imm == 0) {937MIB.buildCopy(DstReg, Register(RISCV::X0));938RBI.constrainGenericRegister(DstReg, RISCV::GPRRegClass, MRI);939return true;940}941942RISCVMatInt::InstSeq Seq = RISCVMatInt::generateInstSeq(Imm, *Subtarget);943unsigned NumInsts = Seq.size();944Register SrcReg = RISCV::X0;945946for (unsigned i = 0; i < NumInsts; i++) {947Register TmpReg = i < NumInsts - 1948? MRI.createVirtualRegister(&RISCV::GPRRegClass)949: DstReg;950const RISCVMatInt::Inst &I = Seq[i];951MachineInstr *Result;952953switch (I.getOpndKind()) {954case RISCVMatInt::Imm:955// clang-format off956Result = MIB.buildInstr(I.getOpcode(), {TmpReg}, {})957.addImm(I.getImm());958// clang-format on959break;960case RISCVMatInt::RegX0:961Result = MIB.buildInstr(I.getOpcode(), {TmpReg},962{SrcReg, Register(RISCV::X0)});963break;964case RISCVMatInt::RegReg:965Result = MIB.buildInstr(I.getOpcode(), {TmpReg}, {SrcReg, SrcReg});966break;967case RISCVMatInt::RegImm:968Result =969MIB.buildInstr(I.getOpcode(), {TmpReg}, {SrcReg}).addImm(I.getImm());970break;971}972973if (!constrainSelectedInstRegOperands(*Result, TII, TRI, RBI))974return false;975976SrcReg = TmpReg;977}978979return true;980}981982bool RISCVInstructionSelector::selectAddr(MachineInstr &MI,983MachineIRBuilder &MIB,984MachineRegisterInfo &MRI,985bool IsLocal,986bool IsExternWeak) const {987assert((MI.getOpcode() == TargetOpcode::G_GLOBAL_VALUE ||988MI.getOpcode() == TargetOpcode::G_JUMP_TABLE ||989MI.getOpcode() == TargetOpcode::G_CONSTANT_POOL) &&990"Unexpected opcode");991992const MachineOperand &DispMO = MI.getOperand(1);993994Register DefReg = MI.getOperand(0).getReg();995const LLT DefTy = MRI.getType(DefReg);996997// When HWASAN is used and tagging of global variables is enabled998// they should be accessed via the GOT, since the tagged address of a global999// is incompatible with existing code models. This also applies to non-pic1000// mode.1001if (TM.isPositionIndependent() || Subtarget->allowTaggedGlobals()) {1002if (IsLocal && !Subtarget->allowTaggedGlobals()) {1003// Use PC-relative addressing to access the symbol. This generates the1004// pattern (PseudoLLA sym), which expands to (addi (auipc %pcrel_hi(sym))1005// %pcrel_lo(auipc)).1006MI.setDesc(TII.get(RISCV::PseudoLLA));1007return constrainSelectedInstRegOperands(MI, TII, TRI, RBI);1008}10091010// Use PC-relative addressing to access the GOT for this symbol, then1011// load the address from the GOT. This generates the pattern (PseudoLGA1012// sym), which expands to (ld (addi (auipc %got_pcrel_hi(sym))1013// %pcrel_lo(auipc))).1014MachineFunction &MF = *MI.getParent()->getParent();1015MachineMemOperand *MemOp = MF.getMachineMemOperand(1016MachinePointerInfo::getGOT(MF),1017MachineMemOperand::MOLoad | MachineMemOperand::MODereferenceable |1018MachineMemOperand::MOInvariant,1019DefTy, Align(DefTy.getSizeInBits() / 8));10201021auto Result = MIB.buildInstr(RISCV::PseudoLGA, {DefReg}, {})1022.addDisp(DispMO, 0)1023.addMemOperand(MemOp);10241025if (!constrainSelectedInstRegOperands(*Result, TII, TRI, RBI))1026return false;10271028MI.eraseFromParent();1029return true;1030}10311032switch (TM.getCodeModel()) {1033default: {1034reportGISelFailure(const_cast<MachineFunction &>(*MF), *TPC, *MORE,1035getName(), "Unsupported code model for lowering", MI);1036return false;1037}1038case CodeModel::Small: {1039// Must lie within a single 2 GiB address range and must lie between1040// absolute addresses -2 GiB and +2 GiB. This generates the pattern (addi1041// (lui %hi(sym)) %lo(sym)).1042Register AddrHiDest = MRI.createVirtualRegister(&RISCV::GPRRegClass);1043MachineInstr *AddrHi = MIB.buildInstr(RISCV::LUI, {AddrHiDest}, {})1044.addDisp(DispMO, 0, RISCVII::MO_HI);10451046if (!constrainSelectedInstRegOperands(*AddrHi, TII, TRI, RBI))1047return false;10481049auto Result = MIB.buildInstr(RISCV::ADDI, {DefReg}, {AddrHiDest})1050.addDisp(DispMO, 0, RISCVII::MO_LO);10511052if (!constrainSelectedInstRegOperands(*Result, TII, TRI, RBI))1053return false;10541055MI.eraseFromParent();1056return true;1057}1058case CodeModel::Medium:1059// Emit LGA/LLA instead of the sequence it expands to because the pcrel_lo1060// relocation needs to reference a label that points to the auipc1061// instruction itself, not the global. This cannot be done inside the1062// instruction selector.1063if (IsExternWeak) {1064// An extern weak symbol may be undefined, i.e. have value 0, which may1065// not be within 2GiB of PC, so use GOT-indirect addressing to access the1066// symbol. This generates the pattern (PseudoLGA sym), which expands to1067// (ld (addi (auipc %got_pcrel_hi(sym)) %pcrel_lo(auipc))).1068MachineFunction &MF = *MI.getParent()->getParent();1069MachineMemOperand *MemOp = MF.getMachineMemOperand(1070MachinePointerInfo::getGOT(MF),1071MachineMemOperand::MOLoad | MachineMemOperand::MODereferenceable |1072MachineMemOperand::MOInvariant,1073DefTy, Align(DefTy.getSizeInBits() / 8));10741075auto Result = MIB.buildInstr(RISCV::PseudoLGA, {DefReg}, {})1076.addDisp(DispMO, 0)1077.addMemOperand(MemOp);10781079if (!constrainSelectedInstRegOperands(*Result, TII, TRI, RBI))1080return false;10811082MI.eraseFromParent();1083return true;1084}10851086// Generate a sequence for accessing addresses within any 2GiB range1087// within the address space. This generates the pattern (PseudoLLA sym),1088// which expands to (addi (auipc %pcrel_hi(sym)) %pcrel_lo(auipc)).1089MI.setDesc(TII.get(RISCV::PseudoLLA));1090return constrainSelectedInstRegOperands(MI, TII, TRI, RBI);1091}10921093return false;1094}10951096bool RISCVInstructionSelector::selectSExtInreg(MachineInstr &MI,1097MachineIRBuilder &MIB) const {1098if (!STI.isRV64())1099return false;11001101const MachineOperand &Size = MI.getOperand(2);1102// Only Size == 32 (i.e. shift by 32 bits) is acceptable at this point.1103if (!Size.isImm() || Size.getImm() != 32)1104return false;11051106const MachineOperand &Src = MI.getOperand(1);1107const MachineOperand &Dst = MI.getOperand(0);1108// addiw rd, rs, 0 (i.e. sext.w rd, rs)1109MachineInstr *NewMI =1110MIB.buildInstr(RISCV::ADDIW, {Dst.getReg()}, {Src.getReg()}).addImm(0U);11111112if (!constrainSelectedInstRegOperands(*NewMI, TII, TRI, RBI))1113return false;11141115MI.eraseFromParent();1116return true;1117}11181119bool RISCVInstructionSelector::selectSelect(MachineInstr &MI,1120MachineIRBuilder &MIB,1121MachineRegisterInfo &MRI) const {1122auto &SelectMI = cast<GSelect>(MI);11231124Register LHS, RHS;1125RISCVCC::CondCode CC;1126getOperandsForBranch(SelectMI.getCondReg(), MRI, CC, LHS, RHS);11271128Register DstReg = SelectMI.getReg(0);11291130unsigned Opc = RISCV::Select_GPR_Using_CC_GPR;1131if (RBI.getRegBank(DstReg, MRI, TRI)->getID() == RISCV::FPRBRegBankID) {1132unsigned Size = MRI.getType(DstReg).getSizeInBits();1133Opc = Size == 32 ? RISCV::Select_FPR32_Using_CC_GPR1134: RISCV::Select_FPR64_Using_CC_GPR;1135}11361137MachineInstr *Result = MIB.buildInstr(Opc)1138.addDef(DstReg)1139.addReg(LHS)1140.addReg(RHS)1141.addImm(CC)1142.addReg(SelectMI.getTrueReg())1143.addReg(SelectMI.getFalseReg());1144MI.eraseFromParent();1145return constrainSelectedInstRegOperands(*Result, TII, TRI, RBI);1146}11471148// Convert an FCMP predicate to one of the supported F or D instructions.1149static unsigned getFCmpOpcode(CmpInst::Predicate Pred, unsigned Size) {1150assert((Size == 16 || Size == 32 || Size == 64) && "Unsupported size");1151switch (Pred) {1152default:1153llvm_unreachable("Unsupported predicate");1154case CmpInst::FCMP_OLT:1155return Size == 16 ? RISCV::FLT_H : Size == 32 ? RISCV::FLT_S : RISCV::FLT_D;1156case CmpInst::FCMP_OLE:1157return Size == 16 ? RISCV::FLE_H : Size == 32 ? RISCV::FLE_S : RISCV::FLE_D;1158case CmpInst::FCMP_OEQ:1159return Size == 16 ? RISCV::FEQ_H : Size == 32 ? RISCV::FEQ_S : RISCV::FEQ_D;1160}1161}11621163// Try legalizing an FCMP by swapping or inverting the predicate to one that1164// is supported.1165static bool legalizeFCmpPredicate(Register &LHS, Register &RHS,1166CmpInst::Predicate &Pred, bool &NeedInvert) {1167auto isLegalFCmpPredicate = [](CmpInst::Predicate Pred) {1168return Pred == CmpInst::FCMP_OLT || Pred == CmpInst::FCMP_OLE ||1169Pred == CmpInst::FCMP_OEQ;1170};11711172assert(!isLegalFCmpPredicate(Pred) && "Predicate already legal?");11731174CmpInst::Predicate InvPred = CmpInst::getSwappedPredicate(Pred);1175if (isLegalFCmpPredicate(InvPred)) {1176Pred = InvPred;1177std::swap(LHS, RHS);1178return true;1179}11801181InvPred = CmpInst::getInversePredicate(Pred);1182NeedInvert = true;1183if (isLegalFCmpPredicate(InvPred)) {1184Pred = InvPred;1185return true;1186}1187InvPred = CmpInst::getSwappedPredicate(InvPred);1188if (isLegalFCmpPredicate(InvPred)) {1189Pred = InvPred;1190std::swap(LHS, RHS);1191return true;1192}11931194return false;1195}11961197// Emit a sequence of instructions to compare LHS and RHS using Pred. Return1198// the result in DstReg.1199// FIXME: Maybe we should expand this earlier.1200bool RISCVInstructionSelector::selectFPCompare(MachineInstr &MI,1201MachineIRBuilder &MIB,1202MachineRegisterInfo &MRI) const {1203auto &CmpMI = cast<GFCmp>(MI);1204CmpInst::Predicate Pred = CmpMI.getCond();12051206Register DstReg = CmpMI.getReg(0);1207Register LHS = CmpMI.getLHSReg();1208Register RHS = CmpMI.getRHSReg();12091210unsigned Size = MRI.getType(LHS).getSizeInBits();1211assert((Size == 16 || Size == 32 || Size == 64) && "Unexpected size");12121213Register TmpReg = DstReg;12141215bool NeedInvert = false;1216// First try swapping operands or inverting.1217if (legalizeFCmpPredicate(LHS, RHS, Pred, NeedInvert)) {1218if (NeedInvert)1219TmpReg = MRI.createVirtualRegister(&RISCV::GPRRegClass);1220auto Cmp = MIB.buildInstr(getFCmpOpcode(Pred, Size), {TmpReg}, {LHS, RHS});1221if (!Cmp.constrainAllUses(TII, TRI, RBI))1222return false;1223} else if (Pred == CmpInst::FCMP_ONE || Pred == CmpInst::FCMP_UEQ) {1224// fcmp one LHS, RHS => (OR (FLT LHS, RHS), (FLT RHS, LHS))1225NeedInvert = Pred == CmpInst::FCMP_UEQ;1226auto Cmp1 = MIB.buildInstr(getFCmpOpcode(CmpInst::FCMP_OLT, Size),1227{&RISCV::GPRRegClass}, {LHS, RHS});1228if (!Cmp1.constrainAllUses(TII, TRI, RBI))1229return false;1230auto Cmp2 = MIB.buildInstr(getFCmpOpcode(CmpInst::FCMP_OLT, Size),1231{&RISCV::GPRRegClass}, {RHS, LHS});1232if (!Cmp2.constrainAllUses(TII, TRI, RBI))1233return false;1234if (NeedInvert)1235TmpReg = MRI.createVirtualRegister(&RISCV::GPRRegClass);1236auto Or =1237MIB.buildInstr(RISCV::OR, {TmpReg}, {Cmp1.getReg(0), Cmp2.getReg(0)});1238if (!Or.constrainAllUses(TII, TRI, RBI))1239return false;1240} else if (Pred == CmpInst::FCMP_ORD || Pred == CmpInst::FCMP_UNO) {1241// fcmp ord LHS, RHS => (AND (FEQ LHS, LHS), (FEQ RHS, RHS))1242// FIXME: If LHS and RHS are the same we can use a single FEQ.1243NeedInvert = Pred == CmpInst::FCMP_UNO;1244auto Cmp1 = MIB.buildInstr(getFCmpOpcode(CmpInst::FCMP_OEQ, Size),1245{&RISCV::GPRRegClass}, {LHS, LHS});1246if (!Cmp1.constrainAllUses(TII, TRI, RBI))1247return false;1248auto Cmp2 = MIB.buildInstr(getFCmpOpcode(CmpInst::FCMP_OEQ, Size),1249{&RISCV::GPRRegClass}, {RHS, RHS});1250if (!Cmp2.constrainAllUses(TII, TRI, RBI))1251return false;1252if (NeedInvert)1253TmpReg = MRI.createVirtualRegister(&RISCV::GPRRegClass);1254auto And =1255MIB.buildInstr(RISCV::AND, {TmpReg}, {Cmp1.getReg(0), Cmp2.getReg(0)});1256if (!And.constrainAllUses(TII, TRI, RBI))1257return false;1258} else1259llvm_unreachable("Unhandled predicate");12601261// Emit an XORI to invert the result if needed.1262if (NeedInvert) {1263auto Xor = MIB.buildInstr(RISCV::XORI, {DstReg}, {TmpReg}).addImm(1);1264if (!Xor.constrainAllUses(TII, TRI, RBI))1265return false;1266}12671268MI.eraseFromParent();1269return true;1270}12711272void RISCVInstructionSelector::emitFence(AtomicOrdering FenceOrdering,1273SyncScope::ID FenceSSID,1274MachineIRBuilder &MIB) const {1275if (STI.hasStdExtZtso()) {1276// The only fence that needs an instruction is a sequentially-consistent1277// cross-thread fence.1278if (FenceOrdering == AtomicOrdering::SequentiallyConsistent &&1279FenceSSID == SyncScope::System) {1280// fence rw, rw1281MIB.buildInstr(RISCV::FENCE, {}, {})1282.addImm(RISCVFenceField::R | RISCVFenceField::W)1283.addImm(RISCVFenceField::R | RISCVFenceField::W);1284return;1285}12861287// MEMBARRIER is a compiler barrier; it codegens to a no-op.1288MIB.buildInstr(TargetOpcode::MEMBARRIER, {}, {});1289return;1290}12911292// singlethread fences only synchronize with signal handlers on the same1293// thread and thus only need to preserve instruction order, not actually1294// enforce memory ordering.1295if (FenceSSID == SyncScope::SingleThread) {1296MIB.buildInstr(TargetOpcode::MEMBARRIER, {}, {});1297return;1298}12991300// Refer to Table A.6 in the version 2.3 draft of the RISC-V Instruction Set1301// Manual: Volume I.1302unsigned Pred, Succ;1303switch (FenceOrdering) {1304default:1305llvm_unreachable("Unexpected ordering");1306case AtomicOrdering::AcquireRelease:1307// fence acq_rel -> fence.tso1308MIB.buildInstr(RISCV::FENCE_TSO, {}, {});1309return;1310case AtomicOrdering::Acquire:1311// fence acquire -> fence r, rw1312Pred = RISCVFenceField::R;1313Succ = RISCVFenceField::R | RISCVFenceField::W;1314break;1315case AtomicOrdering::Release:1316// fence release -> fence rw, w1317Pred = RISCVFenceField::R | RISCVFenceField::W;1318Succ = RISCVFenceField::W;1319break;1320case AtomicOrdering::SequentiallyConsistent:1321// fence seq_cst -> fence rw, rw1322Pred = RISCVFenceField::R | RISCVFenceField::W;1323Succ = RISCVFenceField::R | RISCVFenceField::W;1324break;1325}1326MIB.buildInstr(RISCV::FENCE, {}, {}).addImm(Pred).addImm(Succ);1327}13281329namespace llvm {1330InstructionSelector *1331createRISCVInstructionSelector(const RISCVTargetMachine &TM,1332const RISCVSubtarget &Subtarget,1333const RISCVRegisterBankInfo &RBI) {1334return new RISCVInstructionSelector(TM, Subtarget, RBI);1335}1336} // end namespace llvm133713381339