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