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
Select(SDNode * Node)23 void LoongArchDAGToDAGISel::Select(SDNode *Node) {
24 // If we have a custom node, we have already selected.
25 if (Node->isMachineOpcode()) {
26 LLVM_DEBUG(dbgs() << "== "; Node->dump(CurDAG); dbgs() << "\n");
27 Node->setNodeId(-1);
28 return;
29 }
30
31 // Instruction Selection not handled by the auto-generated tablegen selection
32 // should be handled here.
33 unsigned Opcode = Node->getOpcode();
34 MVT GRLenVT = Subtarget->getGRLenVT();
35 SDLoc DL(Node);
36 MVT VT = Node->getSimpleValueType(0);
37
38 switch (Opcode) {
39 default:
40 break;
41 case ISD::Constant: {
42 int64_t Imm = cast<ConstantSDNode>(Node)->getSExtValue();
43 if (Imm == 0 && VT == GRLenVT) {
44 SDValue New = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), DL,
45 LoongArch::R0, GRLenVT);
46 ReplaceNode(Node, New.getNode());
47 return;
48 }
49 SDNode *Result = nullptr;
50 SDValue SrcReg = CurDAG->getRegister(LoongArch::R0, GRLenVT);
51 // The instructions in the sequence are handled here.
52 for (LoongArchMatInt::Inst &Inst : LoongArchMatInt::generateInstSeq(Imm)) {
53 SDValue SDImm = CurDAG->getTargetConstant(Inst.Imm, DL, GRLenVT);
54 if (Inst.Opc == LoongArch::LU12I_W)
55 Result = CurDAG->getMachineNode(LoongArch::LU12I_W, DL, GRLenVT, SDImm);
56 else
57 Result = CurDAG->getMachineNode(Inst.Opc, DL, GRLenVT, SrcReg, SDImm);
58 SrcReg = SDValue(Result, 0);
59 }
60
61 ReplaceNode(Node, Result);
62 return;
63 }
64 case ISD::FrameIndex: {
65 SDValue Imm = CurDAG->getTargetConstant(0, DL, GRLenVT);
66 int FI = cast<FrameIndexSDNode>(Node)->getIndex();
67 SDValue TFI = CurDAG->getTargetFrameIndex(FI, VT);
68 unsigned ADDIOp =
69 Subtarget->is64Bit() ? LoongArch::ADDI_D : LoongArch::ADDI_W;
70 ReplaceNode(Node, CurDAG->getMachineNode(ADDIOp, DL, VT, TFI, Imm));
71 return;
72 }
73 // TODO: Add selection nodes needed later.
74 }
75
76 // Select the default instruction.
77 SelectCode(Node);
78 }
79
SelectBaseAddr(SDValue Addr,SDValue & Base)80 bool LoongArchDAGToDAGISel::SelectBaseAddr(SDValue Addr, SDValue &Base) {
81 // If this is FrameIndex, select it directly. Otherwise just let it get
82 // selected to a register independently.
83 if (auto *FIN = dyn_cast<FrameIndexSDNode>(Addr))
84 Base =
85 CurDAG->getTargetFrameIndex(FIN->getIndex(), Subtarget->getGRLenVT());
86 else
87 Base = Addr;
88 return true;
89 }
90
selectShiftMask(SDValue N,unsigned ShiftWidth,SDValue & ShAmt)91 bool LoongArchDAGToDAGISel::selectShiftMask(SDValue N, unsigned ShiftWidth,
92 SDValue &ShAmt) {
93 // Shift instructions on LoongArch only read the lower 5 or 6 bits of the
94 // shift amount. If there is an AND on the shift amount, we can bypass it if
95 // it doesn't affect any of those bits.
96 if (N.getOpcode() == ISD::AND && isa<ConstantSDNode>(N.getOperand(1))) {
97 const APInt &AndMask = N->getConstantOperandAPInt(1);
98
99 // Since the max shift amount is a power of 2 we can subtract 1 to make a
100 // mask that covers the bits needed to represent all shift amounts.
101 assert(isPowerOf2_32(ShiftWidth) && "Unexpected max shift amount!");
102 APInt ShMask(AndMask.getBitWidth(), ShiftWidth - 1);
103
104 if (ShMask.isSubsetOf(AndMask)) {
105 ShAmt = N.getOperand(0);
106 return true;
107 }
108
109 // SimplifyDemandedBits may have optimized the mask so try restoring any
110 // bits that are known zero.
111 KnownBits Known = CurDAG->computeKnownBits(N->getOperand(0));
112 if (ShMask.isSubsetOf(AndMask | Known.Zero)) {
113 ShAmt = N.getOperand(0);
114 return true;
115 }
116 } else if (N.getOpcode() == LoongArchISD::BSTRPICK) {
117 // Similar to the above AND, if there is a BSTRPICK on the shift amount, we
118 // can bypass it.
119 assert(isPowerOf2_32(ShiftWidth) && "Unexpected max shift amount!");
120 assert(isa<ConstantSDNode>(N.getOperand(1)) && "Illegal msb operand!");
121 assert(isa<ConstantSDNode>(N.getOperand(2)) && "Illegal lsb operand!");
122 uint64_t msb = N.getConstantOperandVal(1), lsb = N.getConstantOperandVal(2);
123 if (lsb == 0 && Log2_32(ShiftWidth) <= msb + 1) {
124 ShAmt = N.getOperand(0);
125 return true;
126 }
127 } else if (N.getOpcode() == ISD::SUB &&
128 isa<ConstantSDNode>(N.getOperand(0))) {
129 uint64_t Imm = N.getConstantOperandVal(0);
130 // If we are shifting by N-X where N == 0 mod Size, then just shift by -X to
131 // generate a NEG instead of a SUB of a constant.
132 if (Imm != 0 && Imm % ShiftWidth == 0) {
133 SDLoc DL(N);
134 EVT VT = N.getValueType();
135 SDValue Zero =
136 CurDAG->getCopyFromReg(CurDAG->getEntryNode(), DL, LoongArch::R0, VT);
137 unsigned NegOpc = VT == MVT::i64 ? LoongArch::SUB_D : LoongArch::SUB_W;
138 MachineSDNode *Neg =
139 CurDAG->getMachineNode(NegOpc, DL, VT, Zero, N.getOperand(1));
140 ShAmt = SDValue(Neg, 0);
141 return true;
142 }
143 }
144
145 ShAmt = N;
146 return true;
147 }
148
selectSExti32(SDValue N,SDValue & Val)149 bool LoongArchDAGToDAGISel::selectSExti32(SDValue N, SDValue &Val) {
150 if (N.getOpcode() == ISD::SIGN_EXTEND_INREG &&
151 cast<VTSDNode>(N.getOperand(1))->getVT() == MVT::i32) {
152 Val = N.getOperand(0);
153 return true;
154 }
155 MVT VT = N.getSimpleValueType();
156 if (CurDAG->ComputeNumSignBits(N) > (VT.getSizeInBits() - 32)) {
157 Val = N;
158 return true;
159 }
160
161 return false;
162 }
163
selectZExti32(SDValue N,SDValue & Val)164 bool LoongArchDAGToDAGISel::selectZExti32(SDValue N, SDValue &Val) {
165 if (N.getOpcode() == ISD::AND) {
166 auto *C = dyn_cast<ConstantSDNode>(N.getOperand(1));
167 if (C && C->getZExtValue() == UINT64_C(0xFFFFFFFF)) {
168 Val = N.getOperand(0);
169 return true;
170 }
171 }
172 MVT VT = N.getSimpleValueType();
173 APInt Mask = APInt::getHighBitsSet(VT.getSizeInBits(), 32);
174 if (CurDAG->MaskedValueIsZero(N, Mask)) {
175 Val = N;
176 return true;
177 }
178
179 return false;
180 }
181
182 // This pass converts a legalized DAG into a LoongArch-specific DAG, ready
183 // for instruction scheduling.
createLoongArchISelDag(LoongArchTargetMachine & TM)184 FunctionPass *llvm::createLoongArchISelDag(LoongArchTargetMachine &TM) {
185 return new LoongArchDAGToDAGISel(TM);
186 }
187