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