xref: /llvm-project/llvm/lib/Target/LoongArch/LoongArchISelDAGToDAG.cpp (revision 84220eccb6ce5413f9782590b3877bd689c9b43c)
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