1 //=- LoongArchISelDAGToDAG.cpp - A dag to dag inst selector for LoongArch -===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file defines an instruction selector for the LoongArch target. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "LoongArchISelDAGToDAG.h" 14 #include "LoongArchISelLowering.h" 15 #include "MCTargetDesc/LoongArchMCTargetDesc.h" 16 #include "MCTargetDesc/LoongArchMatInt.h" 17 #include "llvm/Support/KnownBits.h" 18 19 using namespace llvm; 20 21 #define DEBUG_TYPE "loongarch-isel" 22 #define PASS_NAME "LoongArch DAG->DAG Pattern Instruction Selection" 23 24 char LoongArchDAGToDAGISel::ID; 25 26 INITIALIZE_PASS(LoongArchDAGToDAGISel, DEBUG_TYPE, PASS_NAME, false, false) 27 28 void LoongArchDAGToDAGISel::Select(SDNode *Node) { 29 // If we have a custom node, we have already selected. 30 if (Node->isMachineOpcode()) { 31 LLVM_DEBUG(dbgs() << "== "; Node->dump(CurDAG); dbgs() << "\n"); 32 Node->setNodeId(-1); 33 return; 34 } 35 36 // Instruction Selection not handled by the auto-generated tablegen selection 37 // should be handled here. 38 unsigned Opcode = Node->getOpcode(); 39 MVT GRLenVT = Subtarget->getGRLenVT(); 40 SDLoc DL(Node); 41 MVT VT = Node->getSimpleValueType(0); 42 43 switch (Opcode) { 44 default: 45 break; 46 case ISD::Constant: { 47 int64_t Imm = cast<ConstantSDNode>(Node)->getSExtValue(); 48 if (Imm == 0 && VT == GRLenVT) { 49 SDValue New = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), DL, 50 LoongArch::R0, GRLenVT); 51 ReplaceNode(Node, New.getNode()); 52 return; 53 } 54 SDNode *Result = nullptr; 55 SDValue SrcReg = CurDAG->getRegister(LoongArch::R0, GRLenVT); 56 // The instructions in the sequence are handled here. 57 for (LoongArchMatInt::Inst &Inst : LoongArchMatInt::generateInstSeq(Imm)) { 58 SDValue SDImm = CurDAG->getTargetConstant(Inst.Imm, DL, GRLenVT); 59 if (Inst.Opc == LoongArch::LU12I_W) 60 Result = CurDAG->getMachineNode(LoongArch::LU12I_W, DL, GRLenVT, SDImm); 61 else 62 Result = CurDAG->getMachineNode(Inst.Opc, DL, GRLenVT, SrcReg, SDImm); 63 SrcReg = SDValue(Result, 0); 64 } 65 66 ReplaceNode(Node, Result); 67 return; 68 } 69 case ISD::FrameIndex: { 70 SDValue Imm = CurDAG->getTargetConstant(0, DL, GRLenVT); 71 int FI = cast<FrameIndexSDNode>(Node)->getIndex(); 72 SDValue TFI = CurDAG->getTargetFrameIndex(FI, VT); 73 unsigned ADDIOp = 74 Subtarget->is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W; 75 ReplaceNode(Node, CurDAG->getMachineNode(ADDIOp, DL, VT, TFI, Imm)); 76 return; 77 } 78 // TODO: Add selection nodes needed later. 79 } 80 81 // Select the default instruction. 82 SelectCode(Node); 83 } 84 85 bool LoongArchDAGToDAGISel::SelectInlineAsmMemoryOperand( 86 const SDValue &Op, unsigned ConstraintID, std::vector<SDValue> &OutOps) { 87 SDValue Base = Op; 88 SDValue Offset = 89 CurDAG->getTargetConstant(0, SDLoc(Op), Subtarget->getGRLenVT()); 90 switch (ConstraintID) { 91 default: 92 llvm_unreachable("unexpected asm memory constraint"); 93 // Reg+Reg addressing. 94 case InlineAsm::Constraint_k: 95 Base = Op.getOperand(0); 96 Offset = Op.getOperand(1); 97 break; 98 // Reg+simm12 addressing. 99 case InlineAsm::Constraint_m: 100 if (CurDAG->isBaseWithConstantOffset(Op)) { 101 ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Op.getOperand(1)); 102 if (isIntN(12, CN->getSExtValue())) { 103 Base = Op.getOperand(0); 104 Offset = CurDAG->getTargetConstant(CN->getZExtValue(), SDLoc(Op), 105 Op.getValueType()); 106 } 107 } 108 break; 109 // Reg+0 addressing. 110 case InlineAsm::Constraint_ZB: 111 break; 112 // Reg+(simm14<<2) addressing. 113 case InlineAsm::Constraint_ZC: 114 if (CurDAG->isBaseWithConstantOffset(Op)) { 115 ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Op.getOperand(1)); 116 if (isIntN(16, CN->getSExtValue()) && 117 isAligned(Align(4ULL), CN->getZExtValue())) { 118 Base = Op.getOperand(0); 119 Offset = CurDAG->getTargetConstant(CN->getZExtValue(), SDLoc(Op), 120 Op.getValueType()); 121 } 122 } 123 break; 124 } 125 OutOps.push_back(Base); 126 OutOps.push_back(Offset); 127 return false; 128 } 129 130 bool LoongArchDAGToDAGISel::SelectBaseAddr(SDValue Addr, SDValue &Base) { 131 // If this is FrameIndex, select it directly. Otherwise just let it get 132 // selected to a register independently. 133 if (auto *FIN = dyn_cast<FrameIndexSDNode>(Addr)) 134 Base = 135 CurDAG->getTargetFrameIndex(FIN->getIndex(), Subtarget->getGRLenVT()); 136 else 137 Base = Addr; 138 return true; 139 } 140 141 bool LoongArchDAGToDAGISel::selectNonFIBaseAddr(SDValue Addr, SDValue &Base) { 142 // If this is FrameIndex, don't select it. 143 if (isa<FrameIndexSDNode>(Addr)) 144 return false; 145 Base = Addr; 146 return true; 147 } 148 149 bool LoongArchDAGToDAGISel::selectShiftMask(SDValue N, unsigned ShiftWidth, 150 SDValue &ShAmt) { 151 // Shift instructions on LoongArch only read the lower 5 or 6 bits of the 152 // shift amount. If there is an AND on the shift amount, we can bypass it if 153 // it doesn't affect any of those bits. 154 if (N.getOpcode() == ISD::AND && isa<ConstantSDNode>(N.getOperand(1))) { 155 const APInt &AndMask = N->getConstantOperandAPInt(1); 156 157 // Since the max shift amount is a power of 2 we can subtract 1 to make a 158 // mask that covers the bits needed to represent all shift amounts. 159 assert(isPowerOf2_32(ShiftWidth) && "Unexpected max shift amount!"); 160 APInt ShMask(AndMask.getBitWidth(), ShiftWidth - 1); 161 162 if (ShMask.isSubsetOf(AndMask)) { 163 ShAmt = N.getOperand(0); 164 return true; 165 } 166 167 // SimplifyDemandedBits may have optimized the mask so try restoring any 168 // bits that are known zero. 169 KnownBits Known = CurDAG->computeKnownBits(N->getOperand(0)); 170 if (ShMask.isSubsetOf(AndMask | Known.Zero)) { 171 ShAmt = N.getOperand(0); 172 return true; 173 } 174 } else if (N.getOpcode() == LoongArchISD::BSTRPICK) { 175 // Similar to the above AND, if there is a BSTRPICK on the shift amount, we 176 // can bypass it. 177 assert(isPowerOf2_32(ShiftWidth) && "Unexpected max shift amount!"); 178 assert(isa<ConstantSDNode>(N.getOperand(1)) && "Illegal msb operand!"); 179 assert(isa<ConstantSDNode>(N.getOperand(2)) && "Illegal lsb operand!"); 180 uint64_t msb = N.getConstantOperandVal(1), lsb = N.getConstantOperandVal(2); 181 if (lsb == 0 && Log2_32(ShiftWidth) <= msb + 1) { 182 ShAmt = N.getOperand(0); 183 return true; 184 } 185 } else if (N.getOpcode() == ISD::SUB && 186 isa<ConstantSDNode>(N.getOperand(0))) { 187 uint64_t Imm = N.getConstantOperandVal(0); 188 // If we are shifting by N-X where N == 0 mod Size, then just shift by -X to 189 // generate a NEG instead of a SUB of a constant. 190 if (Imm != 0 && Imm % ShiftWidth == 0) { 191 SDLoc DL(N); 192 EVT VT = N.getValueType(); 193 SDValue Zero = 194 CurDAG->getCopyFromReg(CurDAG->getEntryNode(), DL, LoongArch::R0, VT); 195 unsigned NegOpc = VT == MVT::i64 ? LoongArch::SUB_D : LoongArch::SUB_W; 196 MachineSDNode *Neg = 197 CurDAG->getMachineNode(NegOpc, DL, VT, Zero, N.getOperand(1)); 198 ShAmt = SDValue(Neg, 0); 199 return true; 200 } 201 } 202 203 ShAmt = N; 204 return true; 205 } 206 207 bool LoongArchDAGToDAGISel::selectSExti32(SDValue N, SDValue &Val) { 208 if (N.getOpcode() == ISD::SIGN_EXTEND_INREG && 209 cast<VTSDNode>(N.getOperand(1))->getVT() == MVT::i32) { 210 Val = N.getOperand(0); 211 return true; 212 } 213 if (N.getOpcode() == LoongArchISD::BSTRPICK && 214 N.getConstantOperandVal(1) < UINT64_C(0X1F) && 215 N.getConstantOperandVal(2) == UINT64_C(0)) { 216 Val = N; 217 return true; 218 } 219 MVT VT = N.getSimpleValueType(); 220 if (CurDAG->ComputeNumSignBits(N) > (VT.getSizeInBits() - 32)) { 221 Val = N; 222 return true; 223 } 224 225 return false; 226 } 227 228 bool LoongArchDAGToDAGISel::selectZExti32(SDValue N, SDValue &Val) { 229 if (N.getOpcode() == ISD::AND) { 230 auto *C = dyn_cast<ConstantSDNode>(N.getOperand(1)); 231 if (C && C->getZExtValue() == UINT64_C(0xFFFFFFFF)) { 232 Val = N.getOperand(0); 233 return true; 234 } 235 } 236 MVT VT = N.getSimpleValueType(); 237 APInt Mask = APInt::getHighBitsSet(VT.getSizeInBits(), 32); 238 if (CurDAG->MaskedValueIsZero(N, Mask)) { 239 Val = N; 240 return true; 241 } 242 243 return false; 244 } 245 246 // This pass converts a legalized DAG into a LoongArch-specific DAG, ready 247 // for instruction scheduling. 248 FunctionPass *llvm::createLoongArchISelDag(LoongArchTargetMachine &TM) { 249 return new LoongArchDAGToDAGISel(TM); 250 } 251