1 //===- MipsLegalizerInfo.cpp ------------------------------------*- C++ -*-===//
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 /// \file
9 /// This file implements the targeting of the Machinelegalizer class for Mips.
10 /// \todo This should be generated by TableGen.
11 //===----------------------------------------------------------------------===//
12 
13 #include "MipsLegalizerInfo.h"
14 #include "MipsTargetMachine.h"
15 #include "llvm/CodeGen/GlobalISel/LegalizerHelper.h"
16 
17 using namespace llvm;
18 
19 struct TypesAndMemOps {
20   LLT ValTy;
21   LLT PtrTy;
22   unsigned MemSize;
23   bool MustBeNaturallyAligned;
24 };
25 
26 static bool
27 CheckTy0Ty1MemSizeAlign(const LegalityQuery &Query,
28                         std::initializer_list<TypesAndMemOps> SupportedValues) {
29   for (auto &Val : SupportedValues) {
30     if (Val.ValTy != Query.Types[0])
31       continue;
32     if (Val.PtrTy != Query.Types[1])
33       continue;
34     if (Val.MemSize != Query.MMODescrs[0].SizeInBits)
35       continue;
36     if (Val.MustBeNaturallyAligned &&
37         Query.MMODescrs[0].SizeInBits % Query.MMODescrs[0].AlignInBits != 0)
38       continue;
39     return true;
40   }
41   return false;
42 }
43 
44 MipsLegalizerInfo::MipsLegalizerInfo(const MipsSubtarget &ST) {
45   using namespace TargetOpcode;
46 
47   const LLT s1 = LLT::scalar(1);
48   const LLT s32 = LLT::scalar(32);
49   const LLT s64 = LLT::scalar(64);
50   const LLT v16s8 = LLT::vector(16, 8);
51   const LLT v8s16 = LLT::vector(8, 16);
52   const LLT v4s32 = LLT::vector(4, 32);
53   const LLT v2s64 = LLT::vector(2, 64);
54   const LLT p0 = LLT::pointer(0, 32);
55 
56   getActionDefinitionsBuilder({G_ADD, G_SUB, G_MUL})
57       .legalFor({s32})
58       .clampScalar(0, s32, s32);
59 
60   getActionDefinitionsBuilder({G_UADDO, G_UADDE, G_USUBO, G_USUBE, G_UMULO})
61       .lowerFor({{s32, s1}});
62 
63   getActionDefinitionsBuilder(G_UMULH)
64       .legalFor({s32})
65       .maxScalar(0, s32);
66 
67   getActionDefinitionsBuilder({G_LOAD, G_STORE})
68       .legalIf([=, &ST](const LegalityQuery &Query) {
69         if (CheckTy0Ty1MemSizeAlign(Query, {{s32, p0, 8, ST.hasMips32r6()},
70                                             {s32, p0, 16, ST.hasMips32r6()},
71                                             {s32, p0, 32, ST.hasMips32r6()},
72                                             {p0, p0, 32, ST.hasMips32r6()},
73                                             {s64, p0, 64, ST.hasMips32r6()}}))
74           return true;
75         if (ST.hasMSA() &&
76             CheckTy0Ty1MemSizeAlign(Query, {{v16s8, p0, 128, false},
77                                             {v8s16, p0, 128, false},
78                                             {v4s32, p0, 128, false},
79                                             {v2s64, p0, 128, false}}))
80           return true;
81         return false;
82       })
83       .minScalar(0, s32);
84 
85   getActionDefinitionsBuilder(G_IMPLICIT_DEF)
86       .legalFor({s32, s64});
87 
88   getActionDefinitionsBuilder(G_UNMERGE_VALUES)
89      .legalFor({{s32, s64}});
90 
91   getActionDefinitionsBuilder(G_MERGE_VALUES)
92      .legalFor({{s64, s32}});
93 
94   getActionDefinitionsBuilder({G_ZEXTLOAD, G_SEXTLOAD})
95       .legalForTypesWithMemDesc({{s32, p0, 8, 8},
96                                  {s32, p0, 16, 8}})
97       .clampScalar(0, s32, s32);
98 
99   getActionDefinitionsBuilder({G_ZEXT, G_SEXT})
100       .legalIf([](const LegalityQuery &Query) { return false; })
101       .maxScalar(0, s32);
102 
103   getActionDefinitionsBuilder(G_TRUNC)
104       .legalIf([](const LegalityQuery &Query) { return false; })
105       .maxScalar(1, s32);
106 
107   getActionDefinitionsBuilder(G_SELECT)
108       .legalForCartesianProduct({p0, s32, s64}, {s32})
109       .minScalar(0, s32)
110       .minScalar(1, s32);
111 
112   getActionDefinitionsBuilder(G_BRCOND)
113       .legalFor({s32})
114       .minScalar(0, s32);
115 
116   getActionDefinitionsBuilder(G_BRJT)
117       .legalFor({{p0, s32}});
118 
119   getActionDefinitionsBuilder(G_BRINDIRECT)
120       .legalFor({p0});
121 
122   getActionDefinitionsBuilder(G_PHI)
123       .legalFor({p0, s32, s64})
124       .minScalar(0, s32);
125 
126   getActionDefinitionsBuilder({G_AND, G_OR, G_XOR})
127       .legalFor({s32})
128       .clampScalar(0, s32, s32);
129 
130   getActionDefinitionsBuilder({G_SDIV, G_SREM, G_UREM, G_UDIV})
131       .legalFor({s32})
132       .minScalar(0, s32)
133       .libcallFor({s64});
134 
135   getActionDefinitionsBuilder({G_SHL, G_ASHR, G_LSHR})
136       .legalFor({{s32, s32}})
137       .clampScalar(1, s32, s32)
138       .clampScalar(0, s32, s32);
139 
140   getActionDefinitionsBuilder(G_ICMP)
141       .legalForCartesianProduct({s32}, {s32, p0})
142       .clampScalar(1, s32, s32)
143       .minScalar(0, s32);
144 
145   getActionDefinitionsBuilder(G_CONSTANT)
146       .legalFor({s32})
147       .clampScalar(0, s32, s32);
148 
149   getActionDefinitionsBuilder({G_GEP, G_INTTOPTR})
150       .legalFor({{p0, s32}});
151 
152   getActionDefinitionsBuilder(G_PTRTOINT)
153       .legalFor({{s32, p0}});
154 
155   getActionDefinitionsBuilder(G_FRAME_INDEX)
156       .legalFor({p0});
157 
158   getActionDefinitionsBuilder({G_GLOBAL_VALUE, G_JUMP_TABLE})
159       .legalFor({p0});
160 
161   getActionDefinitionsBuilder(G_DYN_STACKALLOC)
162       .lowerFor({{p0, s32}});
163 
164   getActionDefinitionsBuilder(G_VASTART)
165      .legalFor({p0});
166 
167   // FP instructions
168   getActionDefinitionsBuilder(G_FCONSTANT)
169       .legalFor({s32, s64});
170 
171   getActionDefinitionsBuilder({G_FADD, G_FSUB, G_FMUL, G_FDIV, G_FABS, G_FSQRT})
172       .legalFor({s32, s64});
173 
174   getActionDefinitionsBuilder(G_FCMP)
175       .legalFor({{s32, s32}, {s32, s64}})
176       .minScalar(0, s32);
177 
178   getActionDefinitionsBuilder({G_FCEIL, G_FFLOOR})
179       .libcallFor({s32, s64});
180 
181   getActionDefinitionsBuilder(G_FPEXT)
182       .legalFor({{s64, s32}});
183 
184   getActionDefinitionsBuilder(G_FPTRUNC)
185       .legalFor({{s32, s64}});
186 
187   // FP to int conversion instructions
188   getActionDefinitionsBuilder(G_FPTOSI)
189       .legalForCartesianProduct({s32}, {s64, s32})
190       .libcallForCartesianProduct({s64}, {s64, s32})
191       .minScalar(0, s32);
192 
193   getActionDefinitionsBuilder(G_FPTOUI)
194       .libcallForCartesianProduct({s64}, {s64, s32})
195       .lowerForCartesianProduct({s32}, {s64, s32})
196       .minScalar(0, s32);
197 
198   // Int to FP conversion instructions
199   getActionDefinitionsBuilder(G_SITOFP)
200       .legalForCartesianProduct({s64, s32}, {s32})
201       .libcallForCartesianProduct({s64, s32}, {s64})
202       .minScalar(1, s32);
203 
204   getActionDefinitionsBuilder(G_UITOFP)
205       .libcallForCartesianProduct({s64, s32}, {s64})
206       .customForCartesianProduct({s64, s32}, {s32})
207       .minScalar(1, s32);
208 
209   getActionDefinitionsBuilder(G_SEXT_INREG).lower();
210 
211   computeTables();
212   verify(*ST.getInstrInfo());
213 }
214 
215 bool MipsLegalizerInfo::legalizeCustom(MachineInstr &MI,
216                                        MachineRegisterInfo &MRI,
217                                        MachineIRBuilder &MIRBuilder,
218                                        GISelChangeObserver &Observer) const {
219 
220   using namespace TargetOpcode;
221 
222   MIRBuilder.setInstr(MI);
223   const MipsSubtarget &STI =
224       static_cast<const MipsSubtarget &>(MIRBuilder.getMF().getSubtarget());
225   const LLT s32 = LLT::scalar(32);
226   const LLT s64 = LLT::scalar(64);
227 
228   switch (MI.getOpcode()) {
229   case G_UITOFP: {
230     Register Dst = MI.getOperand(0).getReg();
231     Register Src = MI.getOperand(1).getReg();
232     LLT DstTy = MRI.getType(Dst);
233     LLT SrcTy = MRI.getType(Src);
234 
235     if (SrcTy != s32)
236       return false;
237     if (DstTy != s32 && DstTy != s64)
238       return false;
239 
240     // Let 0xABCDEFGH be given unsigned in MI.getOperand(1). First let's convert
241     // unsigned to double. Mantissa has 52 bits so we use following trick:
242     // First make floating point bit mask 0x43300000ABCDEFGH.
243     // Mask represents 2^52 * 0x1.00000ABCDEFGH i.e. 0x100000ABCDEFGH.0 .
244     // Next, subtract  2^52 * 0x1.0000000000000 i.e. 0x10000000000000.0 from it.
245     // Done. Trunc double to float if needed.
246 
247     MachineInstrBuilder Bitcast = MIRBuilder.buildInstr(
248         STI.isFP64bit() ? Mips::BuildPairF64_64 : Mips::BuildPairF64, {s64},
249         {Src, MIRBuilder.buildConstant(s32, UINT32_C(0x43300000))});
250     Bitcast.constrainAllUses(MIRBuilder.getTII(), *STI.getRegisterInfo(),
251                              *STI.getRegBankInfo());
252 
253     MachineInstrBuilder TwoP52FP = MIRBuilder.buildFConstant(
254         s64, BitsToDouble(UINT64_C(0x4330000000000000)));
255 
256     if (DstTy == s64)
257       MIRBuilder.buildFSub(Dst, Bitcast, TwoP52FP);
258     else {
259       MachineInstrBuilder ResF64 = MIRBuilder.buildFSub(s64, Bitcast, TwoP52FP);
260       MIRBuilder.buildFPTrunc(Dst, ResF64);
261     }
262 
263     MI.eraseFromParent();
264     break;
265   }
266   default:
267     return false;
268   }
269 
270   return true;
271 }
272 
273 bool MipsLegalizerInfo::legalizeIntrinsic(MachineInstr &MI,
274                                           MachineRegisterInfo &MRI,
275                                           MachineIRBuilder &MIRBuilder) const {
276   const MipsSubtarget &ST =
277       static_cast<const MipsSubtarget &>(MI.getMF()->getSubtarget());
278   const MipsInstrInfo &TII = *ST.getInstrInfo();
279   const MipsRegisterInfo &TRI = *ST.getRegisterInfo();
280   const RegisterBankInfo &RBI = *ST.getRegBankInfo();
281   MIRBuilder.setInstr(MI);
282 
283   switch (MI.getIntrinsicID()) {
284   case Intrinsic::memcpy:
285   case Intrinsic::memset:
286   case Intrinsic::memmove:
287     if (createMemLibcall(MIRBuilder, MRI, MI) ==
288         LegalizerHelper::UnableToLegalize)
289       return false;
290     MI.eraseFromParent();
291     return true;
292   case Intrinsic::trap: {
293     MachineInstr *Trap = MIRBuilder.buildInstr(Mips::TRAP);
294     MI.eraseFromParent();
295     return constrainSelectedInstRegOperands(*Trap, TII, TRI, RBI);
296   }
297   case Intrinsic::vacopy: {
298     Register Tmp = MRI.createGenericVirtualRegister(LLT::pointer(0, 32));
299     MachinePointerInfo MPO;
300     MIRBuilder.buildLoad(Tmp, MI.getOperand(2),
301                          *MI.getMF()->getMachineMemOperand(
302                              MPO, MachineMemOperand::MOLoad, 4, 4));
303     MIRBuilder.buildStore(Tmp, MI.getOperand(1),
304                           *MI.getMF()->getMachineMemOperand(
305                               MPO, MachineMemOperand::MOStore, 4, 4));
306     MI.eraseFromParent();
307     return true;
308   }
309   default:
310     break;
311   }
312   return true;
313 }
314