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 static bool CheckTyN(unsigned N, const LegalityQuery &Query,
45                      std::initializer_list<LLT> SupportedValues) {
46   for (auto &Val : SupportedValues)
47     if (Val == Query.Types[N])
48       return true;
49   return false;
50 }
51 
52 MipsLegalizerInfo::MipsLegalizerInfo(const MipsSubtarget &ST) {
53   using namespace TargetOpcode;
54 
55   const LLT s1 = LLT::scalar(1);
56   const LLT s32 = LLT::scalar(32);
57   const LLT s64 = LLT::scalar(64);
58   const LLT v16s8 = LLT::vector(16, 8);
59   const LLT v8s16 = LLT::vector(8, 16);
60   const LLT v4s32 = LLT::vector(4, 32);
61   const LLT v2s64 = LLT::vector(2, 64);
62   const LLT p0 = LLT::pointer(0, 32);
63 
64   getActionDefinitionsBuilder({G_ADD, G_SUB, G_MUL})
65       .legalIf([=, &ST](const LegalityQuery &Query) {
66         if (CheckTyN(0, Query, {s32}))
67           return true;
68         if (ST.hasMSA() && CheckTyN(0, Query, {v16s8, v8s16, v4s32, v2s64}))
69           return true;
70         return false;
71       })
72       .clampScalar(0, s32, s32);
73 
74   getActionDefinitionsBuilder({G_UADDO, G_UADDE, G_USUBO, G_USUBE, G_UMULO})
75       .lowerFor({{s32, s1}});
76 
77   getActionDefinitionsBuilder(G_UMULH)
78       .legalFor({s32})
79       .maxScalar(0, s32);
80 
81   getActionDefinitionsBuilder({G_LOAD, G_STORE})
82       .legalIf([=, &ST](const LegalityQuery &Query) {
83         if (CheckTy0Ty1MemSizeAlign(Query, {{s32, p0, 8, ST.hasMips32r6()},
84                                             {s32, p0, 16, ST.hasMips32r6()},
85                                             {s32, p0, 32, ST.hasMips32r6()},
86                                             {p0, p0, 32, ST.hasMips32r6()},
87                                             {s64, p0, 64, ST.hasMips32r6()}}))
88           return true;
89         if (ST.hasMSA() &&
90             CheckTy0Ty1MemSizeAlign(Query, {{v16s8, p0, 128, false},
91                                             {v8s16, p0, 128, false},
92                                             {v4s32, p0, 128, false},
93                                             {v2s64, p0, 128, false}}))
94           return true;
95         return false;
96       })
97       .minScalar(0, s32);
98 
99   getActionDefinitionsBuilder(G_IMPLICIT_DEF)
100       .legalFor({s32, s64});
101 
102   getActionDefinitionsBuilder(G_UNMERGE_VALUES)
103      .legalFor({{s32, s64}});
104 
105   getActionDefinitionsBuilder(G_MERGE_VALUES)
106      .legalFor({{s64, s32}});
107 
108   getActionDefinitionsBuilder({G_ZEXTLOAD, G_SEXTLOAD})
109       .legalForTypesWithMemDesc({{s32, p0, 8, 8},
110                                  {s32, p0, 16, 8}})
111       .clampScalar(0, s32, s32);
112 
113   getActionDefinitionsBuilder({G_ZEXT, G_SEXT})
114       .legalIf([](const LegalityQuery &Query) { return false; })
115       .maxScalar(0, s32);
116 
117   getActionDefinitionsBuilder(G_TRUNC)
118       .legalIf([](const LegalityQuery &Query) { return false; })
119       .maxScalar(1, s32);
120 
121   getActionDefinitionsBuilder(G_SELECT)
122       .legalForCartesianProduct({p0, s32, s64}, {s32})
123       .minScalar(0, s32)
124       .minScalar(1, s32);
125 
126   getActionDefinitionsBuilder(G_BRCOND)
127       .legalFor({s32})
128       .minScalar(0, s32);
129 
130   getActionDefinitionsBuilder(G_BRJT)
131       .legalFor({{p0, s32}});
132 
133   getActionDefinitionsBuilder(G_BRINDIRECT)
134       .legalFor({p0});
135 
136   getActionDefinitionsBuilder(G_PHI)
137       .legalFor({p0, s32, s64})
138       .minScalar(0, s32);
139 
140   getActionDefinitionsBuilder({G_AND, G_OR, G_XOR})
141       .legalFor({s32})
142       .clampScalar(0, s32, s32);
143 
144   getActionDefinitionsBuilder({G_SDIV, G_SREM, G_UDIV, G_UREM})
145       .legalIf([=, &ST](const LegalityQuery &Query) {
146         if (CheckTyN(0, Query, {s32}))
147           return true;
148         if (ST.hasMSA() && CheckTyN(0, Query, {v16s8, v8s16, v4s32, v2s64}))
149           return true;
150         return false;
151       })
152       .minScalar(0, s32)
153       .libcallFor({s64});
154 
155   getActionDefinitionsBuilder({G_SHL, G_ASHR, G_LSHR})
156       .legalFor({{s32, s32}})
157       .clampScalar(1, s32, s32)
158       .clampScalar(0, s32, s32);
159 
160   getActionDefinitionsBuilder(G_ICMP)
161       .legalForCartesianProduct({s32}, {s32, p0})
162       .clampScalar(1, s32, s32)
163       .minScalar(0, s32);
164 
165   getActionDefinitionsBuilder(G_CONSTANT)
166       .legalFor({s32})
167       .clampScalar(0, s32, s32);
168 
169   getActionDefinitionsBuilder({G_GEP, G_INTTOPTR})
170       .legalFor({{p0, s32}});
171 
172   getActionDefinitionsBuilder(G_PTRTOINT)
173       .legalFor({{s32, p0}});
174 
175   getActionDefinitionsBuilder(G_FRAME_INDEX)
176       .legalFor({p0});
177 
178   getActionDefinitionsBuilder({G_GLOBAL_VALUE, G_JUMP_TABLE})
179       .legalFor({p0});
180 
181   getActionDefinitionsBuilder(G_DYN_STACKALLOC)
182       .lowerFor({{p0, s32}});
183 
184   getActionDefinitionsBuilder(G_VASTART)
185      .legalFor({p0});
186 
187   // FP instructions
188   getActionDefinitionsBuilder(G_FCONSTANT)
189       .legalFor({s32, s64});
190 
191   getActionDefinitionsBuilder({G_FADD, G_FSUB, G_FMUL, G_FDIV, G_FABS, G_FSQRT})
192       .legalIf([=, &ST](const LegalityQuery &Query) {
193         if (CheckTyN(0, Query, {s32, s64}))
194           return true;
195         if (ST.hasMSA() && CheckTyN(0, Query, {v16s8, v8s16, v4s32, v2s64}))
196           return true;
197         return false;
198       });
199 
200   getActionDefinitionsBuilder(G_FCMP)
201       .legalFor({{s32, s32}, {s32, s64}})
202       .minScalar(0, s32);
203 
204   getActionDefinitionsBuilder({G_FCEIL, G_FFLOOR})
205       .libcallFor({s32, s64});
206 
207   getActionDefinitionsBuilder(G_FPEXT)
208       .legalFor({{s64, s32}});
209 
210   getActionDefinitionsBuilder(G_FPTRUNC)
211       .legalFor({{s32, s64}});
212 
213   // FP to int conversion instructions
214   getActionDefinitionsBuilder(G_FPTOSI)
215       .legalForCartesianProduct({s32}, {s64, s32})
216       .libcallForCartesianProduct({s64}, {s64, s32})
217       .minScalar(0, s32);
218 
219   getActionDefinitionsBuilder(G_FPTOUI)
220       .libcallForCartesianProduct({s64}, {s64, s32})
221       .lowerForCartesianProduct({s32}, {s64, s32})
222       .minScalar(0, s32);
223 
224   // Int to FP conversion instructions
225   getActionDefinitionsBuilder(G_SITOFP)
226       .legalForCartesianProduct({s64, s32}, {s32})
227       .libcallForCartesianProduct({s64, s32}, {s64})
228       .minScalar(1, s32);
229 
230   getActionDefinitionsBuilder(G_UITOFP)
231       .libcallForCartesianProduct({s64, s32}, {s64})
232       .customForCartesianProduct({s64, s32}, {s32})
233       .minScalar(1, s32);
234 
235   getActionDefinitionsBuilder(G_SEXT_INREG).lower();
236 
237   computeTables();
238   verify(*ST.getInstrInfo());
239 }
240 
241 bool MipsLegalizerInfo::legalizeCustom(MachineInstr &MI,
242                                        MachineRegisterInfo &MRI,
243                                        MachineIRBuilder &MIRBuilder,
244                                        GISelChangeObserver &Observer) const {
245 
246   using namespace TargetOpcode;
247 
248   MIRBuilder.setInstr(MI);
249   const MipsSubtarget &STI =
250       static_cast<const MipsSubtarget &>(MIRBuilder.getMF().getSubtarget());
251   const LLT s32 = LLT::scalar(32);
252   const LLT s64 = LLT::scalar(64);
253 
254   switch (MI.getOpcode()) {
255   case G_UITOFP: {
256     Register Dst = MI.getOperand(0).getReg();
257     Register Src = MI.getOperand(1).getReg();
258     LLT DstTy = MRI.getType(Dst);
259     LLT SrcTy = MRI.getType(Src);
260 
261     if (SrcTy != s32)
262       return false;
263     if (DstTy != s32 && DstTy != s64)
264       return false;
265 
266     // Let 0xABCDEFGH be given unsigned in MI.getOperand(1). First let's convert
267     // unsigned to double. Mantissa has 52 bits so we use following trick:
268     // First make floating point bit mask 0x43300000ABCDEFGH.
269     // Mask represents 2^52 * 0x1.00000ABCDEFGH i.e. 0x100000ABCDEFGH.0 .
270     // Next, subtract  2^52 * 0x1.0000000000000 i.e. 0x10000000000000.0 from it.
271     // Done. Trunc double to float if needed.
272 
273     MachineInstrBuilder Bitcast = MIRBuilder.buildInstr(
274         STI.isFP64bit() ? Mips::BuildPairF64_64 : Mips::BuildPairF64, {s64},
275         {Src, MIRBuilder.buildConstant(s32, UINT32_C(0x43300000))});
276     Bitcast.constrainAllUses(MIRBuilder.getTII(), *STI.getRegisterInfo(),
277                              *STI.getRegBankInfo());
278 
279     MachineInstrBuilder TwoP52FP = MIRBuilder.buildFConstant(
280         s64, BitsToDouble(UINT64_C(0x4330000000000000)));
281 
282     if (DstTy == s64)
283       MIRBuilder.buildFSub(Dst, Bitcast, TwoP52FP);
284     else {
285       MachineInstrBuilder ResF64 = MIRBuilder.buildFSub(s64, Bitcast, TwoP52FP);
286       MIRBuilder.buildFPTrunc(Dst, ResF64);
287     }
288 
289     MI.eraseFromParent();
290     break;
291   }
292   default:
293     return false;
294   }
295 
296   return true;
297 }
298 
299 static bool SelectMSA3OpIntrinsic(MachineInstr &MI, unsigned Opcode,
300                                   MachineIRBuilder &MIRBuilder,
301                                   const MipsSubtarget &ST) {
302   assert(ST.hasMSA() && "MSA intrinsic not supported on target without MSA.");
303   if (!MIRBuilder.buildInstr(Opcode)
304            .add(MI.getOperand(0))
305            .add(MI.getOperand(2))
306            .add(MI.getOperand(3))
307            .constrainAllUses(MIRBuilder.getTII(), *ST.getRegisterInfo(),
308                              *ST.getRegBankInfo()))
309     return false;
310   MI.eraseFromParent();
311   return true;
312 }
313 
314 static bool MSA3OpIntrinsicToGeneric(MachineInstr &MI, unsigned Opcode,
315                                      MachineIRBuilder &MIRBuilder,
316                                      const MipsSubtarget &ST) {
317   assert(ST.hasMSA() && "MSA intrinsic not supported on target without MSA.");
318   MIRBuilder.buildInstr(Opcode)
319       .add(MI.getOperand(0))
320       .add(MI.getOperand(2))
321       .add(MI.getOperand(3));
322   MI.eraseFromParent();
323   return true;
324 }
325 
326 bool MSA2OpIntrinsicToGeneric(MachineInstr &MI, unsigned Opcode,
327                               MachineIRBuilder &MIRBuilder,
328                               const MipsSubtarget &ST) {
329   assert(ST.hasMSA() && "MSA intrinsic not supported on target without MSA.");
330   MIRBuilder.buildInstr(Opcode)
331       .add(MI.getOperand(0))
332       .add(MI.getOperand(2));
333   MI.eraseFromParent();
334   return true;
335 }
336 
337 bool MipsLegalizerInfo::legalizeIntrinsic(MachineInstr &MI,
338                                           MachineRegisterInfo &MRI,
339                                           MachineIRBuilder &MIRBuilder) const {
340   const MipsSubtarget &ST =
341       static_cast<const MipsSubtarget &>(MI.getMF()->getSubtarget());
342   const MipsInstrInfo &TII = *ST.getInstrInfo();
343   const MipsRegisterInfo &TRI = *ST.getRegisterInfo();
344   const RegisterBankInfo &RBI = *ST.getRegBankInfo();
345   MIRBuilder.setInstr(MI);
346 
347   switch (MI.getIntrinsicID()) {
348   case Intrinsic::memcpy:
349   case Intrinsic::memset:
350   case Intrinsic::memmove:
351     if (createMemLibcall(MIRBuilder, MRI, MI) ==
352         LegalizerHelper::UnableToLegalize)
353       return false;
354     MI.eraseFromParent();
355     return true;
356   case Intrinsic::trap: {
357     MachineInstr *Trap = MIRBuilder.buildInstr(Mips::TRAP);
358     MI.eraseFromParent();
359     return constrainSelectedInstRegOperands(*Trap, TII, TRI, RBI);
360   }
361   case Intrinsic::vacopy: {
362     Register Tmp = MRI.createGenericVirtualRegister(LLT::pointer(0, 32));
363     MachinePointerInfo MPO;
364     MIRBuilder.buildLoad(Tmp, MI.getOperand(2),
365                          *MI.getMF()->getMachineMemOperand(
366                              MPO, MachineMemOperand::MOLoad, 4, 4));
367     MIRBuilder.buildStore(Tmp, MI.getOperand(1),
368                           *MI.getMF()->getMachineMemOperand(
369                               MPO, MachineMemOperand::MOStore, 4, 4));
370     MI.eraseFromParent();
371     return true;
372   }
373   case Intrinsic::mips_addv_b:
374   case Intrinsic::mips_addv_h:
375   case Intrinsic::mips_addv_w:
376   case Intrinsic::mips_addv_d:
377     return MSA3OpIntrinsicToGeneric(MI, TargetOpcode::G_ADD, MIRBuilder, ST);
378   case Intrinsic::mips_addvi_b:
379     return SelectMSA3OpIntrinsic(MI, Mips::ADDVI_B, MIRBuilder, ST);
380   case Intrinsic::mips_addvi_h:
381     return SelectMSA3OpIntrinsic(MI, Mips::ADDVI_H, MIRBuilder, ST);
382   case Intrinsic::mips_addvi_w:
383     return SelectMSA3OpIntrinsic(MI, Mips::ADDVI_W, MIRBuilder, ST);
384   case Intrinsic::mips_addvi_d:
385     return SelectMSA3OpIntrinsic(MI, Mips::ADDVI_D, MIRBuilder, ST);
386   case Intrinsic::mips_subv_b:
387   case Intrinsic::mips_subv_h:
388   case Intrinsic::mips_subv_w:
389   case Intrinsic::mips_subv_d:
390     return MSA3OpIntrinsicToGeneric(MI, TargetOpcode::G_SUB, MIRBuilder, ST);
391   case Intrinsic::mips_subvi_b:
392     return SelectMSA3OpIntrinsic(MI, Mips::SUBVI_B, MIRBuilder, ST);
393   case Intrinsic::mips_subvi_h:
394     return SelectMSA3OpIntrinsic(MI, Mips::SUBVI_H, MIRBuilder, ST);
395   case Intrinsic::mips_subvi_w:
396     return SelectMSA3OpIntrinsic(MI, Mips::SUBVI_W, MIRBuilder, ST);
397   case Intrinsic::mips_subvi_d:
398     return SelectMSA3OpIntrinsic(MI, Mips::SUBVI_D, MIRBuilder, ST);
399   case Intrinsic::mips_mulv_b:
400   case Intrinsic::mips_mulv_h:
401   case Intrinsic::mips_mulv_w:
402   case Intrinsic::mips_mulv_d:
403     return MSA3OpIntrinsicToGeneric(MI, TargetOpcode::G_MUL, MIRBuilder, ST);
404   case Intrinsic::mips_div_s_b:
405   case Intrinsic::mips_div_s_h:
406   case Intrinsic::mips_div_s_w:
407   case Intrinsic::mips_div_s_d:
408     return MSA3OpIntrinsicToGeneric(MI, TargetOpcode::G_SDIV, MIRBuilder, ST);
409   case Intrinsic::mips_mod_s_b:
410   case Intrinsic::mips_mod_s_h:
411   case Intrinsic::mips_mod_s_w:
412   case Intrinsic::mips_mod_s_d:
413     return MSA3OpIntrinsicToGeneric(MI, TargetOpcode::G_SREM, MIRBuilder, ST);
414   case Intrinsic::mips_div_u_b:
415   case Intrinsic::mips_div_u_h:
416   case Intrinsic::mips_div_u_w:
417   case Intrinsic::mips_div_u_d:
418     return MSA3OpIntrinsicToGeneric(MI, TargetOpcode::G_UDIV, MIRBuilder, ST);
419   case Intrinsic::mips_mod_u_b:
420   case Intrinsic::mips_mod_u_h:
421   case Intrinsic::mips_mod_u_w:
422   case Intrinsic::mips_mod_u_d:
423     return MSA3OpIntrinsicToGeneric(MI, TargetOpcode::G_UREM, MIRBuilder, ST);
424   case Intrinsic::mips_fadd_w:
425   case Intrinsic::mips_fadd_d:
426     return MSA3OpIntrinsicToGeneric(MI, TargetOpcode::G_FADD, MIRBuilder, ST);
427   case Intrinsic::mips_fsub_w:
428   case Intrinsic::mips_fsub_d:
429     return MSA3OpIntrinsicToGeneric(MI, TargetOpcode::G_FSUB, MIRBuilder, ST);
430   case Intrinsic::mips_fmul_w:
431   case Intrinsic::mips_fmul_d:
432     return MSA3OpIntrinsicToGeneric(MI, TargetOpcode::G_FMUL, MIRBuilder, ST);
433   case Intrinsic::mips_fdiv_w:
434   case Intrinsic::mips_fdiv_d:
435     return MSA3OpIntrinsicToGeneric(MI, TargetOpcode::G_FDIV, MIRBuilder, ST);
436   case Intrinsic::mips_fmax_a_w:
437     return SelectMSA3OpIntrinsic(MI, Mips::FMAX_A_W, MIRBuilder, ST);
438   case Intrinsic::mips_fmax_a_d:
439     return SelectMSA3OpIntrinsic(MI, Mips::FMAX_A_D, MIRBuilder, ST);
440   case Intrinsic::mips_fsqrt_w:
441     return MSA2OpIntrinsicToGeneric(MI, TargetOpcode::G_FSQRT, MIRBuilder, ST);
442   case Intrinsic::mips_fsqrt_d:
443     return MSA2OpIntrinsicToGeneric(MI, TargetOpcode::G_FSQRT, MIRBuilder, ST);
444   default:
445     break;
446   }
447   return true;
448 }
449