10b57cec5SDimitry Andric //===-- RISCVISelDAGToDAG.cpp - A dag to dag inst selector for RISCV ------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This file defines an instruction selector for the RISCV target. 100b57cec5SDimitry Andric // 110b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 120b57cec5SDimitry Andric 135ffd83dbSDimitry Andric #include "RISCVISelDAGToDAG.h" 140b57cec5SDimitry Andric #include "MCTargetDesc/RISCVMCTargetDesc.h" 150b57cec5SDimitry Andric #include "Utils/RISCVMatInt.h" 160b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h" 175ffd83dbSDimitry Andric #include "llvm/Support/Alignment.h" 180b57cec5SDimitry Andric #include "llvm/Support/Debug.h" 190b57cec5SDimitry Andric #include "llvm/Support/MathExtras.h" 200b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 215ffd83dbSDimitry Andric 220b57cec5SDimitry Andric using namespace llvm; 230b57cec5SDimitry Andric 240b57cec5SDimitry Andric #define DEBUG_TYPE "riscv-isel" 250b57cec5SDimitry Andric 260b57cec5SDimitry Andric void RISCVDAGToDAGISel::PostprocessISelDAG() { 270b57cec5SDimitry Andric doPeepholeLoadStoreADDI(); 280b57cec5SDimitry Andric } 290b57cec5SDimitry Andric 300b57cec5SDimitry Andric static SDNode *selectImm(SelectionDAG *CurDAG, const SDLoc &DL, int64_t Imm, 310b57cec5SDimitry Andric MVT XLenVT) { 320b57cec5SDimitry Andric RISCVMatInt::InstSeq Seq; 330b57cec5SDimitry Andric RISCVMatInt::generateInstSeq(Imm, XLenVT == MVT::i64, Seq); 340b57cec5SDimitry Andric 358bcb0991SDimitry Andric SDNode *Result = nullptr; 360b57cec5SDimitry Andric SDValue SrcReg = CurDAG->getRegister(RISCV::X0, XLenVT); 370b57cec5SDimitry Andric for (RISCVMatInt::Inst &Inst : Seq) { 380b57cec5SDimitry Andric SDValue SDImm = CurDAG->getTargetConstant(Inst.Imm, DL, XLenVT); 390b57cec5SDimitry Andric if (Inst.Opc == RISCV::LUI) 400b57cec5SDimitry Andric Result = CurDAG->getMachineNode(RISCV::LUI, DL, XLenVT, SDImm); 410b57cec5SDimitry Andric else 420b57cec5SDimitry Andric Result = CurDAG->getMachineNode(Inst.Opc, DL, XLenVT, SrcReg, SDImm); 430b57cec5SDimitry Andric 440b57cec5SDimitry Andric // Only the first instruction has X0 as its source. 450b57cec5SDimitry Andric SrcReg = SDValue(Result, 0); 460b57cec5SDimitry Andric } 470b57cec5SDimitry Andric 480b57cec5SDimitry Andric return Result; 490b57cec5SDimitry Andric } 500b57cec5SDimitry Andric 510b57cec5SDimitry Andric // Returns true if the Node is an ISD::AND with a constant argument. If so, 520b57cec5SDimitry Andric // set Mask to that constant value. 530b57cec5SDimitry Andric static bool isConstantMask(SDNode *Node, uint64_t &Mask) { 540b57cec5SDimitry Andric if (Node->getOpcode() == ISD::AND && 550b57cec5SDimitry Andric Node->getOperand(1).getOpcode() == ISD::Constant) { 560b57cec5SDimitry Andric Mask = cast<ConstantSDNode>(Node->getOperand(1))->getZExtValue(); 570b57cec5SDimitry Andric return true; 580b57cec5SDimitry Andric } 590b57cec5SDimitry Andric return false; 600b57cec5SDimitry Andric } 610b57cec5SDimitry Andric 620b57cec5SDimitry Andric void RISCVDAGToDAGISel::Select(SDNode *Node) { 630b57cec5SDimitry Andric // If we have a custom node, we have already selected. 640b57cec5SDimitry Andric if (Node->isMachineOpcode()) { 650b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "== "; Node->dump(CurDAG); dbgs() << "\n"); 660b57cec5SDimitry Andric Node->setNodeId(-1); 670b57cec5SDimitry Andric return; 680b57cec5SDimitry Andric } 690b57cec5SDimitry Andric 700b57cec5SDimitry Andric // Instruction Selection not handled by the auto-generated tablegen selection 710b57cec5SDimitry Andric // should be handled here. 720b57cec5SDimitry Andric unsigned Opcode = Node->getOpcode(); 730b57cec5SDimitry Andric MVT XLenVT = Subtarget->getXLenVT(); 740b57cec5SDimitry Andric SDLoc DL(Node); 750b57cec5SDimitry Andric EVT VT = Node->getValueType(0); 760b57cec5SDimitry Andric 770b57cec5SDimitry Andric switch (Opcode) { 785ffd83dbSDimitry Andric case ISD::ADD: { 795ffd83dbSDimitry Andric // Optimize (add r, imm) to (addi (addi r, imm0) imm1) if applicable. The 805ffd83dbSDimitry Andric // immediate must be in specific ranges and have a single use. 815ffd83dbSDimitry Andric if (auto *ConstOp = dyn_cast<ConstantSDNode>(Node->getOperand(1))) { 825ffd83dbSDimitry Andric if (!(ConstOp->hasOneUse())) 835ffd83dbSDimitry Andric break; 845ffd83dbSDimitry Andric // The imm must be in range [-4096,-2049] or [2048,4094]. 855ffd83dbSDimitry Andric int64_t Imm = ConstOp->getSExtValue(); 865ffd83dbSDimitry Andric if (!(-4096 <= Imm && Imm <= -2049) && !(2048 <= Imm && Imm <= 4094)) 875ffd83dbSDimitry Andric break; 885ffd83dbSDimitry Andric // Break the imm to imm0+imm1. 895ffd83dbSDimitry Andric SDLoc DL(Node); 905ffd83dbSDimitry Andric EVT VT = Node->getValueType(0); 915ffd83dbSDimitry Andric const SDValue ImmOp0 = CurDAG->getTargetConstant(Imm - Imm / 2, DL, VT); 925ffd83dbSDimitry Andric const SDValue ImmOp1 = CurDAG->getTargetConstant(Imm / 2, DL, VT); 935ffd83dbSDimitry Andric auto *NodeAddi0 = CurDAG->getMachineNode(RISCV::ADDI, DL, VT, 945ffd83dbSDimitry Andric Node->getOperand(0), ImmOp0); 955ffd83dbSDimitry Andric auto *NodeAddi1 = CurDAG->getMachineNode(RISCV::ADDI, DL, VT, 965ffd83dbSDimitry Andric SDValue(NodeAddi0, 0), ImmOp1); 975ffd83dbSDimitry Andric ReplaceNode(Node, NodeAddi1); 985ffd83dbSDimitry Andric return; 995ffd83dbSDimitry Andric } 1005ffd83dbSDimitry Andric break; 1015ffd83dbSDimitry Andric } 1020b57cec5SDimitry Andric case ISD::Constant: { 1030b57cec5SDimitry Andric auto ConstNode = cast<ConstantSDNode>(Node); 1040b57cec5SDimitry Andric if (VT == XLenVT && ConstNode->isNullValue()) { 1050b57cec5SDimitry Andric SDValue New = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), SDLoc(Node), 1060b57cec5SDimitry Andric RISCV::X0, XLenVT); 1070b57cec5SDimitry Andric ReplaceNode(Node, New.getNode()); 1080b57cec5SDimitry Andric return; 1090b57cec5SDimitry Andric } 1100b57cec5SDimitry Andric int64_t Imm = ConstNode->getSExtValue(); 1110b57cec5SDimitry Andric if (XLenVT == MVT::i64) { 1120b57cec5SDimitry Andric ReplaceNode(Node, selectImm(CurDAG, SDLoc(Node), Imm, XLenVT)); 1130b57cec5SDimitry Andric return; 1140b57cec5SDimitry Andric } 1150b57cec5SDimitry Andric break; 1160b57cec5SDimitry Andric } 1170b57cec5SDimitry Andric case ISD::FrameIndex: { 1180b57cec5SDimitry Andric SDValue Imm = CurDAG->getTargetConstant(0, DL, XLenVT); 1190b57cec5SDimitry Andric int FI = cast<FrameIndexSDNode>(Node)->getIndex(); 1200b57cec5SDimitry Andric SDValue TFI = CurDAG->getTargetFrameIndex(FI, VT); 1210b57cec5SDimitry Andric ReplaceNode(Node, CurDAG->getMachineNode(RISCV::ADDI, DL, VT, TFI, Imm)); 1220b57cec5SDimitry Andric return; 1230b57cec5SDimitry Andric } 1240b57cec5SDimitry Andric case ISD::SRL: { 1250b57cec5SDimitry Andric if (!Subtarget->is64Bit()) 1260b57cec5SDimitry Andric break; 1270b57cec5SDimitry Andric SDValue Op0 = Node->getOperand(0); 1280b57cec5SDimitry Andric SDValue Op1 = Node->getOperand(1); 1290b57cec5SDimitry Andric uint64_t Mask; 1300b57cec5SDimitry Andric // Match (srl (and val, mask), imm) where the result would be a 1310b57cec5SDimitry Andric // zero-extended 32-bit integer. i.e. the mask is 0xffffffff or the result 1320b57cec5SDimitry Andric // is equivalent to this (SimplifyDemandedBits may have removed lower bits 1330b57cec5SDimitry Andric // from the mask that aren't necessary due to the right-shifting). 1340b57cec5SDimitry Andric if (Op1.getOpcode() == ISD::Constant && 1350b57cec5SDimitry Andric isConstantMask(Op0.getNode(), Mask)) { 1360b57cec5SDimitry Andric uint64_t ShAmt = cast<ConstantSDNode>(Op1.getNode())->getZExtValue(); 1370b57cec5SDimitry Andric 1380b57cec5SDimitry Andric if ((Mask | maskTrailingOnes<uint64_t>(ShAmt)) == 0xffffffff) { 1390b57cec5SDimitry Andric SDValue ShAmtVal = 1400b57cec5SDimitry Andric CurDAG->getTargetConstant(ShAmt, SDLoc(Node), XLenVT); 1410b57cec5SDimitry Andric CurDAG->SelectNodeTo(Node, RISCV::SRLIW, XLenVT, Op0.getOperand(0), 1420b57cec5SDimitry Andric ShAmtVal); 1430b57cec5SDimitry Andric return; 1440b57cec5SDimitry Andric } 1450b57cec5SDimitry Andric } 1460b57cec5SDimitry Andric break; 1470b57cec5SDimitry Andric } 1480b57cec5SDimitry Andric case RISCVISD::READ_CYCLE_WIDE: 1490b57cec5SDimitry Andric assert(!Subtarget->is64Bit() && "READ_CYCLE_WIDE is only used on riscv32"); 1500b57cec5SDimitry Andric 1510b57cec5SDimitry Andric ReplaceNode(Node, CurDAG->getMachineNode(RISCV::ReadCycleWide, DL, MVT::i32, 1520b57cec5SDimitry Andric MVT::i32, MVT::Other, 1530b57cec5SDimitry Andric Node->getOperand(0))); 1540b57cec5SDimitry Andric return; 1550b57cec5SDimitry Andric } 1560b57cec5SDimitry Andric 1570b57cec5SDimitry Andric // Select the default instruction. 1580b57cec5SDimitry Andric SelectCode(Node); 1590b57cec5SDimitry Andric } 1600b57cec5SDimitry Andric 1610b57cec5SDimitry Andric bool RISCVDAGToDAGISel::SelectInlineAsmMemoryOperand( 1620b57cec5SDimitry Andric const SDValue &Op, unsigned ConstraintID, std::vector<SDValue> &OutOps) { 1630b57cec5SDimitry Andric switch (ConstraintID) { 1640b57cec5SDimitry Andric case InlineAsm::Constraint_m: 1650b57cec5SDimitry Andric // We just support simple memory operands that have a single address 1660b57cec5SDimitry Andric // operand and need no special handling. 1670b57cec5SDimitry Andric OutOps.push_back(Op); 1680b57cec5SDimitry Andric return false; 1690b57cec5SDimitry Andric case InlineAsm::Constraint_A: 1700b57cec5SDimitry Andric OutOps.push_back(Op); 1710b57cec5SDimitry Andric return false; 1720b57cec5SDimitry Andric default: 1730b57cec5SDimitry Andric break; 1740b57cec5SDimitry Andric } 1750b57cec5SDimitry Andric 1760b57cec5SDimitry Andric return true; 1770b57cec5SDimitry Andric } 1780b57cec5SDimitry Andric 1790b57cec5SDimitry Andric bool RISCVDAGToDAGISel::SelectAddrFI(SDValue Addr, SDValue &Base) { 1800b57cec5SDimitry Andric if (auto FIN = dyn_cast<FrameIndexSDNode>(Addr)) { 1810b57cec5SDimitry Andric Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), Subtarget->getXLenVT()); 1820b57cec5SDimitry Andric return true; 1830b57cec5SDimitry Andric } 1840b57cec5SDimitry Andric return false; 1850b57cec5SDimitry Andric } 1860b57cec5SDimitry Andric 187*979e22ffSDimitry Andric // Check that it is a SLOI (Shift Left Ones Immediate). We first check that 188*979e22ffSDimitry Andric // it is the right node tree: 189*979e22ffSDimitry Andric // 190*979e22ffSDimitry Andric // (OR (SHL RS1, VC2), VC1) 191*979e22ffSDimitry Andric // 192*979e22ffSDimitry Andric // and then we check that VC1, the mask used to fill with ones, is compatible 193*979e22ffSDimitry Andric // with VC2, the shamt: 194*979e22ffSDimitry Andric // 195*979e22ffSDimitry Andric // VC1 == maskTrailingOnes<uint64_t>(VC2) 196*979e22ffSDimitry Andric 197*979e22ffSDimitry Andric bool RISCVDAGToDAGISel::SelectSLOI(SDValue N, SDValue &RS1, SDValue &Shamt) { 198*979e22ffSDimitry Andric MVT XLenVT = Subtarget->getXLenVT(); 199*979e22ffSDimitry Andric if (N.getOpcode() == ISD::OR) { 200*979e22ffSDimitry Andric SDValue Or = N; 201*979e22ffSDimitry Andric if (Or.getOperand(0).getOpcode() == ISD::SHL) { 202*979e22ffSDimitry Andric SDValue Shl = Or.getOperand(0); 203*979e22ffSDimitry Andric if (isa<ConstantSDNode>(Shl.getOperand(1)) && 204*979e22ffSDimitry Andric isa<ConstantSDNode>(Or.getOperand(1))) { 205*979e22ffSDimitry Andric if (XLenVT == MVT::i64) { 206*979e22ffSDimitry Andric uint64_t VC1 = Or.getConstantOperandVal(1); 207*979e22ffSDimitry Andric uint64_t VC2 = Shl.getConstantOperandVal(1); 208*979e22ffSDimitry Andric if (VC1 == maskTrailingOnes<uint64_t>(VC2)) { 209*979e22ffSDimitry Andric RS1 = Shl.getOperand(0); 210*979e22ffSDimitry Andric Shamt = CurDAG->getTargetConstant(VC2, SDLoc(N), 211*979e22ffSDimitry Andric Shl.getOperand(1).getValueType()); 212*979e22ffSDimitry Andric return true; 213*979e22ffSDimitry Andric } 214*979e22ffSDimitry Andric } 215*979e22ffSDimitry Andric if (XLenVT == MVT::i32) { 216*979e22ffSDimitry Andric uint32_t VC1 = Or.getConstantOperandVal(1); 217*979e22ffSDimitry Andric uint32_t VC2 = Shl.getConstantOperandVal(1); 218*979e22ffSDimitry Andric if (VC1 == maskTrailingOnes<uint32_t>(VC2)) { 219*979e22ffSDimitry Andric RS1 = Shl.getOperand(0); 220*979e22ffSDimitry Andric Shamt = CurDAG->getTargetConstant(VC2, SDLoc(N), 221*979e22ffSDimitry Andric Shl.getOperand(1).getValueType()); 222*979e22ffSDimitry Andric return true; 223*979e22ffSDimitry Andric } 224*979e22ffSDimitry Andric } 225*979e22ffSDimitry Andric } 226*979e22ffSDimitry Andric } 227*979e22ffSDimitry Andric } 228*979e22ffSDimitry Andric return false; 229*979e22ffSDimitry Andric } 230*979e22ffSDimitry Andric 231*979e22ffSDimitry Andric // Check that it is a SROI (Shift Right Ones Immediate). We first check that 232*979e22ffSDimitry Andric // it is the right node tree: 233*979e22ffSDimitry Andric // 234*979e22ffSDimitry Andric // (OR (SRL RS1, VC2), VC1) 235*979e22ffSDimitry Andric // 236*979e22ffSDimitry Andric // and then we check that VC1, the mask used to fill with ones, is compatible 237*979e22ffSDimitry Andric // with VC2, the shamt: 238*979e22ffSDimitry Andric // 239*979e22ffSDimitry Andric // VC1 == maskLeadingOnes<uint64_t>(VC2) 240*979e22ffSDimitry Andric 241*979e22ffSDimitry Andric bool RISCVDAGToDAGISel::SelectSROI(SDValue N, SDValue &RS1, SDValue &Shamt) { 242*979e22ffSDimitry Andric MVT XLenVT = Subtarget->getXLenVT(); 243*979e22ffSDimitry Andric if (N.getOpcode() == ISD::OR) { 244*979e22ffSDimitry Andric SDValue Or = N; 245*979e22ffSDimitry Andric if (Or.getOperand(0).getOpcode() == ISD::SRL) { 246*979e22ffSDimitry Andric SDValue Srl = Or.getOperand(0); 247*979e22ffSDimitry Andric if (isa<ConstantSDNode>(Srl.getOperand(1)) && 248*979e22ffSDimitry Andric isa<ConstantSDNode>(Or.getOperand(1))) { 249*979e22ffSDimitry Andric if (XLenVT == MVT::i64) { 250*979e22ffSDimitry Andric uint64_t VC1 = Or.getConstantOperandVal(1); 251*979e22ffSDimitry Andric uint64_t VC2 = Srl.getConstantOperandVal(1); 252*979e22ffSDimitry Andric if (VC1 == maskLeadingOnes<uint64_t>(VC2)) { 253*979e22ffSDimitry Andric RS1 = Srl.getOperand(0); 254*979e22ffSDimitry Andric Shamt = CurDAG->getTargetConstant(VC2, SDLoc(N), 255*979e22ffSDimitry Andric Srl.getOperand(1).getValueType()); 256*979e22ffSDimitry Andric return true; 257*979e22ffSDimitry Andric } 258*979e22ffSDimitry Andric } 259*979e22ffSDimitry Andric if (XLenVT == MVT::i32) { 260*979e22ffSDimitry Andric uint32_t VC1 = Or.getConstantOperandVal(1); 261*979e22ffSDimitry Andric uint32_t VC2 = Srl.getConstantOperandVal(1); 262*979e22ffSDimitry Andric if (VC1 == maskLeadingOnes<uint32_t>(VC2)) { 263*979e22ffSDimitry Andric RS1 = Srl.getOperand(0); 264*979e22ffSDimitry Andric Shamt = CurDAG->getTargetConstant(VC2, SDLoc(N), 265*979e22ffSDimitry Andric Srl.getOperand(1).getValueType()); 266*979e22ffSDimitry Andric return true; 267*979e22ffSDimitry Andric } 268*979e22ffSDimitry Andric } 269*979e22ffSDimitry Andric } 270*979e22ffSDimitry Andric } 271*979e22ffSDimitry Andric } 272*979e22ffSDimitry Andric return false; 273*979e22ffSDimitry Andric } 274*979e22ffSDimitry Andric 275*979e22ffSDimitry Andric // Check that it is a RORI (Rotate Right Immediate). We first check that 276*979e22ffSDimitry Andric // it is the right node tree: 277*979e22ffSDimitry Andric // 278*979e22ffSDimitry Andric // (ROTL RS1, VC) 279*979e22ffSDimitry Andric // 280*979e22ffSDimitry Andric // The compiler translates immediate rotations to the right given by the call 281*979e22ffSDimitry Andric // to the rotateright32/rotateright64 intrinsics as rotations to the left. 282*979e22ffSDimitry Andric // Since the rotation to the left can be easily emulated as a rotation to the 283*979e22ffSDimitry Andric // right by negating the constant, there is no encoding for ROLI. 284*979e22ffSDimitry Andric // We then select the immediate left rotations as RORI by the complementary 285*979e22ffSDimitry Andric // constant: 286*979e22ffSDimitry Andric // 287*979e22ffSDimitry Andric // Shamt == XLen - VC 288*979e22ffSDimitry Andric 289*979e22ffSDimitry Andric bool RISCVDAGToDAGISel::SelectRORI(SDValue N, SDValue &RS1, SDValue &Shamt) { 290*979e22ffSDimitry Andric MVT XLenVT = Subtarget->getXLenVT(); 291*979e22ffSDimitry Andric if (N.getOpcode() == ISD::ROTL) { 292*979e22ffSDimitry Andric if (isa<ConstantSDNode>(N.getOperand(1))) { 293*979e22ffSDimitry Andric if (XLenVT == MVT::i64) { 294*979e22ffSDimitry Andric uint64_t VC = N.getConstantOperandVal(1); 295*979e22ffSDimitry Andric Shamt = CurDAG->getTargetConstant((64 - VC), SDLoc(N), 296*979e22ffSDimitry Andric N.getOperand(1).getValueType()); 297*979e22ffSDimitry Andric RS1 = N.getOperand(0); 298*979e22ffSDimitry Andric return true; 299*979e22ffSDimitry Andric } 300*979e22ffSDimitry Andric if (XLenVT == MVT::i32) { 301*979e22ffSDimitry Andric uint32_t VC = N.getConstantOperandVal(1); 302*979e22ffSDimitry Andric Shamt = CurDAG->getTargetConstant((32 - VC), SDLoc(N), 303*979e22ffSDimitry Andric N.getOperand(1).getValueType()); 304*979e22ffSDimitry Andric RS1 = N.getOperand(0); 305*979e22ffSDimitry Andric return true; 306*979e22ffSDimitry Andric } 307*979e22ffSDimitry Andric } 308*979e22ffSDimitry Andric } 309*979e22ffSDimitry Andric return false; 310*979e22ffSDimitry Andric } 311*979e22ffSDimitry Andric 312*979e22ffSDimitry Andric 313*979e22ffSDimitry Andric // Check that it is a SLLIUW (Shift Logical Left Immediate Unsigned i32 314*979e22ffSDimitry Andric // on RV64). 315*979e22ffSDimitry Andric // SLLIUW is the same as SLLI except for the fact that it clears the bits 316*979e22ffSDimitry Andric // XLEN-1:32 of the input RS1 before shifting. 317*979e22ffSDimitry Andric // We first check that it is the right node tree: 318*979e22ffSDimitry Andric // 319*979e22ffSDimitry Andric // (AND (SHL RS1, VC2), VC1) 320*979e22ffSDimitry Andric // 321*979e22ffSDimitry Andric // We check that VC2, the shamt is less than 32, otherwise the pattern is 322*979e22ffSDimitry Andric // exactly the same as SLLI and we give priority to that. 323*979e22ffSDimitry Andric // Eventually we check that that VC1, the mask used to clear the upper 32 bits 324*979e22ffSDimitry Andric // of RS1, is correct: 325*979e22ffSDimitry Andric // 326*979e22ffSDimitry Andric // VC1 == (0xFFFFFFFF << VC2) 327*979e22ffSDimitry Andric 328*979e22ffSDimitry Andric bool RISCVDAGToDAGISel::SelectSLLIUW(SDValue N, SDValue &RS1, SDValue &Shamt) { 329*979e22ffSDimitry Andric if (N.getOpcode() == ISD::AND && Subtarget->getXLenVT() == MVT::i64) { 330*979e22ffSDimitry Andric SDValue And = N; 331*979e22ffSDimitry Andric if (And.getOperand(0).getOpcode() == ISD::SHL) { 332*979e22ffSDimitry Andric SDValue Shl = And.getOperand(0); 333*979e22ffSDimitry Andric if (isa<ConstantSDNode>(Shl.getOperand(1)) && 334*979e22ffSDimitry Andric isa<ConstantSDNode>(And.getOperand(1))) { 335*979e22ffSDimitry Andric uint64_t VC1 = And.getConstantOperandVal(1); 336*979e22ffSDimitry Andric uint64_t VC2 = Shl.getConstantOperandVal(1); 337*979e22ffSDimitry Andric if (VC2 < 32 && VC1 == ((uint64_t)0xFFFFFFFF << VC2)) { 338*979e22ffSDimitry Andric RS1 = Shl.getOperand(0); 339*979e22ffSDimitry Andric Shamt = CurDAG->getTargetConstant(VC2, SDLoc(N), 340*979e22ffSDimitry Andric Shl.getOperand(1).getValueType()); 341*979e22ffSDimitry Andric return true; 342*979e22ffSDimitry Andric } 343*979e22ffSDimitry Andric } 344*979e22ffSDimitry Andric } 345*979e22ffSDimitry Andric } 346*979e22ffSDimitry Andric return false; 347*979e22ffSDimitry Andric } 348*979e22ffSDimitry Andric 349*979e22ffSDimitry Andric // Check that it is a SLOIW (Shift Left Ones Immediate i32 on RV64). 350*979e22ffSDimitry Andric // We first check that it is the right node tree: 351*979e22ffSDimitry Andric // 352*979e22ffSDimitry Andric // (SIGN_EXTEND_INREG (OR (SHL RS1, VC2), VC1)) 353*979e22ffSDimitry Andric // 354*979e22ffSDimitry Andric // and then we check that VC1, the mask used to fill with ones, is compatible 355*979e22ffSDimitry Andric // with VC2, the shamt: 356*979e22ffSDimitry Andric // 357*979e22ffSDimitry Andric // VC1 == maskTrailingOnes<uint32_t>(VC2) 358*979e22ffSDimitry Andric 359*979e22ffSDimitry Andric bool RISCVDAGToDAGISel::SelectSLOIW(SDValue N, SDValue &RS1, SDValue &Shamt) { 360*979e22ffSDimitry Andric if (Subtarget->getXLenVT() == MVT::i64 && 361*979e22ffSDimitry Andric N.getOpcode() == ISD::SIGN_EXTEND_INREG && 362*979e22ffSDimitry Andric cast<VTSDNode>(N.getOperand(1))->getVT() == MVT::i32) { 363*979e22ffSDimitry Andric if (N.getOperand(0).getOpcode() == ISD::OR) { 364*979e22ffSDimitry Andric SDValue Or = N.getOperand(0); 365*979e22ffSDimitry Andric if (Or.getOperand(0).getOpcode() == ISD::SHL) { 366*979e22ffSDimitry Andric SDValue Shl = Or.getOperand(0); 367*979e22ffSDimitry Andric if (isa<ConstantSDNode>(Shl.getOperand(1)) && 368*979e22ffSDimitry Andric isa<ConstantSDNode>(Or.getOperand(1))) { 369*979e22ffSDimitry Andric uint32_t VC1 = Or.getConstantOperandVal(1); 370*979e22ffSDimitry Andric uint32_t VC2 = Shl.getConstantOperandVal(1); 371*979e22ffSDimitry Andric if (VC1 == maskTrailingOnes<uint32_t>(VC2)) { 372*979e22ffSDimitry Andric RS1 = Shl.getOperand(0); 373*979e22ffSDimitry Andric Shamt = CurDAG->getTargetConstant(VC2, SDLoc(N), 374*979e22ffSDimitry Andric Shl.getOperand(1).getValueType()); 375*979e22ffSDimitry Andric return true; 376*979e22ffSDimitry Andric } 377*979e22ffSDimitry Andric } 378*979e22ffSDimitry Andric } 379*979e22ffSDimitry Andric } 380*979e22ffSDimitry Andric } 381*979e22ffSDimitry Andric return false; 382*979e22ffSDimitry Andric } 383*979e22ffSDimitry Andric 384*979e22ffSDimitry Andric // Check that it is a SROIW (Shift Right Ones Immediate i32 on RV64). 385*979e22ffSDimitry Andric // We first check that it is the right node tree: 386*979e22ffSDimitry Andric // 387*979e22ffSDimitry Andric // (OR (SHL RS1, VC2), VC1) 388*979e22ffSDimitry Andric // 389*979e22ffSDimitry Andric // and then we check that VC1, the mask used to fill with ones, is compatible 390*979e22ffSDimitry Andric // with VC2, the shamt: 391*979e22ffSDimitry Andric // 392*979e22ffSDimitry Andric // VC1 == maskLeadingOnes<uint32_t>(VC2) 393*979e22ffSDimitry Andric 394*979e22ffSDimitry Andric bool RISCVDAGToDAGISel::SelectSROIW(SDValue N, SDValue &RS1, SDValue &Shamt) { 395*979e22ffSDimitry Andric if (N.getOpcode() == ISD::OR && Subtarget->getXLenVT() == MVT::i64) { 396*979e22ffSDimitry Andric SDValue Or = N; 397*979e22ffSDimitry Andric if (Or.getOperand(0).getOpcode() == ISD::SRL) { 398*979e22ffSDimitry Andric SDValue Srl = Or.getOperand(0); 399*979e22ffSDimitry Andric if (isa<ConstantSDNode>(Srl.getOperand(1)) && 400*979e22ffSDimitry Andric isa<ConstantSDNode>(Or.getOperand(1))) { 401*979e22ffSDimitry Andric uint32_t VC1 = Or.getConstantOperandVal(1); 402*979e22ffSDimitry Andric uint32_t VC2 = Srl.getConstantOperandVal(1); 403*979e22ffSDimitry Andric if (VC1 == maskLeadingOnes<uint32_t>(VC2)) { 404*979e22ffSDimitry Andric RS1 = Srl.getOperand(0); 405*979e22ffSDimitry Andric Shamt = CurDAG->getTargetConstant(VC2, SDLoc(N), 406*979e22ffSDimitry Andric Srl.getOperand(1).getValueType()); 407*979e22ffSDimitry Andric return true; 408*979e22ffSDimitry Andric } 409*979e22ffSDimitry Andric } 410*979e22ffSDimitry Andric } 411*979e22ffSDimitry Andric } 412*979e22ffSDimitry Andric return false; 413*979e22ffSDimitry Andric } 414*979e22ffSDimitry Andric 415*979e22ffSDimitry Andric // Check that it is a RORIW (i32 Right Rotate Immediate on RV64). 416*979e22ffSDimitry Andric // We first check that it is the right node tree: 417*979e22ffSDimitry Andric // 418*979e22ffSDimitry Andric // (SIGN_EXTEND_INREG (OR (SHL (AsserSext RS1, i32), VC2), 419*979e22ffSDimitry Andric // (SRL (AND (AssertSext RS2, i32), VC3), VC1))) 420*979e22ffSDimitry Andric // 421*979e22ffSDimitry Andric // Then we check that the constant operands respect these constraints: 422*979e22ffSDimitry Andric // 423*979e22ffSDimitry Andric // VC2 == 32 - VC1 424*979e22ffSDimitry Andric // VC3 == maskLeadingOnes<uint32_t>(VC2) 425*979e22ffSDimitry Andric // 426*979e22ffSDimitry Andric // being VC1 the Shamt we need, VC2 the complementary of Shamt over 32 427*979e22ffSDimitry Andric // and VC3 a 32 bit mask of (32 - VC1) leading ones. 428*979e22ffSDimitry Andric 429*979e22ffSDimitry Andric bool RISCVDAGToDAGISel::SelectRORIW(SDValue N, SDValue &RS1, SDValue &Shamt) { 430*979e22ffSDimitry Andric if (N.getOpcode() == ISD::SIGN_EXTEND_INREG && 431*979e22ffSDimitry Andric Subtarget->getXLenVT() == MVT::i64 && 432*979e22ffSDimitry Andric cast<VTSDNode>(N.getOperand(1))->getVT() == MVT::i32) { 433*979e22ffSDimitry Andric if (N.getOperand(0).getOpcode() == ISD::OR) { 434*979e22ffSDimitry Andric SDValue Or = N.getOperand(0); 435*979e22ffSDimitry Andric if (Or.getOperand(0).getOpcode() == ISD::SHL && 436*979e22ffSDimitry Andric Or.getOperand(1).getOpcode() == ISD::SRL) { 437*979e22ffSDimitry Andric SDValue Shl = Or.getOperand(0); 438*979e22ffSDimitry Andric SDValue Srl = Or.getOperand(1); 439*979e22ffSDimitry Andric if (Srl.getOperand(0).getOpcode() == ISD::AND) { 440*979e22ffSDimitry Andric SDValue And = Srl.getOperand(0); 441*979e22ffSDimitry Andric if (isa<ConstantSDNode>(Srl.getOperand(1)) && 442*979e22ffSDimitry Andric isa<ConstantSDNode>(Shl.getOperand(1)) && 443*979e22ffSDimitry Andric isa<ConstantSDNode>(And.getOperand(1))) { 444*979e22ffSDimitry Andric uint32_t VC1 = Srl.getConstantOperandVal(1); 445*979e22ffSDimitry Andric uint32_t VC2 = Shl.getConstantOperandVal(1); 446*979e22ffSDimitry Andric uint32_t VC3 = And.getConstantOperandVal(1); 447*979e22ffSDimitry Andric if (VC2 == (32 - VC1) && 448*979e22ffSDimitry Andric VC3 == maskLeadingOnes<uint32_t>(VC2)) { 449*979e22ffSDimitry Andric RS1 = Shl.getOperand(0); 450*979e22ffSDimitry Andric Shamt = CurDAG->getTargetConstant(VC1, SDLoc(N), 451*979e22ffSDimitry Andric Srl.getOperand(1).getValueType()); 452*979e22ffSDimitry Andric return true; 453*979e22ffSDimitry Andric } 454*979e22ffSDimitry Andric } 455*979e22ffSDimitry Andric } 456*979e22ffSDimitry Andric } 457*979e22ffSDimitry Andric } 458*979e22ffSDimitry Andric } 459*979e22ffSDimitry Andric return false; 460*979e22ffSDimitry Andric } 461*979e22ffSDimitry Andric 462*979e22ffSDimitry Andric // Check that it is a FSRIW (i32 Funnel Shift Right Immediate on RV64). 463*979e22ffSDimitry Andric // We first check that it is the right node tree: 464*979e22ffSDimitry Andric // 465*979e22ffSDimitry Andric // (SIGN_EXTEND_INREG (OR (SHL (AsserSext RS1, i32), VC2), 466*979e22ffSDimitry Andric // (SRL (AND (AssertSext RS2, i32), VC3), VC1))) 467*979e22ffSDimitry Andric // 468*979e22ffSDimitry Andric // Then we check that the constant operands respect these constraints: 469*979e22ffSDimitry Andric // 470*979e22ffSDimitry Andric // VC2 == 32 - VC1 471*979e22ffSDimitry Andric // VC3 == maskLeadingOnes<uint32_t>(VC2) 472*979e22ffSDimitry Andric // 473*979e22ffSDimitry Andric // being VC1 the Shamt we need, VC2 the complementary of Shamt over 32 474*979e22ffSDimitry Andric // and VC3 a 32 bit mask of (32 - VC1) leading ones. 475*979e22ffSDimitry Andric 476*979e22ffSDimitry Andric bool RISCVDAGToDAGISel::SelectFSRIW(SDValue N, SDValue &RS1, SDValue &RS2, 477*979e22ffSDimitry Andric SDValue &Shamt) { 478*979e22ffSDimitry Andric if (N.getOpcode() == ISD::SIGN_EXTEND_INREG && 479*979e22ffSDimitry Andric Subtarget->getXLenVT() == MVT::i64 && 480*979e22ffSDimitry Andric cast<VTSDNode>(N.getOperand(1))->getVT() == MVT::i32) { 481*979e22ffSDimitry Andric if (N.getOperand(0).getOpcode() == ISD::OR) { 482*979e22ffSDimitry Andric SDValue Or = N.getOperand(0); 483*979e22ffSDimitry Andric if (Or.getOperand(0).getOpcode() == ISD::SHL && 484*979e22ffSDimitry Andric Or.getOperand(1).getOpcode() == ISD::SRL) { 485*979e22ffSDimitry Andric SDValue Shl = Or.getOperand(0); 486*979e22ffSDimitry Andric SDValue Srl = Or.getOperand(1); 487*979e22ffSDimitry Andric if (Srl.getOperand(0).getOpcode() == ISD::AND) { 488*979e22ffSDimitry Andric SDValue And = Srl.getOperand(0); 489*979e22ffSDimitry Andric if (isa<ConstantSDNode>(Srl.getOperand(1)) && 490*979e22ffSDimitry Andric isa<ConstantSDNode>(Shl.getOperand(1)) && 491*979e22ffSDimitry Andric isa<ConstantSDNode>(And.getOperand(1))) { 492*979e22ffSDimitry Andric uint32_t VC1 = Srl.getConstantOperandVal(1); 493*979e22ffSDimitry Andric uint32_t VC2 = Shl.getConstantOperandVal(1); 494*979e22ffSDimitry Andric uint32_t VC3 = And.getConstantOperandVal(1); 495*979e22ffSDimitry Andric if (VC2 == (32 - VC1) && 496*979e22ffSDimitry Andric VC3 == maskLeadingOnes<uint32_t>(VC2)) { 497*979e22ffSDimitry Andric RS1 = Shl.getOperand(0); 498*979e22ffSDimitry Andric RS2 = And.getOperand(0); 499*979e22ffSDimitry Andric Shamt = CurDAG->getTargetConstant(VC1, SDLoc(N), 500*979e22ffSDimitry Andric Srl.getOperand(1).getValueType()); 501*979e22ffSDimitry Andric return true; 502*979e22ffSDimitry Andric } 503*979e22ffSDimitry Andric } 504*979e22ffSDimitry Andric } 505*979e22ffSDimitry Andric } 506*979e22ffSDimitry Andric } 507*979e22ffSDimitry Andric } 508*979e22ffSDimitry Andric return false; 509*979e22ffSDimitry Andric } 510*979e22ffSDimitry Andric 5110b57cec5SDimitry Andric // Merge an ADDI into the offset of a load/store instruction where possible. 5125ffd83dbSDimitry Andric // (load (addi base, off1), off2) -> (load base, off1+off2) 5135ffd83dbSDimitry Andric // (store val, (addi base, off1), off2) -> (store val, base, off1+off2) 5145ffd83dbSDimitry Andric // This is possible when off1+off2 fits a 12-bit immediate. 5150b57cec5SDimitry Andric void RISCVDAGToDAGISel::doPeepholeLoadStoreADDI() { 5160b57cec5SDimitry Andric SelectionDAG::allnodes_iterator Position(CurDAG->getRoot().getNode()); 5170b57cec5SDimitry Andric ++Position; 5180b57cec5SDimitry Andric 5190b57cec5SDimitry Andric while (Position != CurDAG->allnodes_begin()) { 5200b57cec5SDimitry Andric SDNode *N = &*--Position; 5210b57cec5SDimitry Andric // Skip dead nodes and any non-machine opcodes. 5220b57cec5SDimitry Andric if (N->use_empty() || !N->isMachineOpcode()) 5230b57cec5SDimitry Andric continue; 5240b57cec5SDimitry Andric 5250b57cec5SDimitry Andric int OffsetOpIdx; 5260b57cec5SDimitry Andric int BaseOpIdx; 5270b57cec5SDimitry Andric 5280b57cec5SDimitry Andric // Only attempt this optimisation for I-type loads and S-type stores. 5290b57cec5SDimitry Andric switch (N->getMachineOpcode()) { 5300b57cec5SDimitry Andric default: 5310b57cec5SDimitry Andric continue; 5320b57cec5SDimitry Andric case RISCV::LB: 5330b57cec5SDimitry Andric case RISCV::LH: 5340b57cec5SDimitry Andric case RISCV::LW: 5350b57cec5SDimitry Andric case RISCV::LBU: 5360b57cec5SDimitry Andric case RISCV::LHU: 5370b57cec5SDimitry Andric case RISCV::LWU: 5380b57cec5SDimitry Andric case RISCV::LD: 5390b57cec5SDimitry Andric case RISCV::FLW: 5400b57cec5SDimitry Andric case RISCV::FLD: 5410b57cec5SDimitry Andric BaseOpIdx = 0; 5420b57cec5SDimitry Andric OffsetOpIdx = 1; 5430b57cec5SDimitry Andric break; 5440b57cec5SDimitry Andric case RISCV::SB: 5450b57cec5SDimitry Andric case RISCV::SH: 5460b57cec5SDimitry Andric case RISCV::SW: 5470b57cec5SDimitry Andric case RISCV::SD: 5480b57cec5SDimitry Andric case RISCV::FSW: 5490b57cec5SDimitry Andric case RISCV::FSD: 5500b57cec5SDimitry Andric BaseOpIdx = 1; 5510b57cec5SDimitry Andric OffsetOpIdx = 2; 5520b57cec5SDimitry Andric break; 5530b57cec5SDimitry Andric } 5540b57cec5SDimitry Andric 5555ffd83dbSDimitry Andric if (!isa<ConstantSDNode>(N->getOperand(OffsetOpIdx))) 5560b57cec5SDimitry Andric continue; 5570b57cec5SDimitry Andric 5580b57cec5SDimitry Andric SDValue Base = N->getOperand(BaseOpIdx); 5590b57cec5SDimitry Andric 5600b57cec5SDimitry Andric // If the base is an ADDI, we can merge it in to the load/store. 5610b57cec5SDimitry Andric if (!Base.isMachineOpcode() || Base.getMachineOpcode() != RISCV::ADDI) 5620b57cec5SDimitry Andric continue; 5630b57cec5SDimitry Andric 5640b57cec5SDimitry Andric SDValue ImmOperand = Base.getOperand(1); 5655ffd83dbSDimitry Andric uint64_t Offset2 = N->getConstantOperandVal(OffsetOpIdx); 5660b57cec5SDimitry Andric 5670b57cec5SDimitry Andric if (auto Const = dyn_cast<ConstantSDNode>(ImmOperand)) { 5685ffd83dbSDimitry Andric int64_t Offset1 = Const->getSExtValue(); 5695ffd83dbSDimitry Andric int64_t CombinedOffset = Offset1 + Offset2; 5705ffd83dbSDimitry Andric if (!isInt<12>(CombinedOffset)) 5715ffd83dbSDimitry Andric continue; 5725ffd83dbSDimitry Andric ImmOperand = CurDAG->getTargetConstant(CombinedOffset, SDLoc(ImmOperand), 5735ffd83dbSDimitry Andric ImmOperand.getValueType()); 5740b57cec5SDimitry Andric } else if (auto GA = dyn_cast<GlobalAddressSDNode>(ImmOperand)) { 5755ffd83dbSDimitry Andric // If the off1 in (addi base, off1) is a global variable's address (its 5765ffd83dbSDimitry Andric // low part, really), then we can rely on the alignment of that variable 5775ffd83dbSDimitry Andric // to provide a margin of safety before off1 can overflow the 12 bits. 5785ffd83dbSDimitry Andric // Check if off2 falls within that margin; if so off1+off2 can't overflow. 5795ffd83dbSDimitry Andric const DataLayout &DL = CurDAG->getDataLayout(); 5805ffd83dbSDimitry Andric Align Alignment = GA->getGlobal()->getPointerAlignment(DL); 5815ffd83dbSDimitry Andric if (Offset2 != 0 && Alignment <= Offset2) 5825ffd83dbSDimitry Andric continue; 5835ffd83dbSDimitry Andric int64_t Offset1 = GA->getOffset(); 5845ffd83dbSDimitry Andric int64_t CombinedOffset = Offset1 + Offset2; 5850b57cec5SDimitry Andric ImmOperand = CurDAG->getTargetGlobalAddress( 5860b57cec5SDimitry Andric GA->getGlobal(), SDLoc(ImmOperand), ImmOperand.getValueType(), 5875ffd83dbSDimitry Andric CombinedOffset, GA->getTargetFlags()); 5885ffd83dbSDimitry Andric } else if (auto CP = dyn_cast<ConstantPoolSDNode>(ImmOperand)) { 5895ffd83dbSDimitry Andric // Ditto. 5905ffd83dbSDimitry Andric Align Alignment = CP->getAlign(); 5915ffd83dbSDimitry Andric if (Offset2 != 0 && Alignment <= Offset2) 5925ffd83dbSDimitry Andric continue; 5935ffd83dbSDimitry Andric int64_t Offset1 = CP->getOffset(); 5945ffd83dbSDimitry Andric int64_t CombinedOffset = Offset1 + Offset2; 5955ffd83dbSDimitry Andric ImmOperand = CurDAG->getTargetConstantPool( 5965ffd83dbSDimitry Andric CP->getConstVal(), ImmOperand.getValueType(), CP->getAlign(), 5975ffd83dbSDimitry Andric CombinedOffset, CP->getTargetFlags()); 5980b57cec5SDimitry Andric } else { 5990b57cec5SDimitry Andric continue; 6000b57cec5SDimitry Andric } 6010b57cec5SDimitry Andric 6020b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Folding add-immediate into mem-op:\nBase: "); 6030b57cec5SDimitry Andric LLVM_DEBUG(Base->dump(CurDAG)); 6040b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "\nN: "); 6050b57cec5SDimitry Andric LLVM_DEBUG(N->dump(CurDAG)); 6060b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "\n"); 6070b57cec5SDimitry Andric 6080b57cec5SDimitry Andric // Modify the offset operand of the load/store. 6090b57cec5SDimitry Andric if (BaseOpIdx == 0) // Load 6100b57cec5SDimitry Andric CurDAG->UpdateNodeOperands(N, Base.getOperand(0), ImmOperand, 6110b57cec5SDimitry Andric N->getOperand(2)); 6120b57cec5SDimitry Andric else // Store 6130b57cec5SDimitry Andric CurDAG->UpdateNodeOperands(N, N->getOperand(0), Base.getOperand(0), 6140b57cec5SDimitry Andric ImmOperand, N->getOperand(3)); 6150b57cec5SDimitry Andric 6160b57cec5SDimitry Andric // The add-immediate may now be dead, in which case remove it. 6170b57cec5SDimitry Andric if (Base.getNode()->use_empty()) 6180b57cec5SDimitry Andric CurDAG->RemoveDeadNode(Base.getNode()); 6190b57cec5SDimitry Andric } 6200b57cec5SDimitry Andric } 6210b57cec5SDimitry Andric 6220b57cec5SDimitry Andric // This pass converts a legalized DAG into a RISCV-specific DAG, ready 6230b57cec5SDimitry Andric // for instruction scheduling. 6240b57cec5SDimitry Andric FunctionPass *llvm::createRISCVISelDag(RISCVTargetMachine &TM) { 6250b57cec5SDimitry Andric return new RISCVDAGToDAGISel(TM); 6260b57cec5SDimitry Andric } 627