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