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 // Fold constant addresses. 142 bool LoongArchDAGToDAGISel::SelectAddrConstant(SDValue Addr, SDValue &Base, 143 SDValue &Offset) { 144 SDLoc DL(Addr); 145 MVT VT = Addr.getSimpleValueType(); 146 147 if (!isa<ConstantSDNode>(Addr)) 148 return false; 149 150 // If the constant is a simm12, we can fold the whole constant and use R0 as 151 // the base. 152 int64_t CVal = cast<ConstantSDNode>(Addr)->getSExtValue(); 153 if (!isInt<12>(CVal)) 154 return false; 155 Base = CurDAG->getRegister(LoongArch::R0, VT); 156 Offset = CurDAG->getTargetConstant(SignExtend64<12>(CVal), DL, VT); 157 return true; 158 } 159 160 bool LoongArchDAGToDAGISel::selectNonFIBaseAddr(SDValue Addr, SDValue &Base) { 161 // If this is FrameIndex, don't select it. 162 if (isa<FrameIndexSDNode>(Addr)) 163 return false; 164 Base = Addr; 165 return true; 166 } 167 168 bool LoongArchDAGToDAGISel::selectShiftMask(SDValue N, unsigned ShiftWidth, 169 SDValue &ShAmt) { 170 // Shift instructions on LoongArch only read the lower 5 or 6 bits of the 171 // shift amount. If there is an AND on the shift amount, we can bypass it if 172 // it doesn't affect any of those bits. 173 if (N.getOpcode() == ISD::AND && isa<ConstantSDNode>(N.getOperand(1))) { 174 const APInt &AndMask = N->getConstantOperandAPInt(1); 175 176 // Since the max shift amount is a power of 2 we can subtract 1 to make a 177 // mask that covers the bits needed to represent all shift amounts. 178 assert(isPowerOf2_32(ShiftWidth) && "Unexpected max shift amount!"); 179 APInt ShMask(AndMask.getBitWidth(), ShiftWidth - 1); 180 181 if (ShMask.isSubsetOf(AndMask)) { 182 ShAmt = N.getOperand(0); 183 return true; 184 } 185 186 // SimplifyDemandedBits may have optimized the mask so try restoring any 187 // bits that are known zero. 188 KnownBits Known = CurDAG->computeKnownBits(N->getOperand(0)); 189 if (ShMask.isSubsetOf(AndMask | Known.Zero)) { 190 ShAmt = N.getOperand(0); 191 return true; 192 } 193 } else if (N.getOpcode() == LoongArchISD::BSTRPICK) { 194 // Similar to the above AND, if there is a BSTRPICK on the shift amount, we 195 // can bypass it. 196 assert(isPowerOf2_32(ShiftWidth) && "Unexpected max shift amount!"); 197 assert(isa<ConstantSDNode>(N.getOperand(1)) && "Illegal msb operand!"); 198 assert(isa<ConstantSDNode>(N.getOperand(2)) && "Illegal lsb operand!"); 199 uint64_t msb = N.getConstantOperandVal(1), lsb = N.getConstantOperandVal(2); 200 if (lsb == 0 && Log2_32(ShiftWidth) <= msb + 1) { 201 ShAmt = N.getOperand(0); 202 return true; 203 } 204 } else if (N.getOpcode() == ISD::SUB && 205 isa<ConstantSDNode>(N.getOperand(0))) { 206 uint64_t Imm = N.getConstantOperandVal(0); 207 // If we are shifting by N-X where N == 0 mod Size, then just shift by -X to 208 // generate a NEG instead of a SUB of a constant. 209 if (Imm != 0 && Imm % ShiftWidth == 0) { 210 SDLoc DL(N); 211 EVT VT = N.getValueType(); 212 SDValue Zero = 213 CurDAG->getCopyFromReg(CurDAG->getEntryNode(), DL, LoongArch::R0, VT); 214 unsigned NegOpc = VT == MVT::i64 ? LoongArch::SUB_D : LoongArch::SUB_W; 215 MachineSDNode *Neg = 216 CurDAG->getMachineNode(NegOpc, DL, VT, Zero, N.getOperand(1)); 217 ShAmt = SDValue(Neg, 0); 218 return true; 219 } 220 } 221 222 ShAmt = N; 223 return true; 224 } 225 226 bool LoongArchDAGToDAGISel::selectSExti32(SDValue N, SDValue &Val) { 227 if (N.getOpcode() == ISD::SIGN_EXTEND_INREG && 228 cast<VTSDNode>(N.getOperand(1))->getVT() == MVT::i32) { 229 Val = N.getOperand(0); 230 return true; 231 } 232 if (N.getOpcode() == LoongArchISD::BSTRPICK && 233 N.getConstantOperandVal(1) < UINT64_C(0X1F) && 234 N.getConstantOperandVal(2) == UINT64_C(0)) { 235 Val = N; 236 return true; 237 } 238 MVT VT = N.getSimpleValueType(); 239 if (CurDAG->ComputeNumSignBits(N) > (VT.getSizeInBits() - 32)) { 240 Val = N; 241 return true; 242 } 243 244 return false; 245 } 246 247 bool LoongArchDAGToDAGISel::selectZExti32(SDValue N, SDValue &Val) { 248 if (N.getOpcode() == ISD::AND) { 249 auto *C = dyn_cast<ConstantSDNode>(N.getOperand(1)); 250 if (C && C->getZExtValue() == UINT64_C(0xFFFFFFFF)) { 251 Val = N.getOperand(0); 252 return true; 253 } 254 } 255 MVT VT = N.getSimpleValueType(); 256 APInt Mask = APInt::getHighBitsSet(VT.getSizeInBits(), 32); 257 if (CurDAG->MaskedValueIsZero(N, Mask)) { 258 Val = N; 259 return true; 260 } 261 262 return false; 263 } 264 265 // This pass converts a legalized DAG into a LoongArch-specific DAG, ready 266 // for instruction scheduling. 267 FunctionPass *llvm::createLoongArchISelDag(LoongArchTargetMachine &TM) { 268 return new LoongArchDAGToDAGISel(TM); 269 } 270