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