1 | //===-- Mips16ISelDAGToDAG.cpp - A Dag to Dag Inst Selector for Mips16 ----===// |
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 | // Subclass of MipsDAGToDAGISel specialized for mips16. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "Mips16ISelDAGToDAG.h" |
14 | #include "MCTargetDesc/MipsBaseInfo.h" |
15 | #include "Mips.h" |
16 | #include "MipsMachineFunction.h" |
17 | #include "MipsRegisterInfo.h" |
18 | #include "llvm/CodeGen/MachineConstantPool.h" |
19 | #include "llvm/CodeGen/MachineFrameInfo.h" |
20 | #include "llvm/CodeGen/MachineFunction.h" |
21 | #include "llvm/CodeGen/MachineInstrBuilder.h" |
22 | #include "llvm/CodeGen/MachineRegisterInfo.h" |
23 | #include "llvm/CodeGen/SelectionDAGNodes.h" |
24 | #include "llvm/IR/CFG.h" |
25 | #include "llvm/IR/GlobalValue.h" |
26 | #include "llvm/IR/Instructions.h" |
27 | #include "llvm/IR/Intrinsics.h" |
28 | #include "llvm/IR/Type.h" |
29 | #include "llvm/Support/Debug.h" |
30 | #include "llvm/Support/ErrorHandling.h" |
31 | #include "llvm/Support/raw_ostream.h" |
32 | #include "llvm/Target/TargetMachine.h" |
33 | using namespace llvm; |
34 | |
35 | #define DEBUG_TYPE "mips-isel" |
36 | |
37 | bool Mips16DAGToDAGISel::runOnMachineFunction(MachineFunction &MF) { |
38 | Subtarget = &MF.getSubtarget<MipsSubtarget>(); |
39 | if (!Subtarget->inMips16Mode()) |
40 | return false; |
41 | return MipsDAGToDAGISel::runOnMachineFunction(MF); |
42 | } |
43 | /// Select multiply instructions. |
44 | std::pair<SDNode *, SDNode *> |
45 | Mips16DAGToDAGISel::selectMULT(SDNode *N, unsigned Opc, const SDLoc &DL, EVT Ty, |
46 | bool HasLo, bool HasHi) { |
47 | SDNode *Lo = nullptr, *Hi = nullptr; |
48 | SDNode *Mul = CurDAG->getMachineNode(Opcode: Opc, dl: DL, VT: MVT::Glue, Op1: N->getOperand(Num: 0), |
49 | Op2: N->getOperand(Num: 1)); |
50 | SDValue InGlue = SDValue(Mul, 0); |
51 | |
52 | if (HasLo) { |
53 | unsigned Opcode = Mips::Mflo16; |
54 | Lo = CurDAG->getMachineNode(Opcode, dl: DL, VT1: Ty, VT2: MVT::Glue, Ops: InGlue); |
55 | InGlue = SDValue(Lo, 1); |
56 | } |
57 | if (HasHi) { |
58 | unsigned Opcode = Mips::Mfhi16; |
59 | Hi = CurDAG->getMachineNode(Opcode, dl: DL, VT: Ty, Op1: InGlue); |
60 | } |
61 | return std::make_pair(x&: Lo, y&: Hi); |
62 | } |
63 | |
64 | void Mips16DAGToDAGISel::initGlobalBaseReg(MachineFunction &MF) { |
65 | MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>(); |
66 | |
67 | if (!MipsFI->globalBaseRegSet()) |
68 | return; |
69 | |
70 | MachineBasicBlock &MBB = MF.front(); |
71 | MachineBasicBlock::iterator I = MBB.begin(); |
72 | MachineRegisterInfo &RegInfo = MF.getRegInfo(); |
73 | const TargetInstrInfo &TII = *Subtarget->getInstrInfo(); |
74 | DebugLoc DL; |
75 | Register V0, V1, V2, GlobalBaseReg = MipsFI->getGlobalBaseReg(MF); |
76 | const TargetRegisterClass *RC = &Mips::CPU16RegsRegClass; |
77 | |
78 | V0 = RegInfo.createVirtualRegister(RegClass: RC); |
79 | V1 = RegInfo.createVirtualRegister(RegClass: RC); |
80 | V2 = RegInfo.createVirtualRegister(RegClass: RC); |
81 | |
82 | |
83 | BuildMI(BB&: MBB, I, MIMD: DL, MCID: TII.get(Opcode: Mips::LiRxImmX16), DestReg: V0) |
84 | .addExternalSymbol(FnName: "_gp_disp" , TargetFlags: MipsII::MO_ABS_HI); |
85 | BuildMI(BB&: MBB, I, MIMD: DL, MCID: TII.get(Opcode: Mips::AddiuRxPcImmX16), DestReg: V1) |
86 | .addExternalSymbol(FnName: "_gp_disp" , TargetFlags: MipsII::MO_ABS_LO); |
87 | |
88 | BuildMI(BB&: MBB, I, MIMD: DL, MCID: TII.get(Opcode: Mips::SllX16), DestReg: V2).addReg(RegNo: V0).addImm(Val: 16); |
89 | BuildMI(BB&: MBB, I, MIMD: DL, MCID: TII.get(Opcode: Mips::AdduRxRyRz16), DestReg: GlobalBaseReg) |
90 | .addReg(RegNo: V1) |
91 | .addReg(RegNo: V2); |
92 | } |
93 | |
94 | void Mips16DAGToDAGISel::processFunctionAfterISel(MachineFunction &MF) { |
95 | initGlobalBaseReg(MF); |
96 | } |
97 | |
98 | bool Mips16DAGToDAGISel::selectAddr(bool SPAllowed, SDValue Addr, SDValue &Base, |
99 | SDValue &Offset) { |
100 | SDLoc DL(Addr); |
101 | EVT ValTy = Addr.getValueType(); |
102 | |
103 | // if Address is FI, get the TargetFrameIndex. |
104 | if (SPAllowed) { |
105 | if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Val&: Addr)) { |
106 | Base = CurDAG->getTargetFrameIndex(FI: FIN->getIndex(), VT: ValTy); |
107 | Offset = CurDAG->getTargetConstant(Val: 0, DL, VT: ValTy); |
108 | return true; |
109 | } |
110 | } |
111 | // on PIC code Load GA |
112 | if (Addr.getOpcode() == MipsISD::Wrapper) { |
113 | Base = Addr.getOperand(i: 0); |
114 | Offset = Addr.getOperand(i: 1); |
115 | return true; |
116 | } |
117 | if (!TM.isPositionIndependent()) { |
118 | if ((Addr.getOpcode() == ISD::TargetExternalSymbol || |
119 | Addr.getOpcode() == ISD::TargetGlobalAddress)) |
120 | return false; |
121 | } |
122 | // Addresses of the form FI+const or FI|const |
123 | if (CurDAG->isBaseWithConstantOffset(Op: Addr)) { |
124 | auto *CN = cast<ConstantSDNode>(Val: Addr.getOperand(i: 1)); |
125 | if (isInt<16>(x: CN->getSExtValue())) { |
126 | // If the first operand is a FI, get the TargetFI Node |
127 | if (SPAllowed) { |
128 | if (FrameIndexSDNode *FIN = |
129 | dyn_cast<FrameIndexSDNode>(Val: Addr.getOperand(i: 0))) { |
130 | Base = CurDAG->getTargetFrameIndex(FI: FIN->getIndex(), VT: ValTy); |
131 | Offset = CurDAG->getTargetConstant(Val: CN->getZExtValue(), DL, VT: ValTy); |
132 | return true; |
133 | } |
134 | } |
135 | |
136 | Base = Addr.getOperand(i: 0); |
137 | Offset = CurDAG->getTargetConstant(Val: CN->getZExtValue(), DL, VT: ValTy); |
138 | return true; |
139 | } |
140 | } |
141 | // Operand is a result from an ADD. |
142 | if (Addr.getOpcode() == ISD::ADD) { |
143 | // When loading from constant pools, load the lower address part in |
144 | // the instruction itself. Example, instead of: |
145 | // lui $2, %hi($CPI1_0) |
146 | // addiu $2, $2, %lo($CPI1_0) |
147 | // lwc1 $f0, 0($2) |
148 | // Generate: |
149 | // lui $2, %hi($CPI1_0) |
150 | // lwc1 $f0, %lo($CPI1_0)($2) |
151 | if (Addr.getOperand(i: 1).getOpcode() == MipsISD::Lo || |
152 | Addr.getOperand(i: 1).getOpcode() == MipsISD::GPRel) { |
153 | SDValue Opnd0 = Addr.getOperand(i: 1).getOperand(i: 0); |
154 | if (isa<ConstantPoolSDNode>(Val: Opnd0) || isa<GlobalAddressSDNode>(Val: Opnd0) || |
155 | isa<JumpTableSDNode>(Val: Opnd0)) { |
156 | Base = Addr.getOperand(i: 0); |
157 | Offset = Opnd0; |
158 | return true; |
159 | } |
160 | } |
161 | } |
162 | Base = Addr; |
163 | Offset = CurDAG->getTargetConstant(Val: 0, DL, VT: ValTy); |
164 | return true; |
165 | } |
166 | |
167 | bool Mips16DAGToDAGISel::selectAddr16(SDValue Addr, SDValue &Base, |
168 | SDValue &Offset) { |
169 | return selectAddr(SPAllowed: false, Addr, Base, Offset); |
170 | } |
171 | |
172 | bool Mips16DAGToDAGISel::selectAddr16SP(SDValue Addr, SDValue &Base, |
173 | SDValue &Offset) { |
174 | return selectAddr(SPAllowed: true, Addr, Base, Offset); |
175 | } |
176 | |
177 | /// Select instructions not customized! Used for |
178 | /// expanded, promoted and normal instructions |
179 | bool Mips16DAGToDAGISel::trySelect(SDNode *Node) { |
180 | unsigned Opcode = Node->getOpcode(); |
181 | SDLoc DL(Node); |
182 | |
183 | /// |
184 | // Instruction Selection not handled by the auto-generated |
185 | // tablegen selection should be handled here. |
186 | /// |
187 | EVT NodeTy = Node->getValueType(ResNo: 0); |
188 | unsigned MultOpc; |
189 | |
190 | switch (Opcode) { |
191 | default: |
192 | break; |
193 | |
194 | /// Mul with two results |
195 | case ISD::SMUL_LOHI: |
196 | case ISD::UMUL_LOHI: { |
197 | MultOpc = (Opcode == ISD::UMUL_LOHI ? Mips::MultuRxRy16 : Mips::MultRxRy16); |
198 | std::pair<SDNode *, SDNode *> LoHi = |
199 | selectMULT(N: Node, Opc: MultOpc, DL, Ty: NodeTy, HasLo: true, HasHi: true); |
200 | if (!SDValue(Node, 0).use_empty()) |
201 | ReplaceUses(F: SDValue(Node, 0), T: SDValue(LoHi.first, 0)); |
202 | |
203 | if (!SDValue(Node, 1).use_empty()) |
204 | ReplaceUses(F: SDValue(Node, 1), T: SDValue(LoHi.second, 0)); |
205 | |
206 | CurDAG->RemoveDeadNode(N: Node); |
207 | return true; |
208 | } |
209 | |
210 | case ISD::MULHS: |
211 | case ISD::MULHU: { |
212 | MultOpc = (Opcode == ISD::MULHU ? Mips::MultuRxRy16 : Mips::MultRxRy16); |
213 | auto LoHi = selectMULT(N: Node, Opc: MultOpc, DL, Ty: NodeTy, HasLo: false, HasHi: true); |
214 | ReplaceNode(F: Node, T: LoHi.second); |
215 | return true; |
216 | } |
217 | } |
218 | |
219 | return false; |
220 | } |
221 | |
222 | Mips16DAGToDAGISelLegacy::Mips16DAGToDAGISelLegacy(MipsTargetMachine &TM, |
223 | CodeGenOptLevel OL) |
224 | : MipsDAGToDAGISelLegacy(std::make_unique<Mips16DAGToDAGISel>(args&: TM, args&: OL)) {} |
225 | |
226 | FunctionPass *llvm::createMips16ISelDag(MipsTargetMachine &TM, |
227 | CodeGenOptLevel OptLevel) { |
228 | return new Mips16DAGToDAGISelLegacy(TM, OptLevel); |
229 | } |
230 | |