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