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 #include "llvm/Support/raw_ostream.h" 19 20 using namespace llvm; 21 22 #define DEBUG_TYPE "loongarch-isel" 23 #define PASS_NAME "LoongArch DAG->DAG Pattern Instruction Selection" 24 25 char LoongArchDAGToDAGISelLegacy::ID; 26 27 LoongArchDAGToDAGISelLegacy::LoongArchDAGToDAGISelLegacy( 28 LoongArchTargetMachine &TM) 29 : SelectionDAGISelLegacy(ID, std::make_unique<LoongArchDAGToDAGISel>(TM)) {} 30 31 INITIALIZE_PASS(LoongArchDAGToDAGISelLegacy, DEBUG_TYPE, PASS_NAME, false, 32 false) 33 34 void LoongArchDAGToDAGISel::Select(SDNode *Node) { 35 // If we have a custom node, we have already selected. 36 if (Node->isMachineOpcode()) { 37 LLVM_DEBUG(dbgs() << "== "; Node->dump(CurDAG); dbgs() << "\n"); 38 Node->setNodeId(-1); 39 return; 40 } 41 42 // Instruction Selection not handled by the auto-generated tablegen selection 43 // should be handled here. 44 unsigned Opcode = Node->getOpcode(); 45 MVT GRLenVT = Subtarget->getGRLenVT(); 46 SDLoc DL(Node); 47 MVT VT = Node->getSimpleValueType(0); 48 49 switch (Opcode) { 50 default: 51 break; 52 case ISD::Constant: { 53 int64_t Imm = cast<ConstantSDNode>(Node)->getSExtValue(); 54 if (Imm == 0 && VT == GRLenVT) { 55 SDValue New = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), DL, 56 LoongArch::R0, GRLenVT); 57 ReplaceNode(Node, New.getNode()); 58 return; 59 } 60 SDNode *Result = nullptr; 61 SDValue SrcReg = CurDAG->getRegister(LoongArch::R0, GRLenVT); 62 // The instructions in the sequence are handled here. 63 for (LoongArchMatInt::Inst &Inst : LoongArchMatInt::generateInstSeq(Imm)) { 64 SDValue SDImm = CurDAG->getTargetConstant(Inst.Imm, DL, GRLenVT); 65 if (Inst.Opc == LoongArch::LU12I_W) 66 Result = CurDAG->getMachineNode(LoongArch::LU12I_W, DL, GRLenVT, SDImm); 67 else 68 Result = CurDAG->getMachineNode(Inst.Opc, DL, GRLenVT, SrcReg, SDImm); 69 SrcReg = SDValue(Result, 0); 70 } 71 72 ReplaceNode(Node, Result); 73 return; 74 } 75 case ISD::FrameIndex: { 76 SDValue Imm = CurDAG->getTargetConstant(0, DL, GRLenVT); 77 int FI = cast<FrameIndexSDNode>(Node)->getIndex(); 78 SDValue TFI = CurDAG->getTargetFrameIndex(FI, VT); 79 unsigned ADDIOp = 80 Subtarget->is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W; 81 ReplaceNode(Node, CurDAG->getMachineNode(ADDIOp, DL, VT, TFI, Imm)); 82 return; 83 } 84 case ISD::BITCAST: { 85 if (VT.is128BitVector() || VT.is256BitVector()) { 86 ReplaceUses(SDValue(Node, 0), Node->getOperand(0)); 87 CurDAG->RemoveDeadNode(Node); 88 return; 89 } 90 break; 91 } 92 case ISD::BUILD_VECTOR: { 93 // Select appropriate [x]vrepli.[bhwd] instructions for constant splats of 94 // 128/256-bit when LSX/LASX is enabled. 95 BuildVectorSDNode *BVN = cast<BuildVectorSDNode>(Node); 96 APInt SplatValue, SplatUndef; 97 unsigned SplatBitSize; 98 bool HasAnyUndefs; 99 unsigned Op; 100 EVT ViaVecTy; 101 bool Is128Vec = BVN->getValueType(0).is128BitVector(); 102 bool Is256Vec = BVN->getValueType(0).is256BitVector(); 103 104 if (!Subtarget->hasExtLSX() || (!Is128Vec && !Is256Vec)) 105 break; 106 if (!BVN->isConstantSplat(SplatValue, SplatUndef, SplatBitSize, 107 HasAnyUndefs, 8)) 108 break; 109 110 switch (SplatBitSize) { 111 default: 112 break; 113 case 8: 114 Op = Is256Vec ? LoongArch::PseudoXVREPLI_B : LoongArch::PseudoVREPLI_B; 115 ViaVecTy = Is256Vec ? MVT::v32i8 : MVT::v16i8; 116 break; 117 case 16: 118 Op = Is256Vec ? LoongArch::PseudoXVREPLI_H : LoongArch::PseudoVREPLI_H; 119 ViaVecTy = Is256Vec ? MVT::v16i16 : MVT::v8i16; 120 break; 121 case 32: 122 Op = Is256Vec ? LoongArch::PseudoXVREPLI_W : LoongArch::PseudoVREPLI_W; 123 ViaVecTy = Is256Vec ? MVT::v8i32 : MVT::v4i32; 124 break; 125 case 64: 126 Op = Is256Vec ? LoongArch::PseudoXVREPLI_D : LoongArch::PseudoVREPLI_D; 127 ViaVecTy = Is256Vec ? MVT::v4i64 : MVT::v2i64; 128 break; 129 } 130 131 SDNode *Res; 132 // If we have a signed 10 bit integer, we can splat it directly. 133 if (SplatValue.isSignedIntN(10)) { 134 SDValue Imm = CurDAG->getTargetConstant(SplatValue, DL, 135 ViaVecTy.getVectorElementType()); 136 Res = CurDAG->getMachineNode(Op, DL, ViaVecTy, Imm); 137 ReplaceNode(Node, Res); 138 return; 139 } 140 break; 141 } 142 } 143 144 // Select the default instruction. 145 SelectCode(Node); 146 } 147 148 bool LoongArchDAGToDAGISel::SelectInlineAsmMemoryOperand( 149 const SDValue &Op, InlineAsm::ConstraintCode ConstraintID, 150 std::vector<SDValue> &OutOps) { 151 SDValue Base = Op; 152 SDValue Offset = 153 CurDAG->getTargetConstant(0, SDLoc(Op), Subtarget->getGRLenVT()); 154 switch (ConstraintID) { 155 default: 156 llvm_unreachable("unexpected asm memory constraint"); 157 // Reg+Reg addressing. 158 case InlineAsm::ConstraintCode::k: 159 Base = Op.getOperand(0); 160 Offset = Op.getOperand(1); 161 break; 162 // Reg+simm12 addressing. 163 case InlineAsm::ConstraintCode::m: 164 if (CurDAG->isBaseWithConstantOffset(Op)) { 165 ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Op.getOperand(1)); 166 if (isIntN(12, CN->getSExtValue())) { 167 Base = Op.getOperand(0); 168 Offset = CurDAG->getTargetConstant(CN->getZExtValue(), SDLoc(Op), 169 Op.getValueType()); 170 } 171 } 172 break; 173 // Reg+0 addressing. 174 case InlineAsm::ConstraintCode::ZB: 175 break; 176 // Reg+(simm14<<2) addressing. 177 case InlineAsm::ConstraintCode::ZC: 178 if (CurDAG->isBaseWithConstantOffset(Op)) { 179 ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Op.getOperand(1)); 180 if (isIntN(16, CN->getSExtValue()) && 181 isAligned(Align(4ULL), CN->getZExtValue())) { 182 Base = Op.getOperand(0); 183 Offset = CurDAG->getTargetConstant(CN->getZExtValue(), SDLoc(Op), 184 Op.getValueType()); 185 } 186 } 187 break; 188 } 189 OutOps.push_back(Base); 190 OutOps.push_back(Offset); 191 return false; 192 } 193 194 bool LoongArchDAGToDAGISel::SelectBaseAddr(SDValue Addr, SDValue &Base) { 195 // If this is FrameIndex, select it directly. Otherwise just let it get 196 // selected to a register independently. 197 if (auto *FIN = dyn_cast<FrameIndexSDNode>(Addr)) 198 Base = 199 CurDAG->getTargetFrameIndex(FIN->getIndex(), Subtarget->getGRLenVT()); 200 else 201 Base = Addr; 202 return true; 203 } 204 205 // Fold constant addresses. 206 bool LoongArchDAGToDAGISel::SelectAddrConstant(SDValue Addr, SDValue &Base, 207 SDValue &Offset) { 208 SDLoc DL(Addr); 209 MVT VT = Addr.getSimpleValueType(); 210 211 if (!isa<ConstantSDNode>(Addr)) 212 return false; 213 214 // If the constant is a simm12, we can fold the whole constant and use R0 as 215 // the base. 216 int64_t CVal = cast<ConstantSDNode>(Addr)->getSExtValue(); 217 if (!isInt<12>(CVal)) 218 return false; 219 Base = CurDAG->getRegister(LoongArch::R0, VT); 220 Offset = CurDAG->getTargetConstant(SignExtend64<12>(CVal), DL, VT); 221 return true; 222 } 223 224 bool LoongArchDAGToDAGISel::selectNonFIBaseAddr(SDValue Addr, SDValue &Base) { 225 // If this is FrameIndex, don't select it. 226 if (isa<FrameIndexSDNode>(Addr)) 227 return false; 228 Base = Addr; 229 return true; 230 } 231 232 bool LoongArchDAGToDAGISel::selectShiftMask(SDValue N, unsigned ShiftWidth, 233 SDValue &ShAmt) { 234 // Shift instructions on LoongArch only read the lower 5 or 6 bits of the 235 // shift amount. If there is an AND on the shift amount, we can bypass it if 236 // it doesn't affect any of those bits. 237 if (N.getOpcode() == ISD::AND && isa<ConstantSDNode>(N.getOperand(1))) { 238 const APInt &AndMask = N->getConstantOperandAPInt(1); 239 240 // Since the max shift amount is a power of 2 we can subtract 1 to make a 241 // mask that covers the bits needed to represent all shift amounts. 242 assert(isPowerOf2_32(ShiftWidth) && "Unexpected max shift amount!"); 243 APInt ShMask(AndMask.getBitWidth(), ShiftWidth - 1); 244 245 if (ShMask.isSubsetOf(AndMask)) { 246 ShAmt = N.getOperand(0); 247 return true; 248 } 249 250 // SimplifyDemandedBits may have optimized the mask so try restoring any 251 // bits that are known zero. 252 KnownBits Known = CurDAG->computeKnownBits(N->getOperand(0)); 253 if (ShMask.isSubsetOf(AndMask | Known.Zero)) { 254 ShAmt = N.getOperand(0); 255 return true; 256 } 257 } else if (N.getOpcode() == LoongArchISD::BSTRPICK) { 258 // Similar to the above AND, if there is a BSTRPICK on the shift amount, we 259 // can bypass it. 260 assert(isPowerOf2_32(ShiftWidth) && "Unexpected max shift amount!"); 261 assert(isa<ConstantSDNode>(N.getOperand(1)) && "Illegal msb operand!"); 262 assert(isa<ConstantSDNode>(N.getOperand(2)) && "Illegal lsb operand!"); 263 uint64_t msb = N.getConstantOperandVal(1), lsb = N.getConstantOperandVal(2); 264 if (lsb == 0 && Log2_32(ShiftWidth) <= msb + 1) { 265 ShAmt = N.getOperand(0); 266 return true; 267 } 268 } else if (N.getOpcode() == ISD::SUB && 269 isa<ConstantSDNode>(N.getOperand(0))) { 270 uint64_t Imm = N.getConstantOperandVal(0); 271 // If we are shifting by N-X where N == 0 mod Size, then just shift by -X to 272 // generate a NEG instead of a SUB of a constant. 273 if (Imm != 0 && Imm % ShiftWidth == 0) { 274 SDLoc DL(N); 275 EVT VT = N.getValueType(); 276 SDValue Zero = 277 CurDAG->getCopyFromReg(CurDAG->getEntryNode(), DL, LoongArch::R0, VT); 278 unsigned NegOpc = VT == MVT::i64 ? LoongArch::SUB_D : LoongArch::SUB_W; 279 MachineSDNode *Neg = 280 CurDAG->getMachineNode(NegOpc, DL, VT, Zero, N.getOperand(1)); 281 ShAmt = SDValue(Neg, 0); 282 return true; 283 } 284 } 285 286 ShAmt = N; 287 return true; 288 } 289 290 bool LoongArchDAGToDAGISel::selectSExti32(SDValue N, SDValue &Val) { 291 if (N.getOpcode() == ISD::SIGN_EXTEND_INREG && 292 cast<VTSDNode>(N.getOperand(1))->getVT() == MVT::i32) { 293 Val = N.getOperand(0); 294 return true; 295 } 296 if (N.getOpcode() == LoongArchISD::BSTRPICK && 297 N.getConstantOperandVal(1) < UINT64_C(0X1F) && 298 N.getConstantOperandVal(2) == UINT64_C(0)) { 299 Val = N; 300 return true; 301 } 302 MVT VT = N.getSimpleValueType(); 303 if (CurDAG->ComputeNumSignBits(N) > (VT.getSizeInBits() - 32)) { 304 Val = N; 305 return true; 306 } 307 308 return false; 309 } 310 311 bool LoongArchDAGToDAGISel::selectZExti32(SDValue N, SDValue &Val) { 312 if (N.getOpcode() == ISD::AND) { 313 auto *C = dyn_cast<ConstantSDNode>(N.getOperand(1)); 314 if (C && C->getZExtValue() == UINT64_C(0xFFFFFFFF)) { 315 Val = N.getOperand(0); 316 return true; 317 } 318 } 319 MVT VT = N.getSimpleValueType(); 320 APInt Mask = APInt::getHighBitsSet(VT.getSizeInBits(), 32); 321 if (CurDAG->MaskedValueIsZero(N, Mask)) { 322 Val = N; 323 return true; 324 } 325 326 return false; 327 } 328 329 bool LoongArchDAGToDAGISel::selectVSplat(SDNode *N, APInt &Imm, 330 unsigned MinSizeInBits) const { 331 if (!Subtarget->hasExtLSX()) 332 return false; 333 334 BuildVectorSDNode *Node = dyn_cast<BuildVectorSDNode>(N); 335 336 if (!Node) 337 return false; 338 339 APInt SplatValue, SplatUndef; 340 unsigned SplatBitSize; 341 bool HasAnyUndefs; 342 343 if (!Node->isConstantSplat(SplatValue, SplatUndef, SplatBitSize, HasAnyUndefs, 344 MinSizeInBits, /*IsBigEndian=*/false)) 345 return false; 346 347 Imm = SplatValue; 348 349 return true; 350 } 351 352 template <unsigned ImmBitSize, bool IsSigned> 353 bool LoongArchDAGToDAGISel::selectVSplatImm(SDValue N, SDValue &SplatVal) { 354 APInt ImmValue; 355 EVT EltTy = N->getValueType(0).getVectorElementType(); 356 357 if (N->getOpcode() == ISD::BITCAST) 358 N = N->getOperand(0); 359 360 if (selectVSplat(N.getNode(), ImmValue, EltTy.getSizeInBits()) && 361 ImmValue.getBitWidth() == EltTy.getSizeInBits()) { 362 if (IsSigned && ImmValue.isSignedIntN(ImmBitSize)) { 363 SplatVal = CurDAG->getTargetConstant(ImmValue.getSExtValue(), SDLoc(N), 364 Subtarget->getGRLenVT()); 365 return true; 366 } 367 if (!IsSigned && ImmValue.isIntN(ImmBitSize)) { 368 SplatVal = CurDAG->getTargetConstant(ImmValue.getZExtValue(), SDLoc(N), 369 Subtarget->getGRLenVT()); 370 return true; 371 } 372 } 373 374 return false; 375 } 376 377 bool LoongArchDAGToDAGISel::selectVSplatUimmInvPow2(SDValue N, 378 SDValue &SplatImm) const { 379 APInt ImmValue; 380 EVT EltTy = N->getValueType(0).getVectorElementType(); 381 382 if (N->getOpcode() == ISD::BITCAST) 383 N = N->getOperand(0); 384 385 if (selectVSplat(N.getNode(), ImmValue, EltTy.getSizeInBits()) && 386 ImmValue.getBitWidth() == EltTy.getSizeInBits()) { 387 int32_t Log2 = (~ImmValue).exactLogBase2(); 388 389 if (Log2 != -1) { 390 SplatImm = CurDAG->getTargetConstant(Log2, SDLoc(N), EltTy); 391 return true; 392 } 393 } 394 395 return false; 396 } 397 398 bool LoongArchDAGToDAGISel::selectVSplatUimmPow2(SDValue N, 399 SDValue &SplatImm) const { 400 APInt ImmValue; 401 EVT EltTy = N->getValueType(0).getVectorElementType(); 402 403 if (N->getOpcode() == ISD::BITCAST) 404 N = N->getOperand(0); 405 406 if (selectVSplat(N.getNode(), ImmValue, EltTy.getSizeInBits()) && 407 ImmValue.getBitWidth() == EltTy.getSizeInBits()) { 408 int32_t Log2 = ImmValue.exactLogBase2(); 409 410 if (Log2 != -1) { 411 SplatImm = CurDAG->getTargetConstant(Log2, SDLoc(N), EltTy); 412 return true; 413 } 414 } 415 416 return false; 417 } 418 419 // This pass converts a legalized DAG into a LoongArch-specific DAG, ready 420 // for instruction scheduling. 421 FunctionPass *llvm::createLoongArchISelDag(LoongArchTargetMachine &TM) { 422 return new LoongArchDAGToDAGISelLegacy(TM); 423 } 424