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" 15e8d8bef9SDimitry Andric #include "MCTargetDesc/RISCVMatInt.h" 160b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h" 17e8d8bef9SDimitry Andric #include "llvm/IR/IntrinsicsRISCV.h" 185ffd83dbSDimitry Andric #include "llvm/Support/Alignment.h" 190b57cec5SDimitry Andric #include "llvm/Support/Debug.h" 200b57cec5SDimitry Andric #include "llvm/Support/MathExtras.h" 210b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 225ffd83dbSDimitry Andric 230b57cec5SDimitry Andric using namespace llvm; 240b57cec5SDimitry Andric 250b57cec5SDimitry Andric #define DEBUG_TYPE "riscv-isel" 260b57cec5SDimitry Andric 270b57cec5SDimitry Andric void RISCVDAGToDAGISel::PostprocessISelDAG() { 280b57cec5SDimitry Andric doPeepholeLoadStoreADDI(); 290b57cec5SDimitry Andric } 300b57cec5SDimitry Andric 310b57cec5SDimitry Andric static SDNode *selectImm(SelectionDAG *CurDAG, const SDLoc &DL, int64_t Imm, 320b57cec5SDimitry Andric MVT XLenVT) { 330b57cec5SDimitry Andric RISCVMatInt::InstSeq Seq; 340b57cec5SDimitry Andric RISCVMatInt::generateInstSeq(Imm, XLenVT == MVT::i64, Seq); 350b57cec5SDimitry Andric 368bcb0991SDimitry Andric SDNode *Result = nullptr; 370b57cec5SDimitry Andric SDValue SrcReg = CurDAG->getRegister(RISCV::X0, XLenVT); 380b57cec5SDimitry Andric for (RISCVMatInt::Inst &Inst : Seq) { 390b57cec5SDimitry Andric SDValue SDImm = CurDAG->getTargetConstant(Inst.Imm, DL, XLenVT); 400b57cec5SDimitry Andric if (Inst.Opc == RISCV::LUI) 410b57cec5SDimitry Andric Result = CurDAG->getMachineNode(RISCV::LUI, DL, XLenVT, SDImm); 420b57cec5SDimitry Andric else 430b57cec5SDimitry Andric Result = CurDAG->getMachineNode(Inst.Opc, DL, XLenVT, SrcReg, SDImm); 440b57cec5SDimitry Andric 450b57cec5SDimitry Andric // Only the first instruction has X0 as its source. 460b57cec5SDimitry Andric SrcReg = SDValue(Result, 0); 470b57cec5SDimitry Andric } 480b57cec5SDimitry Andric 490b57cec5SDimitry Andric return Result; 500b57cec5SDimitry Andric } 510b57cec5SDimitry Andric 52e8d8bef9SDimitry Andric static RISCVVLMUL getLMUL(EVT VT) { 53e8d8bef9SDimitry Andric switch (VT.getSizeInBits().getKnownMinValue() / 8) { 54e8d8bef9SDimitry Andric default: 55e8d8bef9SDimitry Andric llvm_unreachable("Invalid LMUL."); 56e8d8bef9SDimitry Andric case 1: 57e8d8bef9SDimitry Andric return RISCVVLMUL::LMUL_F8; 58e8d8bef9SDimitry Andric case 2: 59e8d8bef9SDimitry Andric return RISCVVLMUL::LMUL_F4; 60e8d8bef9SDimitry Andric case 4: 61e8d8bef9SDimitry Andric return RISCVVLMUL::LMUL_F2; 62e8d8bef9SDimitry Andric case 8: 63e8d8bef9SDimitry Andric return RISCVVLMUL::LMUL_1; 64e8d8bef9SDimitry Andric case 16: 65e8d8bef9SDimitry Andric return RISCVVLMUL::LMUL_2; 66e8d8bef9SDimitry Andric case 32: 67e8d8bef9SDimitry Andric return RISCVVLMUL::LMUL_4; 68e8d8bef9SDimitry Andric case 64: 69e8d8bef9SDimitry Andric return RISCVVLMUL::LMUL_8; 700b57cec5SDimitry Andric } 71e8d8bef9SDimitry Andric } 72e8d8bef9SDimitry Andric 73e8d8bef9SDimitry Andric static unsigned getSubregIndexByEVT(EVT VT, unsigned Index) { 74e8d8bef9SDimitry Andric RISCVVLMUL LMUL = getLMUL(VT); 75e8d8bef9SDimitry Andric if (LMUL == RISCVVLMUL::LMUL_F8 || LMUL == RISCVVLMUL::LMUL_F4 || 76e8d8bef9SDimitry Andric LMUL == RISCVVLMUL::LMUL_F2 || LMUL == RISCVVLMUL::LMUL_1) { 77e8d8bef9SDimitry Andric static_assert(RISCV::sub_vrm1_7 == RISCV::sub_vrm1_0 + 7, 78e8d8bef9SDimitry Andric "Unexpected subreg numbering"); 79e8d8bef9SDimitry Andric return RISCV::sub_vrm1_0 + Index; 80e8d8bef9SDimitry Andric } else if (LMUL == RISCVVLMUL::LMUL_2) { 81e8d8bef9SDimitry Andric static_assert(RISCV::sub_vrm2_3 == RISCV::sub_vrm2_0 + 3, 82e8d8bef9SDimitry Andric "Unexpected subreg numbering"); 83e8d8bef9SDimitry Andric return RISCV::sub_vrm2_0 + Index; 84e8d8bef9SDimitry Andric } else if (LMUL == RISCVVLMUL::LMUL_4) { 85e8d8bef9SDimitry Andric static_assert(RISCV::sub_vrm4_1 == RISCV::sub_vrm4_0 + 1, 86e8d8bef9SDimitry Andric "Unexpected subreg numbering"); 87e8d8bef9SDimitry Andric return RISCV::sub_vrm4_0 + Index; 88e8d8bef9SDimitry Andric } 89e8d8bef9SDimitry Andric llvm_unreachable("Invalid vector type."); 90e8d8bef9SDimitry Andric } 91e8d8bef9SDimitry Andric 92e8d8bef9SDimitry Andric static SDValue createTupleImpl(SelectionDAG &CurDAG, ArrayRef<SDValue> Regs, 93e8d8bef9SDimitry Andric unsigned RegClassID, unsigned SubReg0) { 94e8d8bef9SDimitry Andric assert(Regs.size() >= 2 && Regs.size() <= 8); 95e8d8bef9SDimitry Andric 96e8d8bef9SDimitry Andric SDLoc DL(Regs[0]); 97e8d8bef9SDimitry Andric SmallVector<SDValue, 8> Ops; 98e8d8bef9SDimitry Andric 99e8d8bef9SDimitry Andric Ops.push_back(CurDAG.getTargetConstant(RegClassID, DL, MVT::i32)); 100e8d8bef9SDimitry Andric 101e8d8bef9SDimitry Andric for (unsigned I = 0; I < Regs.size(); ++I) { 102e8d8bef9SDimitry Andric Ops.push_back(Regs[I]); 103e8d8bef9SDimitry Andric Ops.push_back(CurDAG.getTargetConstant(SubReg0 + I, DL, MVT::i32)); 104e8d8bef9SDimitry Andric } 105e8d8bef9SDimitry Andric SDNode *N = 106e8d8bef9SDimitry Andric CurDAG.getMachineNode(TargetOpcode::REG_SEQUENCE, DL, MVT::Untyped, Ops); 107e8d8bef9SDimitry Andric return SDValue(N, 0); 108e8d8bef9SDimitry Andric } 109e8d8bef9SDimitry Andric 110e8d8bef9SDimitry Andric static SDValue createM1Tuple(SelectionDAG &CurDAG, ArrayRef<SDValue> Regs, 111e8d8bef9SDimitry Andric unsigned NF) { 112e8d8bef9SDimitry Andric static const unsigned RegClassIDs[] = { 113e8d8bef9SDimitry Andric RISCV::VRN2M1RegClassID, RISCV::VRN3M1RegClassID, RISCV::VRN4M1RegClassID, 114e8d8bef9SDimitry Andric RISCV::VRN5M1RegClassID, RISCV::VRN6M1RegClassID, RISCV::VRN7M1RegClassID, 115e8d8bef9SDimitry Andric RISCV::VRN8M1RegClassID}; 116e8d8bef9SDimitry Andric 117e8d8bef9SDimitry Andric return createTupleImpl(CurDAG, Regs, RegClassIDs[NF - 2], RISCV::sub_vrm1_0); 118e8d8bef9SDimitry Andric } 119e8d8bef9SDimitry Andric 120e8d8bef9SDimitry Andric static SDValue createM2Tuple(SelectionDAG &CurDAG, ArrayRef<SDValue> Regs, 121e8d8bef9SDimitry Andric unsigned NF) { 122e8d8bef9SDimitry Andric static const unsigned RegClassIDs[] = {RISCV::VRN2M2RegClassID, 123e8d8bef9SDimitry Andric RISCV::VRN3M2RegClassID, 124e8d8bef9SDimitry Andric RISCV::VRN4M2RegClassID}; 125e8d8bef9SDimitry Andric 126e8d8bef9SDimitry Andric return createTupleImpl(CurDAG, Regs, RegClassIDs[NF - 2], RISCV::sub_vrm2_0); 127e8d8bef9SDimitry Andric } 128e8d8bef9SDimitry Andric 129e8d8bef9SDimitry Andric static SDValue createM4Tuple(SelectionDAG &CurDAG, ArrayRef<SDValue> Regs, 130e8d8bef9SDimitry Andric unsigned NF) { 131e8d8bef9SDimitry Andric return createTupleImpl(CurDAG, Regs, RISCV::VRN2M4RegClassID, 132e8d8bef9SDimitry Andric RISCV::sub_vrm4_0); 133e8d8bef9SDimitry Andric } 134e8d8bef9SDimitry Andric 135e8d8bef9SDimitry Andric static SDValue createTuple(SelectionDAG &CurDAG, ArrayRef<SDValue> Regs, 136e8d8bef9SDimitry Andric unsigned NF, RISCVVLMUL LMUL) { 137e8d8bef9SDimitry Andric switch (LMUL) { 138e8d8bef9SDimitry Andric default: 139e8d8bef9SDimitry Andric llvm_unreachable("Invalid LMUL."); 140e8d8bef9SDimitry Andric case RISCVVLMUL::LMUL_F8: 141e8d8bef9SDimitry Andric case RISCVVLMUL::LMUL_F4: 142e8d8bef9SDimitry Andric case RISCVVLMUL::LMUL_F2: 143e8d8bef9SDimitry Andric case RISCVVLMUL::LMUL_1: 144e8d8bef9SDimitry Andric return createM1Tuple(CurDAG, Regs, NF); 145e8d8bef9SDimitry Andric case RISCVVLMUL::LMUL_2: 146e8d8bef9SDimitry Andric return createM2Tuple(CurDAG, Regs, NF); 147e8d8bef9SDimitry Andric case RISCVVLMUL::LMUL_4: 148e8d8bef9SDimitry Andric return createM4Tuple(CurDAG, Regs, NF); 149e8d8bef9SDimitry Andric } 150e8d8bef9SDimitry Andric } 151e8d8bef9SDimitry Andric 152e8d8bef9SDimitry Andric void RISCVDAGToDAGISel::selectVLSEG(SDNode *Node, unsigned IntNo, 153e8d8bef9SDimitry Andric bool IsStrided) { 154e8d8bef9SDimitry Andric SDLoc DL(Node); 155e8d8bef9SDimitry Andric unsigned NF = Node->getNumValues() - 1; 156e8d8bef9SDimitry Andric EVT VT = Node->getValueType(0); 157e8d8bef9SDimitry Andric unsigned ScalarSize = VT.getScalarSizeInBits(); 158e8d8bef9SDimitry Andric MVT XLenVT = Subtarget->getXLenVT(); 159e8d8bef9SDimitry Andric RISCVVLMUL LMUL = getLMUL(VT); 160e8d8bef9SDimitry Andric SDValue SEW = CurDAG->getTargetConstant(ScalarSize, DL, XLenVT); 161e8d8bef9SDimitry Andric SmallVector<SDValue, 5> Operands; 162e8d8bef9SDimitry Andric Operands.push_back(Node->getOperand(2)); // Base pointer. 163e8d8bef9SDimitry Andric if (IsStrided) { 164e8d8bef9SDimitry Andric Operands.push_back(Node->getOperand(3)); // Stride. 165e8d8bef9SDimitry Andric Operands.push_back(Node->getOperand(4)); // VL. 166e8d8bef9SDimitry Andric } else { 167e8d8bef9SDimitry Andric Operands.push_back(Node->getOperand(3)); // VL. 168e8d8bef9SDimitry Andric } 169e8d8bef9SDimitry Andric Operands.push_back(SEW); 170e8d8bef9SDimitry Andric Operands.push_back(Node->getOperand(0)); // Chain. 171e8d8bef9SDimitry Andric const RISCVZvlssegTable::RISCVZvlsseg *P = RISCVZvlssegTable::getPseudo( 172e8d8bef9SDimitry Andric IntNo, ScalarSize, static_cast<unsigned>(LMUL), 173e8d8bef9SDimitry Andric static_cast<unsigned>(RISCVVLMUL::LMUL_1)); 174e8d8bef9SDimitry Andric SDNode *Load = 175e8d8bef9SDimitry Andric CurDAG->getMachineNode(P->Pseudo, DL, MVT::Untyped, MVT::Other, Operands); 176e8d8bef9SDimitry Andric SDValue SuperReg = SDValue(Load, 0); 177e8d8bef9SDimitry Andric for (unsigned I = 0; I < NF; ++I) 178e8d8bef9SDimitry Andric ReplaceUses(SDValue(Node, I), 179e8d8bef9SDimitry Andric CurDAG->getTargetExtractSubreg(getSubregIndexByEVT(VT, I), DL, 180e8d8bef9SDimitry Andric VT, SuperReg)); 181e8d8bef9SDimitry Andric 182e8d8bef9SDimitry Andric ReplaceUses(SDValue(Node, NF), SDValue(Load, 1)); 183e8d8bef9SDimitry Andric CurDAG->RemoveDeadNode(Node); 184e8d8bef9SDimitry Andric } 185e8d8bef9SDimitry Andric 186e8d8bef9SDimitry Andric void RISCVDAGToDAGISel::selectVLSEGMask(SDNode *Node, unsigned IntNo, 187e8d8bef9SDimitry Andric bool IsStrided) { 188e8d8bef9SDimitry Andric SDLoc DL(Node); 189e8d8bef9SDimitry Andric unsigned NF = Node->getNumValues() - 1; 190e8d8bef9SDimitry Andric EVT VT = Node->getValueType(0); 191e8d8bef9SDimitry Andric unsigned ScalarSize = VT.getScalarSizeInBits(); 192e8d8bef9SDimitry Andric MVT XLenVT = Subtarget->getXLenVT(); 193e8d8bef9SDimitry Andric RISCVVLMUL LMUL = getLMUL(VT); 194e8d8bef9SDimitry Andric SDValue SEW = CurDAG->getTargetConstant(ScalarSize, DL, XLenVT); 195e8d8bef9SDimitry Andric SmallVector<SDValue, 8> Regs(Node->op_begin() + 2, Node->op_begin() + 2 + NF); 196e8d8bef9SDimitry Andric SDValue MaskedOff = createTuple(*CurDAG, Regs, NF, LMUL); 197e8d8bef9SDimitry Andric SmallVector<SDValue, 7> Operands; 198e8d8bef9SDimitry Andric Operands.push_back(MaskedOff); 199e8d8bef9SDimitry Andric Operands.push_back(Node->getOperand(NF + 2)); // Base pointer. 200e8d8bef9SDimitry Andric if (IsStrided) { 201e8d8bef9SDimitry Andric Operands.push_back(Node->getOperand(NF + 3)); // Stride. 202e8d8bef9SDimitry Andric Operands.push_back(Node->getOperand(NF + 4)); // Mask. 203e8d8bef9SDimitry Andric Operands.push_back(Node->getOperand(NF + 5)); // VL. 204e8d8bef9SDimitry Andric } else { 205e8d8bef9SDimitry Andric Operands.push_back(Node->getOperand(NF + 3)); // Mask. 206e8d8bef9SDimitry Andric Operands.push_back(Node->getOperand(NF + 4)); // VL. 207e8d8bef9SDimitry Andric } 208e8d8bef9SDimitry Andric Operands.push_back(SEW); 209e8d8bef9SDimitry Andric Operands.push_back(Node->getOperand(0)); /// Chain. 210e8d8bef9SDimitry Andric const RISCVZvlssegTable::RISCVZvlsseg *P = RISCVZvlssegTable::getPseudo( 211e8d8bef9SDimitry Andric IntNo, ScalarSize, static_cast<unsigned>(LMUL), 212e8d8bef9SDimitry Andric static_cast<unsigned>(RISCVVLMUL::LMUL_1)); 213e8d8bef9SDimitry Andric SDNode *Load = 214e8d8bef9SDimitry Andric CurDAG->getMachineNode(P->Pseudo, DL, MVT::Untyped, MVT::Other, Operands); 215e8d8bef9SDimitry Andric SDValue SuperReg = SDValue(Load, 0); 216e8d8bef9SDimitry Andric for (unsigned I = 0; I < NF; ++I) 217e8d8bef9SDimitry Andric ReplaceUses(SDValue(Node, I), 218e8d8bef9SDimitry Andric CurDAG->getTargetExtractSubreg(getSubregIndexByEVT(VT, I), DL, 219e8d8bef9SDimitry Andric VT, SuperReg)); 220e8d8bef9SDimitry Andric 221e8d8bef9SDimitry Andric ReplaceUses(SDValue(Node, NF), SDValue(Load, 1)); 222e8d8bef9SDimitry Andric CurDAG->RemoveDeadNode(Node); 223e8d8bef9SDimitry Andric } 224e8d8bef9SDimitry Andric 225e8d8bef9SDimitry Andric void RISCVDAGToDAGISel::selectVLSEGFF(SDNode *Node) { 226e8d8bef9SDimitry Andric SDLoc DL(Node); 227e8d8bef9SDimitry Andric unsigned IntNo = cast<ConstantSDNode>(Node->getOperand(1))->getZExtValue(); 228e8d8bef9SDimitry Andric unsigned NF = Node->getNumValues() - 2; // Do not count Chain and Glue. 229e8d8bef9SDimitry Andric EVT VT = Node->getValueType(0); 230e8d8bef9SDimitry Andric unsigned ScalarSize = VT.getScalarSizeInBits(); 231e8d8bef9SDimitry Andric MVT XLenVT = Subtarget->getXLenVT(); 232e8d8bef9SDimitry Andric RISCVVLMUL LMUL = getLMUL(VT); 233e8d8bef9SDimitry Andric SDValue SEW = CurDAG->getTargetConstant(ScalarSize, DL, XLenVT); 234e8d8bef9SDimitry Andric SmallVector<SDValue, 5> Operands; 235e8d8bef9SDimitry Andric Operands.push_back(Node->getOperand(2)); // Base pointer. 236e8d8bef9SDimitry Andric Operands.push_back(Node->getOperand(3)); // VL. 237e8d8bef9SDimitry Andric Operands.push_back(SEW); 238e8d8bef9SDimitry Andric Operands.push_back(Node->getOperand(0)); // Chain. 239e8d8bef9SDimitry Andric const RISCVZvlssegTable::RISCVZvlsseg *P = RISCVZvlssegTable::getPseudo( 240e8d8bef9SDimitry Andric IntNo, ScalarSize, static_cast<unsigned>(LMUL), 241e8d8bef9SDimitry Andric static_cast<unsigned>(RISCVVLMUL::LMUL_1)); 242e8d8bef9SDimitry Andric SDNode *Load = CurDAG->getMachineNode(P->Pseudo, DL, MVT::Untyped, MVT::Other, 243e8d8bef9SDimitry Andric MVT::Glue, Operands); 244e8d8bef9SDimitry Andric SDValue SuperReg = SDValue(Load, 0); 245e8d8bef9SDimitry Andric for (unsigned I = 0; I < NF; ++I) 246e8d8bef9SDimitry Andric ReplaceUses(SDValue(Node, I), 247e8d8bef9SDimitry Andric CurDAG->getTargetExtractSubreg(getSubregIndexByEVT(VT, I), DL, 248e8d8bef9SDimitry Andric VT, SuperReg)); 249e8d8bef9SDimitry Andric 250e8d8bef9SDimitry Andric ReplaceUses(SDValue(Node, NF), SDValue(Load, 1)); // Chain. 251e8d8bef9SDimitry Andric ReplaceUses(SDValue(Node, NF + 1), SDValue(Load, 2)); // Glue. 252e8d8bef9SDimitry Andric CurDAG->RemoveDeadNode(Node); 253e8d8bef9SDimitry Andric } 254e8d8bef9SDimitry Andric 255e8d8bef9SDimitry Andric void RISCVDAGToDAGISel::selectVLSEGFFMask(SDNode *Node) { 256e8d8bef9SDimitry Andric SDLoc DL(Node); 257e8d8bef9SDimitry Andric unsigned IntNo = cast<ConstantSDNode>(Node->getOperand(1))->getZExtValue(); 258e8d8bef9SDimitry Andric unsigned NF = Node->getNumValues() - 2; // Do not count Chain and Glue. 259e8d8bef9SDimitry Andric EVT VT = Node->getValueType(0); 260e8d8bef9SDimitry Andric unsigned ScalarSize = VT.getScalarSizeInBits(); 261e8d8bef9SDimitry Andric MVT XLenVT = Subtarget->getXLenVT(); 262e8d8bef9SDimitry Andric RISCVVLMUL LMUL = getLMUL(VT); 263e8d8bef9SDimitry Andric SDValue SEW = CurDAG->getTargetConstant(ScalarSize, DL, XLenVT); 264e8d8bef9SDimitry Andric SmallVector<SDValue, 8> Regs(Node->op_begin() + 2, Node->op_begin() + 2 + NF); 265e8d8bef9SDimitry Andric SDValue MaskedOff = createTuple(*CurDAG, Regs, NF, LMUL); 266e8d8bef9SDimitry Andric SmallVector<SDValue, 7> Operands; 267e8d8bef9SDimitry Andric Operands.push_back(MaskedOff); 268e8d8bef9SDimitry Andric Operands.push_back(Node->getOperand(NF + 2)); // Base pointer. 269e8d8bef9SDimitry Andric Operands.push_back(Node->getOperand(NF + 3)); // Mask. 270e8d8bef9SDimitry Andric Operands.push_back(Node->getOperand(NF + 4)); // VL. 271e8d8bef9SDimitry Andric Operands.push_back(SEW); 272e8d8bef9SDimitry Andric Operands.push_back(Node->getOperand(0)); /// Chain. 273e8d8bef9SDimitry Andric const RISCVZvlssegTable::RISCVZvlsseg *P = RISCVZvlssegTable::getPseudo( 274e8d8bef9SDimitry Andric IntNo, ScalarSize, static_cast<unsigned>(LMUL), 275e8d8bef9SDimitry Andric static_cast<unsigned>(RISCVVLMUL::LMUL_1)); 276e8d8bef9SDimitry Andric SDNode *Load = CurDAG->getMachineNode(P->Pseudo, DL, MVT::Untyped, MVT::Other, 277e8d8bef9SDimitry Andric MVT::Glue, Operands); 278e8d8bef9SDimitry Andric SDValue SuperReg = SDValue(Load, 0); 279e8d8bef9SDimitry Andric for (unsigned I = 0; I < NF; ++I) 280e8d8bef9SDimitry Andric ReplaceUses(SDValue(Node, I), 281e8d8bef9SDimitry Andric CurDAG->getTargetExtractSubreg(getSubregIndexByEVT(VT, I), DL, 282e8d8bef9SDimitry Andric VT, SuperReg)); 283e8d8bef9SDimitry Andric 284e8d8bef9SDimitry Andric ReplaceUses(SDValue(Node, NF), SDValue(Load, 1)); // Chain. 285e8d8bef9SDimitry Andric ReplaceUses(SDValue(Node, NF + 1), SDValue(Load, 2)); // Glue. 286e8d8bef9SDimitry Andric CurDAG->RemoveDeadNode(Node); 287e8d8bef9SDimitry Andric } 288e8d8bef9SDimitry Andric 289e8d8bef9SDimitry Andric void RISCVDAGToDAGISel::selectVLXSEG(SDNode *Node, unsigned IntNo) { 290e8d8bef9SDimitry Andric SDLoc DL(Node); 291e8d8bef9SDimitry Andric unsigned NF = Node->getNumValues() - 1; 292e8d8bef9SDimitry Andric EVT VT = Node->getValueType(0); 293e8d8bef9SDimitry Andric unsigned ScalarSize = VT.getScalarSizeInBits(); 294e8d8bef9SDimitry Andric MVT XLenVT = Subtarget->getXLenVT(); 295e8d8bef9SDimitry Andric RISCVVLMUL LMUL = getLMUL(VT); 296e8d8bef9SDimitry Andric SDValue SEW = CurDAG->getTargetConstant(ScalarSize, DL, XLenVT); 297e8d8bef9SDimitry Andric SDValue Operands[] = { 298e8d8bef9SDimitry Andric Node->getOperand(2), // Base pointer. 299e8d8bef9SDimitry Andric Node->getOperand(3), // Index. 300e8d8bef9SDimitry Andric Node->getOperand(4), // VL. 301e8d8bef9SDimitry Andric SEW, Node->getOperand(0) // Chain. 302e8d8bef9SDimitry Andric }; 303e8d8bef9SDimitry Andric 304e8d8bef9SDimitry Andric EVT IndexVT = Node->getOperand(3)->getValueType(0); 305e8d8bef9SDimitry Andric RISCVVLMUL IndexLMUL = getLMUL(IndexVT); 306e8d8bef9SDimitry Andric unsigned IndexScalarSize = IndexVT.getScalarSizeInBits(); 307e8d8bef9SDimitry Andric const RISCVZvlssegTable::RISCVZvlsseg *P = RISCVZvlssegTable::getPseudo( 308e8d8bef9SDimitry Andric IntNo, IndexScalarSize, static_cast<unsigned>(LMUL), 309e8d8bef9SDimitry Andric static_cast<unsigned>(IndexLMUL)); 310e8d8bef9SDimitry Andric SDNode *Load = 311e8d8bef9SDimitry Andric CurDAG->getMachineNode(P->Pseudo, DL, MVT::Untyped, MVT::Other, Operands); 312e8d8bef9SDimitry Andric SDValue SuperReg = SDValue(Load, 0); 313e8d8bef9SDimitry Andric for (unsigned I = 0; I < NF; ++I) 314e8d8bef9SDimitry Andric ReplaceUses(SDValue(Node, I), 315e8d8bef9SDimitry Andric CurDAG->getTargetExtractSubreg(getSubregIndexByEVT(VT, I), DL, 316e8d8bef9SDimitry Andric VT, SuperReg)); 317e8d8bef9SDimitry Andric 318e8d8bef9SDimitry Andric ReplaceUses(SDValue(Node, NF), SDValue(Load, 1)); 319e8d8bef9SDimitry Andric CurDAG->RemoveDeadNode(Node); 320e8d8bef9SDimitry Andric } 321e8d8bef9SDimitry Andric 322e8d8bef9SDimitry Andric void RISCVDAGToDAGISel::selectVLXSEGMask(SDNode *Node, unsigned IntNo) { 323e8d8bef9SDimitry Andric SDLoc DL(Node); 324e8d8bef9SDimitry Andric unsigned NF = Node->getNumValues() - 1; 325e8d8bef9SDimitry Andric EVT VT = Node->getValueType(0); 326e8d8bef9SDimitry Andric unsigned ScalarSize = VT.getScalarSizeInBits(); 327e8d8bef9SDimitry Andric MVT XLenVT = Subtarget->getXLenVT(); 328e8d8bef9SDimitry Andric RISCVVLMUL LMUL = getLMUL(VT); 329e8d8bef9SDimitry Andric SDValue SEW = CurDAG->getTargetConstant(ScalarSize, DL, XLenVT); 330e8d8bef9SDimitry Andric SmallVector<SDValue, 8> Regs(Node->op_begin() + 2, Node->op_begin() + 2 + NF); 331e8d8bef9SDimitry Andric SDValue MaskedOff = createTuple(*CurDAG, Regs, NF, LMUL); 332e8d8bef9SDimitry Andric SDValue Operands[] = { 333e8d8bef9SDimitry Andric MaskedOff, 334e8d8bef9SDimitry Andric Node->getOperand(NF + 2), // Base pointer. 335e8d8bef9SDimitry Andric Node->getOperand(NF + 3), // Index. 336e8d8bef9SDimitry Andric Node->getOperand(NF + 4), // Mask. 337e8d8bef9SDimitry Andric Node->getOperand(NF + 5), // VL. 338e8d8bef9SDimitry Andric SEW, 339e8d8bef9SDimitry Andric Node->getOperand(0) // Chain. 340e8d8bef9SDimitry Andric }; 341e8d8bef9SDimitry Andric 342e8d8bef9SDimitry Andric EVT IndexVT = Node->getOperand(NF + 3)->getValueType(0); 343e8d8bef9SDimitry Andric RISCVVLMUL IndexLMUL = getLMUL(IndexVT); 344e8d8bef9SDimitry Andric unsigned IndexScalarSize = IndexVT.getScalarSizeInBits(); 345e8d8bef9SDimitry Andric const RISCVZvlssegTable::RISCVZvlsseg *P = RISCVZvlssegTable::getPseudo( 346e8d8bef9SDimitry Andric IntNo, IndexScalarSize, static_cast<unsigned>(LMUL), 347e8d8bef9SDimitry Andric static_cast<unsigned>(IndexLMUL)); 348e8d8bef9SDimitry Andric SDNode *Load = 349e8d8bef9SDimitry Andric CurDAG->getMachineNode(P->Pseudo, DL, MVT::Untyped, MVT::Other, Operands); 350e8d8bef9SDimitry Andric SDValue SuperReg = SDValue(Load, 0); 351e8d8bef9SDimitry Andric for (unsigned I = 0; I < NF; ++I) 352e8d8bef9SDimitry Andric ReplaceUses(SDValue(Node, I), 353e8d8bef9SDimitry Andric CurDAG->getTargetExtractSubreg(getSubregIndexByEVT(VT, I), DL, 354e8d8bef9SDimitry Andric VT, SuperReg)); 355e8d8bef9SDimitry Andric 356e8d8bef9SDimitry Andric ReplaceUses(SDValue(Node, NF), SDValue(Load, 1)); 357e8d8bef9SDimitry Andric CurDAG->RemoveDeadNode(Node); 358e8d8bef9SDimitry Andric } 359e8d8bef9SDimitry Andric 360e8d8bef9SDimitry Andric void RISCVDAGToDAGISel::selectVSSEG(SDNode *Node, unsigned IntNo, 361e8d8bef9SDimitry Andric bool IsStrided) { 362e8d8bef9SDimitry Andric SDLoc DL(Node); 363e8d8bef9SDimitry Andric unsigned NF = Node->getNumOperands() - 4; 364e8d8bef9SDimitry Andric if (IsStrided) 365e8d8bef9SDimitry Andric NF--; 366e8d8bef9SDimitry Andric EVT VT = Node->getOperand(2)->getValueType(0); 367e8d8bef9SDimitry Andric unsigned ScalarSize = VT.getScalarSizeInBits(); 368e8d8bef9SDimitry Andric MVT XLenVT = Subtarget->getXLenVT(); 369e8d8bef9SDimitry Andric RISCVVLMUL LMUL = getLMUL(VT); 370e8d8bef9SDimitry Andric SDValue SEW = CurDAG->getTargetConstant(ScalarSize, DL, XLenVT); 371e8d8bef9SDimitry Andric SmallVector<SDValue, 8> Regs(Node->op_begin() + 2, Node->op_begin() + 2 + NF); 372e8d8bef9SDimitry Andric SDValue StoreVal = createTuple(*CurDAG, Regs, NF, LMUL); 373e8d8bef9SDimitry Andric SmallVector<SDValue, 6> Operands; 374e8d8bef9SDimitry Andric Operands.push_back(StoreVal); 375e8d8bef9SDimitry Andric Operands.push_back(Node->getOperand(2 + NF)); // Base pointer. 376e8d8bef9SDimitry Andric if (IsStrided) { 377e8d8bef9SDimitry Andric Operands.push_back(Node->getOperand(3 + NF)); // Stride. 378e8d8bef9SDimitry Andric Operands.push_back(Node->getOperand(4 + NF)); // VL. 379e8d8bef9SDimitry Andric } else { 380e8d8bef9SDimitry Andric Operands.push_back(Node->getOperand(3 + NF)); // VL. 381e8d8bef9SDimitry Andric } 382e8d8bef9SDimitry Andric Operands.push_back(SEW); 383e8d8bef9SDimitry Andric Operands.push_back(Node->getOperand(0)); // Chain. 384e8d8bef9SDimitry Andric const RISCVZvlssegTable::RISCVZvlsseg *P = RISCVZvlssegTable::getPseudo( 385e8d8bef9SDimitry Andric IntNo, ScalarSize, static_cast<unsigned>(LMUL), 386e8d8bef9SDimitry Andric static_cast<unsigned>(RISCVVLMUL::LMUL_1)); 387e8d8bef9SDimitry Andric SDNode *Store = 388e8d8bef9SDimitry Andric CurDAG->getMachineNode(P->Pseudo, DL, Node->getValueType(0), Operands); 389e8d8bef9SDimitry Andric ReplaceNode(Node, Store); 390e8d8bef9SDimitry Andric } 391e8d8bef9SDimitry Andric 392e8d8bef9SDimitry Andric void RISCVDAGToDAGISel::selectVSSEGMask(SDNode *Node, unsigned IntNo, 393e8d8bef9SDimitry Andric bool IsStrided) { 394e8d8bef9SDimitry Andric SDLoc DL(Node); 395e8d8bef9SDimitry Andric unsigned NF = Node->getNumOperands() - 5; 396e8d8bef9SDimitry Andric if (IsStrided) 397e8d8bef9SDimitry Andric NF--; 398e8d8bef9SDimitry Andric EVT VT = Node->getOperand(2)->getValueType(0); 399e8d8bef9SDimitry Andric unsigned ScalarSize = VT.getScalarSizeInBits(); 400e8d8bef9SDimitry Andric MVT XLenVT = Subtarget->getXLenVT(); 401e8d8bef9SDimitry Andric RISCVVLMUL LMUL = getLMUL(VT); 402e8d8bef9SDimitry Andric SDValue SEW = CurDAG->getTargetConstant(ScalarSize, DL, XLenVT); 403e8d8bef9SDimitry Andric SmallVector<SDValue, 8> Regs(Node->op_begin() + 2, Node->op_begin() + 2 + NF); 404e8d8bef9SDimitry Andric SDValue StoreVal = createTuple(*CurDAG, Regs, NF, LMUL); 405e8d8bef9SDimitry Andric SmallVector<SDValue, 7> Operands; 406e8d8bef9SDimitry Andric Operands.push_back(StoreVal); 407e8d8bef9SDimitry Andric Operands.push_back(Node->getOperand(2 + NF)); // Base pointer. 408e8d8bef9SDimitry Andric if (IsStrided) { 409e8d8bef9SDimitry Andric Operands.push_back(Node->getOperand(3 + NF)); // Stride. 410e8d8bef9SDimitry Andric Operands.push_back(Node->getOperand(4 + NF)); // Mask. 411e8d8bef9SDimitry Andric Operands.push_back(Node->getOperand(5 + NF)); // VL. 412e8d8bef9SDimitry Andric } else { 413e8d8bef9SDimitry Andric Operands.push_back(Node->getOperand(3 + NF)); // Mask. 414e8d8bef9SDimitry Andric Operands.push_back(Node->getOperand(4 + NF)); // VL. 415e8d8bef9SDimitry Andric } 416e8d8bef9SDimitry Andric Operands.push_back(SEW); 417e8d8bef9SDimitry Andric Operands.push_back(Node->getOperand(0)); // Chain. 418e8d8bef9SDimitry Andric const RISCVZvlssegTable::RISCVZvlsseg *P = RISCVZvlssegTable::getPseudo( 419e8d8bef9SDimitry Andric IntNo, ScalarSize, static_cast<unsigned>(LMUL), 420e8d8bef9SDimitry Andric static_cast<unsigned>(RISCVVLMUL::LMUL_1)); 421e8d8bef9SDimitry Andric SDNode *Store = 422e8d8bef9SDimitry Andric CurDAG->getMachineNode(P->Pseudo, DL, Node->getValueType(0), Operands); 423e8d8bef9SDimitry Andric ReplaceNode(Node, Store); 424e8d8bef9SDimitry Andric } 425e8d8bef9SDimitry Andric 426e8d8bef9SDimitry Andric void RISCVDAGToDAGISel::selectVSXSEG(SDNode *Node, unsigned IntNo) { 427e8d8bef9SDimitry Andric SDLoc DL(Node); 428e8d8bef9SDimitry Andric unsigned NF = Node->getNumOperands() - 5; 429e8d8bef9SDimitry Andric EVT VT = Node->getOperand(2)->getValueType(0); 430e8d8bef9SDimitry Andric unsigned ScalarSize = VT.getScalarSizeInBits(); 431e8d8bef9SDimitry Andric MVT XLenVT = Subtarget->getXLenVT(); 432e8d8bef9SDimitry Andric RISCVVLMUL LMUL = getLMUL(VT); 433e8d8bef9SDimitry Andric SDValue SEW = CurDAG->getTargetConstant(ScalarSize, DL, XLenVT); 434e8d8bef9SDimitry Andric SmallVector<SDValue, 8> Regs(Node->op_begin() + 2, Node->op_begin() + 2 + NF); 435e8d8bef9SDimitry Andric SDValue StoreVal = createTuple(*CurDAG, Regs, NF, LMUL); 436e8d8bef9SDimitry Andric SDValue Operands[] = { 437e8d8bef9SDimitry Andric StoreVal, 438e8d8bef9SDimitry Andric Node->getOperand(2 + NF), // Base pointer. 439e8d8bef9SDimitry Andric Node->getOperand(3 + NF), // Index. 440e8d8bef9SDimitry Andric Node->getOperand(4 + NF), // VL. 441e8d8bef9SDimitry Andric SEW, 442e8d8bef9SDimitry Andric Node->getOperand(0) // Chain. 443e8d8bef9SDimitry Andric }; 444e8d8bef9SDimitry Andric 445e8d8bef9SDimitry Andric EVT IndexVT = Node->getOperand(3 + NF)->getValueType(0); 446e8d8bef9SDimitry Andric RISCVVLMUL IndexLMUL = getLMUL(IndexVT); 447e8d8bef9SDimitry Andric unsigned IndexScalarSize = IndexVT.getScalarSizeInBits(); 448e8d8bef9SDimitry Andric const RISCVZvlssegTable::RISCVZvlsseg *P = RISCVZvlssegTable::getPseudo( 449e8d8bef9SDimitry Andric IntNo, IndexScalarSize, static_cast<unsigned>(LMUL), 450e8d8bef9SDimitry Andric static_cast<unsigned>(IndexLMUL)); 451e8d8bef9SDimitry Andric SDNode *Store = 452e8d8bef9SDimitry Andric CurDAG->getMachineNode(P->Pseudo, DL, Node->getValueType(0), Operands); 453e8d8bef9SDimitry Andric ReplaceNode(Node, Store); 454e8d8bef9SDimitry Andric } 455e8d8bef9SDimitry Andric 456e8d8bef9SDimitry Andric void RISCVDAGToDAGISel::selectVSXSEGMask(SDNode *Node, unsigned IntNo) { 457e8d8bef9SDimitry Andric SDLoc DL(Node); 458e8d8bef9SDimitry Andric unsigned NF = Node->getNumOperands() - 6; 459e8d8bef9SDimitry Andric EVT VT = Node->getOperand(2)->getValueType(0); 460e8d8bef9SDimitry Andric unsigned ScalarSize = VT.getScalarSizeInBits(); 461e8d8bef9SDimitry Andric MVT XLenVT = Subtarget->getXLenVT(); 462e8d8bef9SDimitry Andric RISCVVLMUL LMUL = getLMUL(VT); 463e8d8bef9SDimitry Andric SDValue SEW = CurDAG->getTargetConstant(ScalarSize, DL, XLenVT); 464e8d8bef9SDimitry Andric SmallVector<SDValue, 8> Regs(Node->op_begin() + 2, Node->op_begin() + 2 + NF); 465e8d8bef9SDimitry Andric SDValue StoreVal = createTuple(*CurDAG, Regs, NF, LMUL); 466e8d8bef9SDimitry Andric SDValue Operands[] = { 467e8d8bef9SDimitry Andric StoreVal, 468e8d8bef9SDimitry Andric Node->getOperand(2 + NF), // Base pointer. 469e8d8bef9SDimitry Andric Node->getOperand(3 + NF), // Index. 470e8d8bef9SDimitry Andric Node->getOperand(4 + NF), // Mask. 471e8d8bef9SDimitry Andric Node->getOperand(5 + NF), // VL. 472e8d8bef9SDimitry Andric SEW, 473e8d8bef9SDimitry Andric Node->getOperand(0) // Chain. 474e8d8bef9SDimitry Andric }; 475e8d8bef9SDimitry Andric 476e8d8bef9SDimitry Andric EVT IndexVT = Node->getOperand(3 + NF)->getValueType(0); 477e8d8bef9SDimitry Andric RISCVVLMUL IndexLMUL = getLMUL(IndexVT); 478e8d8bef9SDimitry Andric unsigned IndexScalarSize = IndexVT.getScalarSizeInBits(); 479e8d8bef9SDimitry Andric const RISCVZvlssegTable::RISCVZvlsseg *P = RISCVZvlssegTable::getPseudo( 480e8d8bef9SDimitry Andric IntNo, IndexScalarSize, static_cast<unsigned>(LMUL), 481e8d8bef9SDimitry Andric static_cast<unsigned>(IndexLMUL)); 482e8d8bef9SDimitry Andric SDNode *Store = 483e8d8bef9SDimitry Andric CurDAG->getMachineNode(P->Pseudo, DL, Node->getValueType(0), Operands); 484e8d8bef9SDimitry Andric ReplaceNode(Node, Store); 4850b57cec5SDimitry Andric } 4860b57cec5SDimitry Andric 4870b57cec5SDimitry Andric void RISCVDAGToDAGISel::Select(SDNode *Node) { 4880b57cec5SDimitry Andric // If we have a custom node, we have already selected. 4890b57cec5SDimitry Andric if (Node->isMachineOpcode()) { 4900b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "== "; Node->dump(CurDAG); dbgs() << "\n"); 4910b57cec5SDimitry Andric Node->setNodeId(-1); 4920b57cec5SDimitry Andric return; 4930b57cec5SDimitry Andric } 4940b57cec5SDimitry Andric 4950b57cec5SDimitry Andric // Instruction Selection not handled by the auto-generated tablegen selection 4960b57cec5SDimitry Andric // should be handled here. 4970b57cec5SDimitry Andric unsigned Opcode = Node->getOpcode(); 4980b57cec5SDimitry Andric MVT XLenVT = Subtarget->getXLenVT(); 4990b57cec5SDimitry Andric SDLoc DL(Node); 5000b57cec5SDimitry Andric EVT VT = Node->getValueType(0); 5010b57cec5SDimitry Andric 5020b57cec5SDimitry Andric switch (Opcode) { 5035ffd83dbSDimitry Andric case ISD::ADD: { 5045ffd83dbSDimitry Andric // Optimize (add r, imm) to (addi (addi r, imm0) imm1) if applicable. The 5055ffd83dbSDimitry Andric // immediate must be in specific ranges and have a single use. 5065ffd83dbSDimitry Andric if (auto *ConstOp = dyn_cast<ConstantSDNode>(Node->getOperand(1))) { 5075ffd83dbSDimitry Andric if (!(ConstOp->hasOneUse())) 5085ffd83dbSDimitry Andric break; 5095ffd83dbSDimitry Andric // The imm must be in range [-4096,-2049] or [2048,4094]. 5105ffd83dbSDimitry Andric int64_t Imm = ConstOp->getSExtValue(); 5115ffd83dbSDimitry Andric if (!(-4096 <= Imm && Imm <= -2049) && !(2048 <= Imm && Imm <= 4094)) 5125ffd83dbSDimitry Andric break; 5135ffd83dbSDimitry Andric // Break the imm to imm0+imm1. 5145ffd83dbSDimitry Andric EVT VT = Node->getValueType(0); 5155ffd83dbSDimitry Andric const SDValue ImmOp0 = CurDAG->getTargetConstant(Imm - Imm / 2, DL, VT); 5165ffd83dbSDimitry Andric const SDValue ImmOp1 = CurDAG->getTargetConstant(Imm / 2, DL, VT); 5175ffd83dbSDimitry Andric auto *NodeAddi0 = CurDAG->getMachineNode(RISCV::ADDI, DL, VT, 5185ffd83dbSDimitry Andric Node->getOperand(0), ImmOp0); 5195ffd83dbSDimitry Andric auto *NodeAddi1 = CurDAG->getMachineNode(RISCV::ADDI, DL, VT, 5205ffd83dbSDimitry Andric SDValue(NodeAddi0, 0), ImmOp1); 5215ffd83dbSDimitry Andric ReplaceNode(Node, NodeAddi1); 5225ffd83dbSDimitry Andric return; 5235ffd83dbSDimitry Andric } 5245ffd83dbSDimitry Andric break; 5255ffd83dbSDimitry Andric } 5260b57cec5SDimitry Andric case ISD::Constant: { 5270b57cec5SDimitry Andric auto ConstNode = cast<ConstantSDNode>(Node); 5280b57cec5SDimitry Andric if (VT == XLenVT && ConstNode->isNullValue()) { 529e8d8bef9SDimitry Andric SDValue New = 530e8d8bef9SDimitry Andric CurDAG->getCopyFromReg(CurDAG->getEntryNode(), DL, RISCV::X0, XLenVT); 5310b57cec5SDimitry Andric ReplaceNode(Node, New.getNode()); 5320b57cec5SDimitry Andric return; 5330b57cec5SDimitry Andric } 5340b57cec5SDimitry Andric int64_t Imm = ConstNode->getSExtValue(); 5350b57cec5SDimitry Andric if (XLenVT == MVT::i64) { 536e8d8bef9SDimitry Andric ReplaceNode(Node, selectImm(CurDAG, DL, Imm, XLenVT)); 5370b57cec5SDimitry Andric return; 5380b57cec5SDimitry Andric } 5390b57cec5SDimitry Andric break; 5400b57cec5SDimitry Andric } 5410b57cec5SDimitry Andric case ISD::FrameIndex: { 5420b57cec5SDimitry Andric SDValue Imm = CurDAG->getTargetConstant(0, DL, XLenVT); 5430b57cec5SDimitry Andric int FI = cast<FrameIndexSDNode>(Node)->getIndex(); 5440b57cec5SDimitry Andric SDValue TFI = CurDAG->getTargetFrameIndex(FI, VT); 5450b57cec5SDimitry Andric ReplaceNode(Node, CurDAG->getMachineNode(RISCV::ADDI, DL, VT, TFI, Imm)); 5460b57cec5SDimitry Andric return; 5470b57cec5SDimitry Andric } 548e8d8bef9SDimitry Andric case ISD::INTRINSIC_W_CHAIN: { 549e8d8bef9SDimitry Andric unsigned IntNo = cast<ConstantSDNode>(Node->getOperand(1))->getZExtValue(); 550e8d8bef9SDimitry Andric switch (IntNo) { 551e8d8bef9SDimitry Andric // By default we do not custom select any intrinsic. 552e8d8bef9SDimitry Andric default: 5530b57cec5SDimitry Andric break; 5540b57cec5SDimitry Andric 555e8d8bef9SDimitry Andric case Intrinsic::riscv_vsetvli: { 556e8d8bef9SDimitry Andric if (!Subtarget->hasStdExtV()) 557e8d8bef9SDimitry Andric break; 558e8d8bef9SDimitry Andric 559e8d8bef9SDimitry Andric assert(Node->getNumOperands() == 5); 560e8d8bef9SDimitry Andric 561e8d8bef9SDimitry Andric RISCVVSEW VSEW = 562e8d8bef9SDimitry Andric static_cast<RISCVVSEW>(Node->getConstantOperandVal(3) & 0x7); 563e8d8bef9SDimitry Andric RISCVVLMUL VLMul = 564e8d8bef9SDimitry Andric static_cast<RISCVVLMUL>(Node->getConstantOperandVal(4) & 0x7); 565e8d8bef9SDimitry Andric 566e8d8bef9SDimitry Andric unsigned VTypeI = RISCVVType::encodeVTYPE( 567e8d8bef9SDimitry Andric VLMul, VSEW, /*TailAgnostic*/ true, /*MaskAgnostic*/ false); 568e8d8bef9SDimitry Andric SDValue VTypeIOp = CurDAG->getTargetConstant(VTypeI, DL, XLenVT); 569e8d8bef9SDimitry Andric 570e8d8bef9SDimitry Andric SDValue VLOperand = Node->getOperand(2); 571e8d8bef9SDimitry Andric if (auto *C = dyn_cast<ConstantSDNode>(VLOperand)) { 572*d409305fSDimitry Andric uint64_t AVL = C->getZExtValue(); 573*d409305fSDimitry Andric if (isUInt<5>(AVL)) { 574*d409305fSDimitry Andric SDValue VLImm = CurDAG->getTargetConstant(AVL, DL, XLenVT); 575*d409305fSDimitry Andric ReplaceNode(Node, 576*d409305fSDimitry Andric CurDAG->getMachineNode(RISCV::PseudoVSETIVLI, DL, XLenVT, 577*d409305fSDimitry Andric MVT::Other, VLImm, VTypeIOp, 578*d409305fSDimitry Andric /* Chain */ Node->getOperand(0))); 579*d409305fSDimitry Andric return; 580e8d8bef9SDimitry Andric } 581e8d8bef9SDimitry Andric } 582e8d8bef9SDimitry Andric 583e8d8bef9SDimitry Andric ReplaceNode(Node, 584e8d8bef9SDimitry Andric CurDAG->getMachineNode(RISCV::PseudoVSETVLI, DL, XLenVT, 585e8d8bef9SDimitry Andric MVT::Other, VLOperand, VTypeIOp, 586e8d8bef9SDimitry Andric /* Chain */ Node->getOperand(0))); 587e8d8bef9SDimitry Andric return; 588e8d8bef9SDimitry Andric } 589e8d8bef9SDimitry Andric case Intrinsic::riscv_vsetvlimax: { 590e8d8bef9SDimitry Andric if (!Subtarget->hasStdExtV()) 591e8d8bef9SDimitry Andric break; 592e8d8bef9SDimitry Andric 593e8d8bef9SDimitry Andric assert(Node->getNumOperands() == 4); 594e8d8bef9SDimitry Andric 595e8d8bef9SDimitry Andric RISCVVSEW VSEW = 596e8d8bef9SDimitry Andric static_cast<RISCVVSEW>(Node->getConstantOperandVal(2) & 0x7); 597e8d8bef9SDimitry Andric RISCVVLMUL VLMul = 598e8d8bef9SDimitry Andric static_cast<RISCVVLMUL>(Node->getConstantOperandVal(3) & 0x7); 599e8d8bef9SDimitry Andric 600e8d8bef9SDimitry Andric unsigned VTypeI = RISCVVType::encodeVTYPE( 601e8d8bef9SDimitry Andric VLMul, VSEW, /*TailAgnostic*/ true, /*MaskAgnostic*/ false); 602e8d8bef9SDimitry Andric SDValue VTypeIOp = CurDAG->getTargetConstant(VTypeI, DL, XLenVT); 603e8d8bef9SDimitry Andric 604e8d8bef9SDimitry Andric SDValue VLOperand = CurDAG->getRegister(RISCV::X0, XLenVT); 605e8d8bef9SDimitry Andric ReplaceNode(Node, 606e8d8bef9SDimitry Andric CurDAG->getMachineNode(RISCV::PseudoVSETVLI, DL, XLenVT, 607e8d8bef9SDimitry Andric MVT::Other, VLOperand, VTypeIOp, 608e8d8bef9SDimitry Andric /* Chain */ Node->getOperand(0))); 609e8d8bef9SDimitry Andric return; 610e8d8bef9SDimitry Andric } 611e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg2: 612e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg3: 613e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg4: 614e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg5: 615e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg6: 616e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg7: 617e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg8: { 618e8d8bef9SDimitry Andric selectVLSEG(Node, IntNo, /*IsStrided=*/false); 619e8d8bef9SDimitry Andric return; 620e8d8bef9SDimitry Andric } 621e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg2_mask: 622e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg3_mask: 623e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg4_mask: 624e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg5_mask: 625e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg6_mask: 626e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg7_mask: 627e8d8bef9SDimitry Andric case Intrinsic::riscv_vlseg8_mask: { 628e8d8bef9SDimitry Andric selectVLSEGMask(Node, IntNo, /*IsStrided=*/false); 629e8d8bef9SDimitry Andric return; 630e8d8bef9SDimitry Andric } 631e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg2: 632e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg3: 633e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg4: 634e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg5: 635e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg6: 636e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg7: 637e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg8: { 638e8d8bef9SDimitry Andric selectVLSEG(Node, IntNo, /*IsStrided=*/true); 639e8d8bef9SDimitry Andric return; 640e8d8bef9SDimitry Andric } 641e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg2_mask: 642e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg3_mask: 643e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg4_mask: 644e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg5_mask: 645e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg6_mask: 646e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg7_mask: 647e8d8bef9SDimitry Andric case Intrinsic::riscv_vlsseg8_mask: { 648e8d8bef9SDimitry Andric selectVLSEGMask(Node, IntNo, /*IsStrided=*/true); 649e8d8bef9SDimitry Andric return; 650e8d8bef9SDimitry Andric } 651e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg2: 652e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg3: 653e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg4: 654e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg5: 655e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg6: 656e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg7: 657e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg8: 658e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg2: 659e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg3: 660e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg4: 661e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg5: 662e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg6: 663e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg7: 664e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg8: { 665e8d8bef9SDimitry Andric selectVLXSEG(Node, IntNo); 666e8d8bef9SDimitry Andric return; 667e8d8bef9SDimitry Andric } 668e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg2_mask: 669e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg3_mask: 670e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg4_mask: 671e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg5_mask: 672e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg6_mask: 673e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg7_mask: 674e8d8bef9SDimitry Andric case Intrinsic::riscv_vloxseg8_mask: 675e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg2_mask: 676e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg3_mask: 677e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg4_mask: 678e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg5_mask: 679e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg6_mask: 680e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg7_mask: 681e8d8bef9SDimitry Andric case Intrinsic::riscv_vluxseg8_mask: { 682e8d8bef9SDimitry Andric selectVLXSEGMask(Node, IntNo); 6830b57cec5SDimitry Andric return; 6840b57cec5SDimitry Andric } 6850b57cec5SDimitry Andric } 6860b57cec5SDimitry Andric break; 6870b57cec5SDimitry Andric } 688e8d8bef9SDimitry Andric case ISD::INTRINSIC_VOID: { 689e8d8bef9SDimitry Andric unsigned IntNo = cast<ConstantSDNode>(Node->getOperand(1))->getZExtValue(); 690e8d8bef9SDimitry Andric switch (IntNo) { 691e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg2: 692e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg3: 693e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg4: 694e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg5: 695e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg6: 696e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg7: 697e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg8: { 698e8d8bef9SDimitry Andric selectVSSEG(Node, IntNo, /*IsStrided=*/false); 6990b57cec5SDimitry Andric return; 7000b57cec5SDimitry Andric } 701e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg2_mask: 702e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg3_mask: 703e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg4_mask: 704e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg5_mask: 705e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg6_mask: 706e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg7_mask: 707e8d8bef9SDimitry Andric case Intrinsic::riscv_vsseg8_mask: { 708e8d8bef9SDimitry Andric selectVSSEGMask(Node, IntNo, /*IsStrided=*/false); 709e8d8bef9SDimitry Andric return; 710e8d8bef9SDimitry Andric } 711e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg2: 712e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg3: 713e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg4: 714e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg5: 715e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg6: 716e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg7: 717e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg8: { 718e8d8bef9SDimitry Andric selectVSSEG(Node, IntNo, /*IsStrided=*/true); 719e8d8bef9SDimitry Andric return; 720e8d8bef9SDimitry Andric } 721e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg2_mask: 722e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg3_mask: 723e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg4_mask: 724e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg5_mask: 725e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg6_mask: 726e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg7_mask: 727e8d8bef9SDimitry Andric case Intrinsic::riscv_vssseg8_mask: { 728e8d8bef9SDimitry Andric selectVSSEGMask(Node, IntNo, /*IsStrided=*/true); 729e8d8bef9SDimitry Andric return; 730e8d8bef9SDimitry Andric } 731e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg2: 732e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg3: 733e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg4: 734e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg5: 735e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg6: 736e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg7: 737e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg8: 738e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg2: 739e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg3: 740e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg4: 741e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg5: 742e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg6: 743e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg7: 744e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg8: { 745e8d8bef9SDimitry Andric selectVSXSEG(Node, IntNo); 746e8d8bef9SDimitry Andric return; 747e8d8bef9SDimitry Andric } 748e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg2_mask: 749e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg3_mask: 750e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg4_mask: 751e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg5_mask: 752e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg6_mask: 753e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg7_mask: 754e8d8bef9SDimitry Andric case Intrinsic::riscv_vsoxseg8_mask: 755e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg2_mask: 756e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg3_mask: 757e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg4_mask: 758e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg5_mask: 759e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg6_mask: 760e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg7_mask: 761e8d8bef9SDimitry Andric case Intrinsic::riscv_vsuxseg8_mask: { 762e8d8bef9SDimitry Andric selectVSXSEGMask(Node, IntNo); 763e8d8bef9SDimitry Andric return; 764e8d8bef9SDimitry Andric } 765e8d8bef9SDimitry Andric } 766e8d8bef9SDimitry Andric break; 767e8d8bef9SDimitry Andric } 768e8d8bef9SDimitry Andric case RISCVISD::VLSEGFF: { 769e8d8bef9SDimitry Andric selectVLSEGFF(Node); 770e8d8bef9SDimitry Andric return; 771e8d8bef9SDimitry Andric } 772e8d8bef9SDimitry Andric case RISCVISD::VLSEGFF_MASK: { 773e8d8bef9SDimitry Andric selectVLSEGFFMask(Node); 774e8d8bef9SDimitry Andric return; 775e8d8bef9SDimitry Andric } 776e8d8bef9SDimitry Andric } 7770b57cec5SDimitry Andric 7780b57cec5SDimitry Andric // Select the default instruction. 7790b57cec5SDimitry Andric SelectCode(Node); 7800b57cec5SDimitry Andric } 7810b57cec5SDimitry Andric 7820b57cec5SDimitry Andric bool RISCVDAGToDAGISel::SelectInlineAsmMemoryOperand( 7830b57cec5SDimitry Andric const SDValue &Op, unsigned ConstraintID, std::vector<SDValue> &OutOps) { 7840b57cec5SDimitry Andric switch (ConstraintID) { 7850b57cec5SDimitry Andric case InlineAsm::Constraint_m: 7860b57cec5SDimitry Andric // We just support simple memory operands that have a single address 7870b57cec5SDimitry Andric // operand and need no special handling. 7880b57cec5SDimitry Andric OutOps.push_back(Op); 7890b57cec5SDimitry Andric return false; 7900b57cec5SDimitry Andric case InlineAsm::Constraint_A: 7910b57cec5SDimitry Andric OutOps.push_back(Op); 7920b57cec5SDimitry Andric return false; 7930b57cec5SDimitry Andric default: 7940b57cec5SDimitry Andric break; 7950b57cec5SDimitry Andric } 7960b57cec5SDimitry Andric 7970b57cec5SDimitry Andric return true; 7980b57cec5SDimitry Andric } 7990b57cec5SDimitry Andric 8000b57cec5SDimitry Andric bool RISCVDAGToDAGISel::SelectAddrFI(SDValue Addr, SDValue &Base) { 8010b57cec5SDimitry Andric if (auto FIN = dyn_cast<FrameIndexSDNode>(Addr)) { 8020b57cec5SDimitry Andric Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), Subtarget->getXLenVT()); 8030b57cec5SDimitry Andric return true; 8040b57cec5SDimitry Andric } 8050b57cec5SDimitry Andric return false; 8060b57cec5SDimitry Andric } 8070b57cec5SDimitry Andric 808e8d8bef9SDimitry Andric // Match (srl (and val, mask), imm) where the result would be a 809e8d8bef9SDimitry Andric // zero-extended 32-bit integer. i.e. the mask is 0xffffffff or the result 810e8d8bef9SDimitry Andric // is equivalent to this (SimplifyDemandedBits may have removed lower bits 811e8d8bef9SDimitry Andric // from the mask that aren't necessary due to the right-shifting). 812e8d8bef9SDimitry Andric bool RISCVDAGToDAGISel::MatchSRLIW(SDNode *N) const { 813e8d8bef9SDimitry Andric assert(N->getOpcode() == ISD::SRL); 814e8d8bef9SDimitry Andric assert(N->getOperand(0).getOpcode() == ISD::AND); 815e8d8bef9SDimitry Andric assert(isa<ConstantSDNode>(N->getOperand(1))); 816e8d8bef9SDimitry Andric assert(isa<ConstantSDNode>(N->getOperand(0).getOperand(1))); 817e8d8bef9SDimitry Andric 818e8d8bef9SDimitry Andric // The IsRV64 predicate is checked after PatFrag predicates so we can get 819e8d8bef9SDimitry Andric // here even on RV32. 820e8d8bef9SDimitry Andric if (!Subtarget->is64Bit()) 821e8d8bef9SDimitry Andric return false; 822e8d8bef9SDimitry Andric 823e8d8bef9SDimitry Andric SDValue And = N->getOperand(0); 824e8d8bef9SDimitry Andric uint64_t ShAmt = N->getConstantOperandVal(1); 825e8d8bef9SDimitry Andric uint64_t Mask = And.getConstantOperandVal(1); 826e8d8bef9SDimitry Andric return (Mask | maskTrailingOnes<uint64_t>(ShAmt)) == 0xffffffff; 827e8d8bef9SDimitry Andric } 828e8d8bef9SDimitry Andric 829979e22ffSDimitry Andric // Check that it is a SLLIUW (Shift Logical Left Immediate Unsigned i32 830979e22ffSDimitry Andric // on RV64). 831979e22ffSDimitry Andric // SLLIUW is the same as SLLI except for the fact that it clears the bits 832979e22ffSDimitry Andric // XLEN-1:32 of the input RS1 before shifting. 833e8d8bef9SDimitry Andric // A PatFrag has already checked that it has the right structure: 834979e22ffSDimitry Andric // 835979e22ffSDimitry Andric // (AND (SHL RS1, VC2), VC1) 836979e22ffSDimitry Andric // 837979e22ffSDimitry Andric // We check that VC2, the shamt is less than 32, otherwise the pattern is 838979e22ffSDimitry Andric // exactly the same as SLLI and we give priority to that. 839e8d8bef9SDimitry Andric // Eventually we check that VC1, the mask used to clear the upper 32 bits 840979e22ffSDimitry Andric // of RS1, is correct: 841979e22ffSDimitry Andric // 842979e22ffSDimitry Andric // VC1 == (0xFFFFFFFF << VC2) 843e8d8bef9SDimitry Andric // 844e8d8bef9SDimitry Andric bool RISCVDAGToDAGISel::MatchSLLIUW(SDNode *N) const { 845e8d8bef9SDimitry Andric assert(N->getOpcode() == ISD::AND); 846e8d8bef9SDimitry Andric assert(N->getOperand(0).getOpcode() == ISD::SHL); 847e8d8bef9SDimitry Andric assert(isa<ConstantSDNode>(N->getOperand(1))); 848e8d8bef9SDimitry Andric assert(isa<ConstantSDNode>(N->getOperand(0).getOperand(1))); 849979e22ffSDimitry Andric 850e8d8bef9SDimitry Andric // The IsRV64 predicate is checked after PatFrag predicates so we can get 851e8d8bef9SDimitry Andric // here even on RV32. 852e8d8bef9SDimitry Andric if (!Subtarget->is64Bit()) 853e8d8bef9SDimitry Andric return false; 854e8d8bef9SDimitry Andric 855e8d8bef9SDimitry Andric SDValue Shl = N->getOperand(0); 856e8d8bef9SDimitry Andric uint64_t VC1 = N->getConstantOperandVal(1); 857979e22ffSDimitry Andric uint64_t VC2 = Shl.getConstantOperandVal(1); 858e8d8bef9SDimitry Andric 859e8d8bef9SDimitry Andric // Immediate range should be enforced by uimm5 predicate. 860e8d8bef9SDimitry Andric assert(VC2 < 32 && "Unexpected immediate"); 861e8d8bef9SDimitry Andric return (VC1 >> VC2) == UINT64_C(0xFFFFFFFF); 862e8d8bef9SDimitry Andric } 863e8d8bef9SDimitry Andric 864*d409305fSDimitry Andric // X0 has special meaning for vsetvl/vsetvli. 865*d409305fSDimitry Andric // rd | rs1 | AVL value | Effect on vl 866*d409305fSDimitry Andric //-------------------------------------------------------------- 867*d409305fSDimitry Andric // !X0 | X0 | VLMAX | Set vl to VLMAX 868*d409305fSDimitry Andric // X0 | X0 | Value in vl | Keep current vl, just change vtype. 869*d409305fSDimitry Andric bool RISCVDAGToDAGISel::selectVLOp(SDValue N, SDValue &VL) { 870*d409305fSDimitry Andric // If the VL value is a constant 0, manually select it to an ADDI with 0 871*d409305fSDimitry Andric // immediate to prevent the default selection path from matching it to X0. 872*d409305fSDimitry Andric auto *C = dyn_cast<ConstantSDNode>(N); 873*d409305fSDimitry Andric if (C && C->isNullValue()) 874*d409305fSDimitry Andric VL = SDValue(selectImm(CurDAG, SDLoc(N), 0, Subtarget->getXLenVT()), 0); 875*d409305fSDimitry Andric else 876*d409305fSDimitry Andric VL = N; 877*d409305fSDimitry Andric 878*d409305fSDimitry Andric return true; 879*d409305fSDimitry Andric } 880*d409305fSDimitry Andric 881e8d8bef9SDimitry Andric bool RISCVDAGToDAGISel::selectVSplat(SDValue N, SDValue &SplatVal) { 882e8d8bef9SDimitry Andric if (N.getOpcode() != ISD::SPLAT_VECTOR && 883e8d8bef9SDimitry Andric N.getOpcode() != RISCVISD::SPLAT_VECTOR_I64) 884e8d8bef9SDimitry Andric return false; 885e8d8bef9SDimitry Andric SplatVal = N.getOperand(0); 886979e22ffSDimitry Andric return true; 887979e22ffSDimitry Andric } 888e8d8bef9SDimitry Andric 889e8d8bef9SDimitry Andric bool RISCVDAGToDAGISel::selectVSplatSimm5(SDValue N, SDValue &SplatVal) { 890e8d8bef9SDimitry Andric if ((N.getOpcode() != ISD::SPLAT_VECTOR && 891e8d8bef9SDimitry Andric N.getOpcode() != RISCVISD::SPLAT_VECTOR_I64) || 892e8d8bef9SDimitry Andric !isa<ConstantSDNode>(N.getOperand(0))) 893979e22ffSDimitry Andric return false; 894e8d8bef9SDimitry Andric 895e8d8bef9SDimitry Andric int64_t SplatImm = cast<ConstantSDNode>(N.getOperand(0))->getSExtValue(); 896e8d8bef9SDimitry Andric 897e8d8bef9SDimitry Andric // Both ISD::SPLAT_VECTOR and RISCVISD::SPLAT_VECTOR_I64 share semantics when 898e8d8bef9SDimitry Andric // the operand type is wider than the resulting vector element type: an 899e8d8bef9SDimitry Andric // implicit truncation first takes place. Therefore, perform a manual 900e8d8bef9SDimitry Andric // truncation/sign-extension in order to ignore any truncated bits and catch 901e8d8bef9SDimitry Andric // any zero-extended immediate. 902e8d8bef9SDimitry Andric // For example, we wish to match (i8 -1) -> (XLenVT 255) as a simm5 by first 903e8d8bef9SDimitry Andric // sign-extending to (XLenVT -1). 904e8d8bef9SDimitry Andric auto XLenVT = Subtarget->getXLenVT(); 905e8d8bef9SDimitry Andric assert(XLenVT == N.getOperand(0).getSimpleValueType() && 906e8d8bef9SDimitry Andric "Unexpected splat operand type"); 907e8d8bef9SDimitry Andric auto EltVT = N.getValueType().getVectorElementType(); 908e8d8bef9SDimitry Andric if (EltVT.bitsLT(XLenVT)) { 909e8d8bef9SDimitry Andric SplatImm = SignExtend64(SplatImm, EltVT.getSizeInBits()); 910979e22ffSDimitry Andric } 911979e22ffSDimitry Andric 912e8d8bef9SDimitry Andric if (!isInt<5>(SplatImm)) 913e8d8bef9SDimitry Andric return false; 914979e22ffSDimitry Andric 915e8d8bef9SDimitry Andric SplatVal = CurDAG->getTargetConstant(SplatImm, SDLoc(N), XLenVT); 916979e22ffSDimitry Andric return true; 917979e22ffSDimitry Andric } 918e8d8bef9SDimitry Andric 919e8d8bef9SDimitry Andric bool RISCVDAGToDAGISel::selectVSplatUimm5(SDValue N, SDValue &SplatVal) { 920e8d8bef9SDimitry Andric if ((N.getOpcode() != ISD::SPLAT_VECTOR && 921e8d8bef9SDimitry Andric N.getOpcode() != RISCVISD::SPLAT_VECTOR_I64) || 922e8d8bef9SDimitry Andric !isa<ConstantSDNode>(N.getOperand(0))) 923979e22ffSDimitry Andric return false; 924979e22ffSDimitry Andric 925e8d8bef9SDimitry Andric int64_t SplatImm = cast<ConstantSDNode>(N.getOperand(0))->getSExtValue(); 926979e22ffSDimitry Andric 927e8d8bef9SDimitry Andric if (!isUInt<5>(SplatImm)) 928e8d8bef9SDimitry Andric return false; 929e8d8bef9SDimitry Andric 930e8d8bef9SDimitry Andric SplatVal = 931e8d8bef9SDimitry Andric CurDAG->getTargetConstant(SplatImm, SDLoc(N), Subtarget->getXLenVT()); 932e8d8bef9SDimitry Andric 933979e22ffSDimitry Andric return true; 934979e22ffSDimitry Andric } 935979e22ffSDimitry Andric 9360b57cec5SDimitry Andric // Merge an ADDI into the offset of a load/store instruction where possible. 9375ffd83dbSDimitry Andric // (load (addi base, off1), off2) -> (load base, off1+off2) 9385ffd83dbSDimitry Andric // (store val, (addi base, off1), off2) -> (store val, base, off1+off2) 9395ffd83dbSDimitry Andric // This is possible when off1+off2 fits a 12-bit immediate. 9400b57cec5SDimitry Andric void RISCVDAGToDAGISel::doPeepholeLoadStoreADDI() { 9410b57cec5SDimitry Andric SelectionDAG::allnodes_iterator Position(CurDAG->getRoot().getNode()); 9420b57cec5SDimitry Andric ++Position; 9430b57cec5SDimitry Andric 9440b57cec5SDimitry Andric while (Position != CurDAG->allnodes_begin()) { 9450b57cec5SDimitry Andric SDNode *N = &*--Position; 9460b57cec5SDimitry Andric // Skip dead nodes and any non-machine opcodes. 9470b57cec5SDimitry Andric if (N->use_empty() || !N->isMachineOpcode()) 9480b57cec5SDimitry Andric continue; 9490b57cec5SDimitry Andric 9500b57cec5SDimitry Andric int OffsetOpIdx; 9510b57cec5SDimitry Andric int BaseOpIdx; 9520b57cec5SDimitry Andric 9530b57cec5SDimitry Andric // Only attempt this optimisation for I-type loads and S-type stores. 9540b57cec5SDimitry Andric switch (N->getMachineOpcode()) { 9550b57cec5SDimitry Andric default: 9560b57cec5SDimitry Andric continue; 9570b57cec5SDimitry Andric case RISCV::LB: 9580b57cec5SDimitry Andric case RISCV::LH: 9590b57cec5SDimitry Andric case RISCV::LW: 9600b57cec5SDimitry Andric case RISCV::LBU: 9610b57cec5SDimitry Andric case RISCV::LHU: 9620b57cec5SDimitry Andric case RISCV::LWU: 9630b57cec5SDimitry Andric case RISCV::LD: 964e8d8bef9SDimitry Andric case RISCV::FLH: 9650b57cec5SDimitry Andric case RISCV::FLW: 9660b57cec5SDimitry Andric case RISCV::FLD: 9670b57cec5SDimitry Andric BaseOpIdx = 0; 9680b57cec5SDimitry Andric OffsetOpIdx = 1; 9690b57cec5SDimitry Andric break; 9700b57cec5SDimitry Andric case RISCV::SB: 9710b57cec5SDimitry Andric case RISCV::SH: 9720b57cec5SDimitry Andric case RISCV::SW: 9730b57cec5SDimitry Andric case RISCV::SD: 974e8d8bef9SDimitry Andric case RISCV::FSH: 9750b57cec5SDimitry Andric case RISCV::FSW: 9760b57cec5SDimitry Andric case RISCV::FSD: 9770b57cec5SDimitry Andric BaseOpIdx = 1; 9780b57cec5SDimitry Andric OffsetOpIdx = 2; 9790b57cec5SDimitry Andric break; 9800b57cec5SDimitry Andric } 9810b57cec5SDimitry Andric 9825ffd83dbSDimitry Andric if (!isa<ConstantSDNode>(N->getOperand(OffsetOpIdx))) 9830b57cec5SDimitry Andric continue; 9840b57cec5SDimitry Andric 9850b57cec5SDimitry Andric SDValue Base = N->getOperand(BaseOpIdx); 9860b57cec5SDimitry Andric 9870b57cec5SDimitry Andric // If the base is an ADDI, we can merge it in to the load/store. 9880b57cec5SDimitry Andric if (!Base.isMachineOpcode() || Base.getMachineOpcode() != RISCV::ADDI) 9890b57cec5SDimitry Andric continue; 9900b57cec5SDimitry Andric 9910b57cec5SDimitry Andric SDValue ImmOperand = Base.getOperand(1); 9925ffd83dbSDimitry Andric uint64_t Offset2 = N->getConstantOperandVal(OffsetOpIdx); 9930b57cec5SDimitry Andric 9940b57cec5SDimitry Andric if (auto Const = dyn_cast<ConstantSDNode>(ImmOperand)) { 9955ffd83dbSDimitry Andric int64_t Offset1 = Const->getSExtValue(); 9965ffd83dbSDimitry Andric int64_t CombinedOffset = Offset1 + Offset2; 9975ffd83dbSDimitry Andric if (!isInt<12>(CombinedOffset)) 9985ffd83dbSDimitry Andric continue; 9995ffd83dbSDimitry Andric ImmOperand = CurDAG->getTargetConstant(CombinedOffset, SDLoc(ImmOperand), 10005ffd83dbSDimitry Andric ImmOperand.getValueType()); 10010b57cec5SDimitry Andric } else if (auto GA = dyn_cast<GlobalAddressSDNode>(ImmOperand)) { 10025ffd83dbSDimitry Andric // If the off1 in (addi base, off1) is a global variable's address (its 10035ffd83dbSDimitry Andric // low part, really), then we can rely on the alignment of that variable 10045ffd83dbSDimitry Andric // to provide a margin of safety before off1 can overflow the 12 bits. 10055ffd83dbSDimitry Andric // Check if off2 falls within that margin; if so off1+off2 can't overflow. 10065ffd83dbSDimitry Andric const DataLayout &DL = CurDAG->getDataLayout(); 10075ffd83dbSDimitry Andric Align Alignment = GA->getGlobal()->getPointerAlignment(DL); 10085ffd83dbSDimitry Andric if (Offset2 != 0 && Alignment <= Offset2) 10095ffd83dbSDimitry Andric continue; 10105ffd83dbSDimitry Andric int64_t Offset1 = GA->getOffset(); 10115ffd83dbSDimitry Andric int64_t CombinedOffset = Offset1 + Offset2; 10120b57cec5SDimitry Andric ImmOperand = CurDAG->getTargetGlobalAddress( 10130b57cec5SDimitry Andric GA->getGlobal(), SDLoc(ImmOperand), ImmOperand.getValueType(), 10145ffd83dbSDimitry Andric CombinedOffset, GA->getTargetFlags()); 10155ffd83dbSDimitry Andric } else if (auto CP = dyn_cast<ConstantPoolSDNode>(ImmOperand)) { 10165ffd83dbSDimitry Andric // Ditto. 10175ffd83dbSDimitry Andric Align Alignment = CP->getAlign(); 10185ffd83dbSDimitry Andric if (Offset2 != 0 && Alignment <= Offset2) 10195ffd83dbSDimitry Andric continue; 10205ffd83dbSDimitry Andric int64_t Offset1 = CP->getOffset(); 10215ffd83dbSDimitry Andric int64_t CombinedOffset = Offset1 + Offset2; 10225ffd83dbSDimitry Andric ImmOperand = CurDAG->getTargetConstantPool( 10235ffd83dbSDimitry Andric CP->getConstVal(), ImmOperand.getValueType(), CP->getAlign(), 10245ffd83dbSDimitry Andric CombinedOffset, CP->getTargetFlags()); 10250b57cec5SDimitry Andric } else { 10260b57cec5SDimitry Andric continue; 10270b57cec5SDimitry Andric } 10280b57cec5SDimitry Andric 10290b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Folding add-immediate into mem-op:\nBase: "); 10300b57cec5SDimitry Andric LLVM_DEBUG(Base->dump(CurDAG)); 10310b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "\nN: "); 10320b57cec5SDimitry Andric LLVM_DEBUG(N->dump(CurDAG)); 10330b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "\n"); 10340b57cec5SDimitry Andric 10350b57cec5SDimitry Andric // Modify the offset operand of the load/store. 10360b57cec5SDimitry Andric if (BaseOpIdx == 0) // Load 10370b57cec5SDimitry Andric CurDAG->UpdateNodeOperands(N, Base.getOperand(0), ImmOperand, 10380b57cec5SDimitry Andric N->getOperand(2)); 10390b57cec5SDimitry Andric else // Store 10400b57cec5SDimitry Andric CurDAG->UpdateNodeOperands(N, N->getOperand(0), Base.getOperand(0), 10410b57cec5SDimitry Andric ImmOperand, N->getOperand(3)); 10420b57cec5SDimitry Andric 10430b57cec5SDimitry Andric // The add-immediate may now be dead, in which case remove it. 10440b57cec5SDimitry Andric if (Base.getNode()->use_empty()) 10450b57cec5SDimitry Andric CurDAG->RemoveDeadNode(Base.getNode()); 10460b57cec5SDimitry Andric } 10470b57cec5SDimitry Andric } 10480b57cec5SDimitry Andric 10490b57cec5SDimitry Andric // This pass converts a legalized DAG into a RISCV-specific DAG, ready 10500b57cec5SDimitry Andric // for instruction scheduling. 10510b57cec5SDimitry Andric FunctionPass *llvm::createRISCVISelDag(RISCVTargetMachine &TM) { 10520b57cec5SDimitry Andric return new RISCVDAGToDAGISel(TM); 10530b57cec5SDimitry Andric } 1054