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 MipsLegalizerInfo::MipsLegalizerInfo(const MipsSubtarget &ST) {
20   using namespace TargetOpcode;
21 
22   const LLT s1 = LLT::scalar(1);
23   const LLT s32 = LLT::scalar(32);
24   const LLT s64 = LLT::scalar(64);
25   const LLT p0 = LLT::pointer(0, 32);
26 
27   getActionDefinitionsBuilder({G_ADD, G_SUB, G_MUL})
28       .legalFor({s32})
29       .clampScalar(0, s32, s32);
30 
31   getActionDefinitionsBuilder({G_UADDO, G_UADDE, G_USUBO, G_USUBE, G_UMULO})
32       .lowerFor({{s32, s1}});
33 
34   getActionDefinitionsBuilder(G_UMULH)
35       .legalFor({s32})
36       .maxScalar(0, s32);
37 
38   getActionDefinitionsBuilder({G_LOAD, G_STORE})
39       .legalForTypesWithMemDesc({{s32, p0, 8, 8},
40                                  {s32, p0, 16, 8},
41                                  {s32, p0, 32, 8},
42                                  {s64, p0, 64, 8},
43                                  {p0, p0, 32, 8}})
44       .minScalar(0, s32);
45 
46   getActionDefinitionsBuilder(G_IMPLICIT_DEF)
47       .legalFor({s32, s64});
48 
49   getActionDefinitionsBuilder(G_UNMERGE_VALUES)
50      .legalFor({{s32, s64}});
51 
52   getActionDefinitionsBuilder(G_MERGE_VALUES)
53      .legalFor({{s64, s32}});
54 
55   getActionDefinitionsBuilder({G_ZEXTLOAD, G_SEXTLOAD})
56       .legalForTypesWithMemDesc({{s32, p0, 8, 8},
57                                  {s32, p0, 16, 8}})
58       .clampScalar(0, s32, s32);
59 
60   getActionDefinitionsBuilder({G_ZEXT, G_SEXT})
61       .legalIf([](const LegalityQuery &Query) { return false; })
62       .maxScalar(0, s32);
63 
64   getActionDefinitionsBuilder(G_TRUNC)
65       .legalIf([](const LegalityQuery &Query) { return false; })
66       .maxScalar(1, s32);
67 
68   getActionDefinitionsBuilder(G_SELECT)
69       .legalForCartesianProduct({p0, s32, s64}, {s32})
70       .minScalar(0, s32)
71       .minScalar(1, s32);
72 
73   getActionDefinitionsBuilder(G_BRCOND)
74       .legalFor({s32})
75       .minScalar(0, s32);
76 
77   getActionDefinitionsBuilder(G_BRJT)
78       .legalFor({{p0, s32}});
79 
80   getActionDefinitionsBuilder(G_BRINDIRECT)
81       .legalFor({p0});
82 
83   getActionDefinitionsBuilder(G_PHI)
84       .legalFor({p0, s32, s64})
85       .minScalar(0, s32);
86 
87   getActionDefinitionsBuilder({G_AND, G_OR, G_XOR})
88       .legalFor({s32})
89       .clampScalar(0, s32, s32);
90 
91   getActionDefinitionsBuilder({G_SDIV, G_SREM, G_UREM, G_UDIV})
92       .legalFor({s32})
93       .minScalar(0, s32)
94       .libcallFor({s64});
95 
96   getActionDefinitionsBuilder({G_SHL, G_ASHR, G_LSHR})
97       .legalFor({{s32, s32}})
98       .clampScalar(1, s32, s32)
99       .clampScalar(0, s32, s32);
100 
101   getActionDefinitionsBuilder(G_ICMP)
102       .legalForCartesianProduct({s32}, {s32, p0})
103       .clampScalar(1, s32, s32)
104       .minScalar(0, s32);
105 
106   getActionDefinitionsBuilder(G_CONSTANT)
107       .legalFor({s32})
108       .clampScalar(0, s32, s32);
109 
110   getActionDefinitionsBuilder({G_GEP, G_INTTOPTR})
111       .legalFor({{p0, s32}});
112 
113   getActionDefinitionsBuilder(G_PTRTOINT)
114       .legalFor({{s32, p0}});
115 
116   getActionDefinitionsBuilder(G_FRAME_INDEX)
117       .legalFor({p0});
118 
119   getActionDefinitionsBuilder({G_GLOBAL_VALUE, G_JUMP_TABLE})
120       .legalFor({p0});
121 
122   getActionDefinitionsBuilder(G_DYN_STACKALLOC)
123       .lowerFor({{p0, s32}});
124 
125   // FP instructions
126   getActionDefinitionsBuilder(G_FCONSTANT)
127       .legalFor({s32, s64});
128 
129   getActionDefinitionsBuilder({G_FADD, G_FSUB, G_FMUL, G_FDIV, G_FABS, G_FSQRT})
130       .legalFor({s32, s64});
131 
132   getActionDefinitionsBuilder(G_FCMP)
133       .legalFor({{s32, s32}, {s32, s64}})
134       .minScalar(0, s32);
135 
136   getActionDefinitionsBuilder({G_FCEIL, G_FFLOOR})
137       .libcallFor({s32, s64});
138 
139   getActionDefinitionsBuilder(G_FPEXT)
140       .legalFor({{s64, s32}});
141 
142   getActionDefinitionsBuilder(G_FPTRUNC)
143       .legalFor({{s32, s64}});
144 
145   // FP to int conversion instructions
146   getActionDefinitionsBuilder(G_FPTOSI)
147       .legalForCartesianProduct({s32}, {s64, s32})
148       .libcallForCartesianProduct({s64}, {s64, s32})
149       .minScalar(0, s32);
150 
151   getActionDefinitionsBuilder(G_FPTOUI)
152       .libcallForCartesianProduct({s64}, {s64, s32})
153       .lowerForCartesianProduct({s32}, {s64, s32})
154       .minScalar(0, s32);
155 
156   // Int to FP conversion instructions
157   getActionDefinitionsBuilder(G_SITOFP)
158       .legalForCartesianProduct({s64, s32}, {s32})
159       .libcallForCartesianProduct({s64, s32}, {s64})
160       .minScalar(1, s32);
161 
162   getActionDefinitionsBuilder(G_UITOFP)
163       .libcallForCartesianProduct({s64, s32}, {s64})
164       .customForCartesianProduct({s64, s32}, {s32})
165       .minScalar(1, s32);
166 
167   getActionDefinitionsBuilder(G_SEXT_INREG).lower();
168 
169   computeTables();
170   verify(*ST.getInstrInfo());
171 }
172 
173 bool MipsLegalizerInfo::legalizeCustom(MachineInstr &MI,
174                                        MachineRegisterInfo &MRI,
175                                        MachineIRBuilder &MIRBuilder,
176                                        GISelChangeObserver &Observer) const {
177 
178   using namespace TargetOpcode;
179 
180   MIRBuilder.setInstr(MI);
181   const MipsSubtarget &STI =
182       static_cast<const MipsSubtarget &>(MIRBuilder.getMF().getSubtarget());
183   const LLT s32 = LLT::scalar(32);
184   const LLT s64 = LLT::scalar(64);
185 
186   switch (MI.getOpcode()) {
187   case G_UITOFP: {
188     Register Dst = MI.getOperand(0).getReg();
189     Register Src = MI.getOperand(1).getReg();
190     LLT DstTy = MRI.getType(Dst);
191     LLT SrcTy = MRI.getType(Src);
192 
193     if (SrcTy != s32)
194       return false;
195     if (DstTy != s32 && DstTy != s64)
196       return false;
197 
198     // Let 0xABCDEFGH be given unsigned in MI.getOperand(1). First let's convert
199     // unsigned to double. Mantissa has 52 bits so we use following trick:
200     // First make floating point bit mask 0x43300000ABCDEFGH.
201     // Mask represents 2^52 * 0x1.00000ABCDEFGH i.e. 0x100000ABCDEFGH.0 .
202     // Next, subtract  2^52 * 0x1.0000000000000 i.e. 0x10000000000000.0 from it.
203     // Done. Trunc double to float if needed.
204 
205     MachineInstrBuilder Bitcast = MIRBuilder.buildInstr(
206         STI.isFP64bit() ? Mips::BuildPairF64_64 : Mips::BuildPairF64, {s64},
207         {Src, MIRBuilder.buildConstant(s32, UINT32_C(0x43300000))});
208     Bitcast.constrainAllUses(MIRBuilder.getTII(), *STI.getRegisterInfo(),
209                              *STI.getRegBankInfo());
210 
211     MachineInstrBuilder TwoP52FP = MIRBuilder.buildFConstant(
212         s64, BitsToDouble(UINT64_C(0x4330000000000000)));
213 
214     if (DstTy == s64)
215       MIRBuilder.buildFSub(Dst, Bitcast, TwoP52FP);
216     else {
217       MachineInstrBuilder ResF64 = MIRBuilder.buildFSub(s64, Bitcast, TwoP52FP);
218       MIRBuilder.buildFPTrunc(Dst, ResF64);
219     }
220 
221     MI.eraseFromParent();
222     break;
223   }
224   default:
225     return false;
226   }
227 
228   return true;
229 }
230 
231 bool MipsLegalizerInfo::legalizeIntrinsic(MachineInstr &MI,
232                                           MachineRegisterInfo &MRI,
233                                           MachineIRBuilder &MIRBuilder) const {
234   const MipsSubtarget &ST =
235       static_cast<const MipsSubtarget &>(MI.getMF()->getSubtarget());
236   const MipsInstrInfo &TII = *ST.getInstrInfo();
237   const MipsRegisterInfo &TRI = *ST.getRegisterInfo();
238   const RegisterBankInfo &RBI = *ST.getRegBankInfo();
239   MIRBuilder.setInstr(MI);
240 
241   switch (MI.getIntrinsicID()) {
242   case Intrinsic::memcpy:
243   case Intrinsic::memset:
244   case Intrinsic::memmove:
245     if (createMemLibcall(MIRBuilder, MRI, MI) ==
246         LegalizerHelper::UnableToLegalize)
247       return false;
248     MI.eraseFromParent();
249     return true;
250   case Intrinsic::trap: {
251     MachineInstr *Trap = MIRBuilder.buildInstr(Mips::TRAP);
252     MI.eraseFromParent();
253     return constrainSelectedInstRegOperands(*Trap, TII, TRI, RBI);
254   }
255   default:
256     break;
257   }
258   return true;
259 }
260