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