LLVM  10.0.0svn
MipsLegalizerInfo.cpp
Go to the documentation of this file.
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"
16 
17 using namespace llvm;
18 
22  unsigned MemSize;
24 };
25 
26 static bool
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 
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 
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 
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 
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) ==
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: {
344  MachinePointerInfo MPO;
345  MIRBuilder.buildLoad(Tmp, MI.getOperand(2),
347  MPO, MachineMemOperand::MOLoad, 4, 4));
348  MIRBuilder.buildStore(Tmp, MI.getOperand(1),
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 }
const RegisterBankInfo * getRegBankInfo() const override
virtual MachineInstrBuilder buildConstant(const DstOp &Res, const ConstantInt &Val)
Build and insert Res = G_CONSTANT Val.
const MachineInstrBuilder & add(const MachineOperand &MO) const
static LLT pointer(unsigned AddressSpace, unsigned SizeInBits)
Get a low-level pointer in the given address space.
const MachineFunction * getMF() const
Return the function that contains the basic block that this instruction belongs to.
This class represents lattice values for constants.
Definition: AllocatorList.h:23
MipsLegalizerInfo(const MipsSubtarget &ST)
The LegalityQuery object bundles together all the information that&#39;s needed to decide whether a given...
const MipsInstrInfo * getInstrInfo() const override
This file declares the targeting of the Machinelegalizer class for Mips.
LLT getType(unsigned Reg) const
Get the low-level type of Reg or LLT{} if Reg is not a generic (target independent) virtual register...
unsigned const TargetRegisterInfo * TRI
bool legalizeIntrinsic(MachineInstr &MI, MachineRegisterInfo &MRI, MachineIRBuilder &MIRBuilder) const override
Return true if MI is either legal or has been legalized and false if not legal.
Holds all the information related to register banks.
const HexagonInstrInfo * TII
void eraseFromParent()
Unlink &#39;this&#39; from the containing basic block and delete it.
bool hasMips32r6() const
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
Definition: MachineInstr.h:410
MachineMemOperand * getMachineMemOperand(MachinePointerInfo PtrInfo, MachineMemOperand::Flags f, uint64_t s, unsigned base_alignment, const AAMDNodes &AAInfo=AAMDNodes(), const MDNode *Ranges=nullptr, SyncScope::ID SSID=SyncScope::System, AtomicOrdering Ordering=AtomicOrdering::NotAtomic, AtomicOrdering FailureOrdering=AtomicOrdering::NotAtomic)
getMachineMemOperand - Allocate a new MachineMemOperand.
MachineInstrBuilder buildFSub(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1)
Build and insert Res = G_FSUB Op0, Op1.
MachineFunction & getMF()
Getter for the function we currently build.
static bool CheckTyN(unsigned N, const LegalityQuery &Query, std::initializer_list< LLT > SupportedValues)
static LLT scalar(unsigned SizeInBits)
Get a low-level scalar or aggregate "bag of bits".
Abstract class that contains various methods for clients to notify about changes. ...
MachineInstrBuilder buildFPTrunc(const DstOp &Res, const SrcOp &Op)
Build and insert Res = G_FPTRUNC Op.
unsigned const MachineRegisterInfo * MRI
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineInstrBuilder buildInstr(unsigned Opcode)
Build and insert <empty> = Opcode <empty>.
Helper class to build MachineInstr.
void setInstr(MachineInstr &MI)
Set the insertion point to before MI.
TRAP - Trapping instruction.
Definition: ISDOpcodes.h:806
LegalizerHelper::LegalizeResult createMemLibcall(MachineIRBuilder &MIRBuilder, MachineRegisterInfo &MRI, MachineInstr &MI)
Create a libcall to memcpy et al.
Some kind of error has occurred and we could not legalize this instruction.
This class contains a discriminated union of information about pointers in memory operands...
bool verify(const TargetRegisterInfo &TRI) const
Check that information hold by this instance make sense for the given TRI.
The memory access writes data.
MachineInstrBuilder buildLoad(const DstOp &Res, const SrcOp &Addr, MachineMemOperand &MMO)
Build and insert Res = G_LOAD Addr, MMO.
virtual MachineInstrBuilder buildFConstant(const DstOp &Res, const ConstantFP &Val)
Build and insert Res = G_FCONSTANT Val.
const MipsRegisterInfo * getRegisterInfo() const override
static uint64_t add(uint64_t LeftOp, uint64_t RightOp)
Definition: FileCheck.cpp:215
static bool SelectMSA3OpIntrinsic(MachineInstr &MI, unsigned Opcode, MachineIRBuilder &MIRBuilder, const MipsSubtarget &ST)
const TargetInstrInfo & getTII()
bool constrainSelectedInstRegOperands(MachineInstr &I, const TargetInstrInfo &TII, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI)
Mutate the newly-selected instruction I to constrain its (possibly generic) virtual register operands...
Definition: Utils.cpp:111
double BitsToDouble(uint64_t Bits)
This function takes a 64-bit integer and returns the bit equivalent double.
Definition: MathExtras.h:624
MachineRegisterInfo - Keep track of information for virtual and physical registers, including vreg register classes, use/def chains for registers, etc.
The memory access reads data.
Representation of each machine instruction.
Definition: MachineInstr.h:63
ArrayRef< LLT > Types
#define N
bool legalizeCustom(MachineInstr &MI, MachineRegisterInfo &MRI, MachineIRBuilder &MIRBuilder, GISelChangeObserver &Observer) const override
MachineInstrBuilder buildStore(const SrcOp &Val, const SrcOp &Addr, MachineMemOperand &MMO)
Build and insert G_STORE Val, Addr, MMO.
static bool MSA3OpIntrinsicToGeneric(MachineInstr &MI, unsigned Opcode, MachineIRBuilder &MIRBuilder, const MipsSubtarget &ST)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
unsigned getIntrinsicID() const
Returns the Intrinsic::ID for this instruction.
static bool CheckTy0Ty1MemSizeAlign(const LegalityQuery &Query, std::initializer_list< TypesAndMemOps > SupportedValues)
IRTranslator LLVM IR MI
static LLT vector(uint16_t NumElements, unsigned ScalarSizeInBits)
Get a low-level vector of some number of elements and element width.
Register createGenericVirtualRegister(LLT Ty, StringRef Name="")
Create and return a new generic virtual register with low-level type Ty.
Register getReg() const
getReg - Returns the register number.
ArrayRef< MemDesc > MMODescrs
Operations which require memory can use this to place requirements on the memory type for each MMO...
const MachineOperand & getOperand(unsigned i) const
Definition: MachineInstr.h:415
bool isFP64bit() const
bool hasMSA() const
bool constrainAllUses(const TargetInstrInfo &TII, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI) const
Wrapper class representing virtual and physical registers.
Definition: Register.h:19