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