xref: /freebsd/contrib/llvm-project/llvm/lib/Target/Mips/MipsLegalizerInfo.cpp (revision 9dba64be9536c28e4800e06512b7f29b43ade345)
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_SUB, G_MUL})
65       .legalFor({s32})
66       .clampScalar(0, s32, s32);
67 
68   getActionDefinitionsBuilder(G_ADD)
69       .legalIf([=, &ST](const LegalityQuery &Query) {
70         if (CheckTyN(0, Query, {s32}))
71           return true;
72         if (ST.hasMSA() && CheckTyN(0, Query, {v16s8, v8s16, v4s32, v2s64}))
73           return true;
74         return false;
75       })
76       .clampScalar(0, s32, s32);
77 
78   getActionDefinitionsBuilder({G_UADDO, G_UADDE, G_USUBO, G_USUBE, G_UMULO})
79       .lowerFor({{s32, s1}});
80 
81   getActionDefinitionsBuilder(G_UMULH)
82       .legalFor({s32})
83       .maxScalar(0, s32);
84 
85   getActionDefinitionsBuilder({G_LOAD, G_STORE})
86       .legalIf([=, &ST](const LegalityQuery &Query) {
87         if (CheckTy0Ty1MemSizeAlign(Query, {{s32, p0, 8, ST.hasMips32r6()},
88                                             {s32, p0, 16, ST.hasMips32r6()},
89                                             {s32, p0, 32, ST.hasMips32r6()},
90                                             {p0, p0, 32, ST.hasMips32r6()},
91                                             {s64, p0, 64, ST.hasMips32r6()}}))
92           return true;
93         if (ST.hasMSA() &&
94             CheckTy0Ty1MemSizeAlign(Query, {{v16s8, p0, 128, false},
95                                             {v8s16, p0, 128, false},
96                                             {v4s32, p0, 128, false},
97                                             {v2s64, p0, 128, false}}))
98           return true;
99         return false;
100       })
101       .minScalar(0, s32);
102 
103   getActionDefinitionsBuilder(G_IMPLICIT_DEF)
104       .legalFor({s32, s64});
105 
106   getActionDefinitionsBuilder(G_UNMERGE_VALUES)
107      .legalFor({{s32, s64}});
108 
109   getActionDefinitionsBuilder(G_MERGE_VALUES)
110      .legalFor({{s64, s32}});
111 
112   getActionDefinitionsBuilder({G_ZEXTLOAD, G_SEXTLOAD})
113       .legalForTypesWithMemDesc({{s32, p0, 8, 8},
114                                  {s32, p0, 16, 8}})
115       .clampScalar(0, s32, s32);
116 
117   getActionDefinitionsBuilder({G_ZEXT, G_SEXT})
118       .legalIf([](const LegalityQuery &Query) { return false; })
119       .maxScalar(0, s32);
120 
121   getActionDefinitionsBuilder(G_TRUNC)
122       .legalIf([](const LegalityQuery &Query) { return false; })
123       .maxScalar(1, s32);
124 
125   getActionDefinitionsBuilder(G_SELECT)
126       .legalForCartesianProduct({p0, s32, s64}, {s32})
127       .minScalar(0, s32)
128       .minScalar(1, s32);
129 
130   getActionDefinitionsBuilder(G_BRCOND)
131       .legalFor({s32})
132       .minScalar(0, s32);
133 
134   getActionDefinitionsBuilder(G_BRJT)
135       .legalFor({{p0, s32}});
136 
137   getActionDefinitionsBuilder(G_BRINDIRECT)
138       .legalFor({p0});
139 
140   getActionDefinitionsBuilder(G_PHI)
141       .legalFor({p0, s32, s64})
142       .minScalar(0, s32);
143 
144   getActionDefinitionsBuilder({G_AND, G_OR, G_XOR})
145       .legalFor({s32})
146       .clampScalar(0, s32, s32);
147 
148   getActionDefinitionsBuilder({G_SDIV, G_SREM, G_UREM, G_UDIV})
149       .legalFor({s32})
150       .minScalar(0, s32)
151       .libcallFor({s64});
152 
153   getActionDefinitionsBuilder({G_SHL, G_ASHR, G_LSHR})
154       .legalFor({{s32, s32}})
155       .clampScalar(1, s32, s32)
156       .clampScalar(0, s32, s32);
157 
158   getActionDefinitionsBuilder(G_ICMP)
159       .legalForCartesianProduct({s32}, {s32, p0})
160       .clampScalar(1, s32, s32)
161       .minScalar(0, s32);
162 
163   getActionDefinitionsBuilder(G_CONSTANT)
164       .legalFor({s32})
165       .clampScalar(0, s32, s32);
166 
167   getActionDefinitionsBuilder({G_GEP, G_INTTOPTR})
168       .legalFor({{p0, s32}});
169 
170   getActionDefinitionsBuilder(G_PTRTOINT)
171       .legalFor({{s32, p0}});
172 
173   getActionDefinitionsBuilder(G_FRAME_INDEX)
174       .legalFor({p0});
175 
176   getActionDefinitionsBuilder({G_GLOBAL_VALUE, G_JUMP_TABLE})
177       .legalFor({p0});
178 
179   getActionDefinitionsBuilder(G_DYN_STACKALLOC)
180       .lowerFor({{p0, s32}});
181 
182   getActionDefinitionsBuilder(G_VASTART)
183      .legalFor({p0});
184 
185   // FP instructions
186   getActionDefinitionsBuilder(G_FCONSTANT)
187       .legalFor({s32, s64});
188 
189   getActionDefinitionsBuilder({G_FADD, G_FSUB, G_FMUL, G_FDIV, G_FABS, G_FSQRT})
190       .legalFor({s32, s64});
191 
192   getActionDefinitionsBuilder(G_FCMP)
193       .legalFor({{s32, s32}, {s32, s64}})
194       .minScalar(0, s32);
195 
196   getActionDefinitionsBuilder({G_FCEIL, G_FFLOOR})
197       .libcallFor({s32, s64});
198 
199   getActionDefinitionsBuilder(G_FPEXT)
200       .legalFor({{s64, s32}});
201 
202   getActionDefinitionsBuilder(G_FPTRUNC)
203       .legalFor({{s32, s64}});
204 
205   // FP to int conversion instructions
206   getActionDefinitionsBuilder(G_FPTOSI)
207       .legalForCartesianProduct({s32}, {s64, s32})
208       .libcallForCartesianProduct({s64}, {s64, s32})
209       .minScalar(0, s32);
210 
211   getActionDefinitionsBuilder(G_FPTOUI)
212       .libcallForCartesianProduct({s64}, {s64, s32})
213       .lowerForCartesianProduct({s32}, {s64, s32})
214       .minScalar(0, s32);
215 
216   // Int to FP conversion instructions
217   getActionDefinitionsBuilder(G_SITOFP)
218       .legalForCartesianProduct({s64, s32}, {s32})
219       .libcallForCartesianProduct({s64, s32}, {s64})
220       .minScalar(1, s32);
221 
222   getActionDefinitionsBuilder(G_UITOFP)
223       .libcallForCartesianProduct({s64, s32}, {s64})
224       .customForCartesianProduct({s64, s32}, {s32})
225       .minScalar(1, s32);
226 
227   getActionDefinitionsBuilder(G_SEXT_INREG).lower();
228 
229   computeTables();
230   verify(*ST.getInstrInfo());
231 }
232 
233 bool MipsLegalizerInfo::legalizeCustom(MachineInstr &MI,
234                                        MachineRegisterInfo &MRI,
235                                        MachineIRBuilder &MIRBuilder,
236                                        GISelChangeObserver &Observer) const {
237 
238   using namespace TargetOpcode;
239 
240   MIRBuilder.setInstr(MI);
241   const MipsSubtarget &STI =
242       static_cast<const MipsSubtarget &>(MIRBuilder.getMF().getSubtarget());
243   const LLT s32 = LLT::scalar(32);
244   const LLT s64 = LLT::scalar(64);
245 
246   switch (MI.getOpcode()) {
247   case G_UITOFP: {
248     Register Dst = MI.getOperand(0).getReg();
249     Register Src = MI.getOperand(1).getReg();
250     LLT DstTy = MRI.getType(Dst);
251     LLT SrcTy = MRI.getType(Src);
252 
253     if (SrcTy != s32)
254       return false;
255     if (DstTy != s32 && DstTy != s64)
256       return false;
257 
258     // Let 0xABCDEFGH be given unsigned in MI.getOperand(1). First let's convert
259     // unsigned to double. Mantissa has 52 bits so we use following trick:
260     // First make floating point bit mask 0x43300000ABCDEFGH.
261     // Mask represents 2^52 * 0x1.00000ABCDEFGH i.e. 0x100000ABCDEFGH.0 .
262     // Next, subtract  2^52 * 0x1.0000000000000 i.e. 0x10000000000000.0 from it.
263     // Done. Trunc double to float if needed.
264 
265     MachineInstrBuilder Bitcast = MIRBuilder.buildInstr(
266         STI.isFP64bit() ? Mips::BuildPairF64_64 : Mips::BuildPairF64, {s64},
267         {Src, MIRBuilder.buildConstant(s32, UINT32_C(0x43300000))});
268     Bitcast.constrainAllUses(MIRBuilder.getTII(), *STI.getRegisterInfo(),
269                              *STI.getRegBankInfo());
270 
271     MachineInstrBuilder TwoP52FP = MIRBuilder.buildFConstant(
272         s64, BitsToDouble(UINT64_C(0x4330000000000000)));
273 
274     if (DstTy == s64)
275       MIRBuilder.buildFSub(Dst, Bitcast, TwoP52FP);
276     else {
277       MachineInstrBuilder ResF64 = MIRBuilder.buildFSub(s64, Bitcast, TwoP52FP);
278       MIRBuilder.buildFPTrunc(Dst, ResF64);
279     }
280 
281     MI.eraseFromParent();
282     break;
283   }
284   default:
285     return false;
286   }
287 
288   return true;
289 }
290 
291 static bool SelectMSA3OpIntrinsic(MachineInstr &MI, unsigned Opcode,
292                                   MachineIRBuilder &MIRBuilder,
293                                   const MipsSubtarget &ST) {
294   assert(ST.hasMSA() && "MSA intrinsic not supported on target without MSA.");
295   if (!MIRBuilder.buildInstr(Opcode)
296            .add(MI.getOperand(0))
297            .add(MI.getOperand(2))
298            .add(MI.getOperand(3))
299            .constrainAllUses(MIRBuilder.getTII(), *ST.getRegisterInfo(),
300                              *ST.getRegBankInfo()))
301     return false;
302   MI.eraseFromParent();
303   return true;
304 }
305 
306 static bool MSA3OpIntrinsicToGeneric(MachineInstr &MI, unsigned Opcode,
307                                      MachineIRBuilder &MIRBuilder,
308                                      const MipsSubtarget &ST) {
309   assert(ST.hasMSA() && "MSA intrinsic not supported on target without MSA.");
310   MIRBuilder.buildInstr(Opcode)
311       .add(MI.getOperand(0))
312       .add(MI.getOperand(2))
313       .add(MI.getOperand(3));
314   MI.eraseFromParent();
315   return true;
316 }
317 
318 bool MipsLegalizerInfo::legalizeIntrinsic(MachineInstr &MI,
319                                           MachineRegisterInfo &MRI,
320                                           MachineIRBuilder &MIRBuilder) const {
321   const MipsSubtarget &ST =
322       static_cast<const MipsSubtarget &>(MI.getMF()->getSubtarget());
323   const MipsInstrInfo &TII = *ST.getInstrInfo();
324   const MipsRegisterInfo &TRI = *ST.getRegisterInfo();
325   const RegisterBankInfo &RBI = *ST.getRegBankInfo();
326   MIRBuilder.setInstr(MI);
327 
328   switch (MI.getIntrinsicID()) {
329   case Intrinsic::memcpy:
330   case Intrinsic::memset:
331   case Intrinsic::memmove:
332     if (createMemLibcall(MIRBuilder, MRI, MI) ==
333         LegalizerHelper::UnableToLegalize)
334       return false;
335     MI.eraseFromParent();
336     return true;
337   case Intrinsic::trap: {
338     MachineInstr *Trap = MIRBuilder.buildInstr(Mips::TRAP);
339     MI.eraseFromParent();
340     return constrainSelectedInstRegOperands(*Trap, TII, TRI, RBI);
341   }
342   case Intrinsic::vacopy: {
343     Register Tmp = MRI.createGenericVirtualRegister(LLT::pointer(0, 32));
344     MachinePointerInfo MPO;
345     MIRBuilder.buildLoad(Tmp, MI.getOperand(2),
346                          *MI.getMF()->getMachineMemOperand(
347                              MPO, MachineMemOperand::MOLoad, 4, 4));
348     MIRBuilder.buildStore(Tmp, MI.getOperand(1),
349                           *MI.getMF()->getMachineMemOperand(
350                               MPO, MachineMemOperand::MOStore, 4, 4));
351     MI.eraseFromParent();
352     return true;
353   }
354   case Intrinsic::mips_addv_b:
355   case Intrinsic::mips_addv_h:
356   case Intrinsic::mips_addv_w:
357   case Intrinsic::mips_addv_d:
358     return MSA3OpIntrinsicToGeneric(MI, TargetOpcode::G_ADD, MIRBuilder, ST);
359   case Intrinsic::mips_addvi_b:
360     return SelectMSA3OpIntrinsic(MI, Mips::ADDVI_B, MIRBuilder, ST);
361   case Intrinsic::mips_addvi_h:
362     return SelectMSA3OpIntrinsic(MI, Mips::ADDVI_H, MIRBuilder, ST);
363   case Intrinsic::mips_addvi_w:
364     return SelectMSA3OpIntrinsic(MI, Mips::ADDVI_W, MIRBuilder, ST);
365   case Intrinsic::mips_addvi_d:
366     return SelectMSA3OpIntrinsic(MI, Mips::ADDVI_D, MIRBuilder, ST);
367   default:
368     break;
369   }
370   return true;
371 }
372