LLVM  7.0.0svn
AArch64LegalizerInfo.cpp
Go to the documentation of this file.
1 //===- AArch64LegalizerInfo.cpp ----------------------------------*- C++ -*-==//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 /// \file
10 /// This file implements the targeting of the Machinelegalizer class for
11 /// AArch64.
12 /// \todo This should be generated by TableGen.
13 //===----------------------------------------------------------------------===//
14 
15 #include "AArch64LegalizerInfo.h"
16 #include "AArch64Subtarget.h"
22 #include "llvm/IR/DerivedTypes.h"
23 #include "llvm/IR/Type.h"
24 
25 using namespace llvm;
26 using namespace LegalizeActions;
27 using namespace LegalityPredicates;
28 
30  using namespace TargetOpcode;
31  const LLT p0 = LLT::pointer(0, 64);
32  const LLT s1 = LLT::scalar(1);
33  const LLT s8 = LLT::scalar(8);
34  const LLT s16 = LLT::scalar(16);
35  const LLT s32 = LLT::scalar(32);
36  const LLT s64 = LLT::scalar(64);
37  const LLT s128 = LLT::scalar(128);
38  const LLT s256 = LLT::scalar(256);
39  const LLT s512 = LLT::scalar(512);
40  const LLT v16s8 = LLT::vector(16, 8);
41  const LLT v8s8 = LLT::vector(8, 8);
42  const LLT v4s8 = LLT::vector(4, 8);
43  const LLT v8s16 = LLT::vector(8, 16);
44  const LLT v4s16 = LLT::vector(4, 16);
45  const LLT v2s16 = LLT::vector(2, 16);
46  const LLT v2s32 = LLT::vector(2, 32);
47  const LLT v4s32 = LLT::vector(4, 32);
48  const LLT v2s64 = LLT::vector(2, 64);
49 
50  getActionDefinitionsBuilder(G_IMPLICIT_DEF)
51  .legalFor({p0, s1, s8, s16, s32, s64})
52  .clampScalar(0, s1, s64)
53  .widenScalarToNextPow2(0, 8);
54 
55  getActionDefinitionsBuilder(G_PHI)
56  .legalFor({p0, s16, s32, s64})
57  .clampScalar(0, s16, s64)
58  .widenScalarToNextPow2(0);
59 
60  getActionDefinitionsBuilder(G_BSWAP)
61  .legalFor({s32, s64})
62  .clampScalar(0, s16, s64)
63  .widenScalarToNextPow2(0);
64 
65  getActionDefinitionsBuilder({G_ADD, G_SUB, G_MUL, G_AND, G_OR, G_XOR, G_SHL})
66  .legalFor({s32, s64, v2s32, v4s32, v2s64})
67  .clampScalar(0, s32, s64)
68  .widenScalarToNextPow2(0)
69  .clampNumElements(0, v2s32, v4s32)
70  .clampNumElements(0, v2s64, v2s64)
71  .moreElementsToNextPow2(0);
72 
73  getActionDefinitionsBuilder(G_GEP)
74  .legalFor({{p0, s64}})
75  .clampScalar(1, s64, s64);
76 
77  getActionDefinitionsBuilder(G_PTR_MASK).legalFor({p0});
78 
79  getActionDefinitionsBuilder({G_LSHR, G_ASHR, G_SDIV, G_UDIV})
80  .legalFor({s32, s64})
81  .clampScalar(0, s32, s64)
82  .widenScalarToNextPow2(0);
83 
84  for (unsigned BinOp : {G_SREM, G_UREM})
85  for (auto Ty : { s1, s8, s16, s32, s64 })
86  setAction({BinOp, Ty}, Lower);
87 
88  for (unsigned Op : {G_SMULO, G_UMULO}) {
89  setAction({Op, 0, s64}, Lower);
90  setAction({Op, 1, s1}, Legal);
91  }
92 
93  getActionDefinitionsBuilder({G_SMULH, G_UMULH}).legalFor({s32, s64});
94 
95  getActionDefinitionsBuilder({G_UADDE, G_USUBE, G_SADDO, G_SSUBO})
96  .legalFor({{s32, s1}, {s64, s1}});
97 
98  getActionDefinitionsBuilder({G_FADD, G_FSUB, G_FMA, G_FMUL, G_FDIV})
99  .legalFor({s32, s64});
100 
101  getActionDefinitionsBuilder({G_FREM, G_FPOW}).libcallFor({s32, s64});
102 
103  getActionDefinitionsBuilder(G_INSERT)
104  .unsupportedIf([=](const LegalityQuery &Query) {
105  return Query.Types[0].getSizeInBits() <= Query.Types[1].getSizeInBits();
106  })
107  .legalIf([=](const LegalityQuery &Query) {
108  const LLT &Ty0 = Query.Types[0];
109  const LLT &Ty1 = Query.Types[1];
110  if (Ty0 != s32 && Ty0 != s64 && Ty0 != p0)
111  return false;
112  return isPowerOf2_32(Ty1.getSizeInBits()) &&
113  (Ty1.getSizeInBits() == 1 || Ty1.getSizeInBits() >= 8);
114  })
115  .clampScalar(0, s32, s64)
116  .widenScalarToNextPow2(0)
117  .maxScalarIf(typeInSet(0, {s32}), 1, s16)
118  .maxScalarIf(typeInSet(0, {s64}), 1, s32)
119  .widenScalarToNextPow2(1);
120 
121  getActionDefinitionsBuilder(G_EXTRACT)
122  .unsupportedIf([=](const LegalityQuery &Query) {
123  return Query.Types[0].getSizeInBits() >= Query.Types[1].getSizeInBits();
124  })
125  .legalIf([=](const LegalityQuery &Query) {
126  const LLT &Ty0 = Query.Types[0];
127  const LLT &Ty1 = Query.Types[1];
128  if (Ty1 != s32 && Ty1 != s64)
129  return false;
130  if (Ty1 == p0)
131  return true;
132  return isPowerOf2_32(Ty0.getSizeInBits()) &&
133  (Ty0.getSizeInBits() == 1 || Ty0.getSizeInBits() >= 8);
134  })
135  .clampScalar(1, s32, s64)
136  .widenScalarToNextPow2(1)
137  .maxScalarIf(typeInSet(1, {s32}), 0, s16)
138  .maxScalarIf(typeInSet(1, {s64}), 0, s32)
139  .widenScalarToNextPow2(0);
140 
141  getActionDefinitionsBuilder({G_LOAD, G_STORE})
142  .legalFor(
143  {{s8, p0}, {s16, p0}, {s32, p0}, {s64, p0}, {p0, p0}, {v2s32, p0}})
144  .clampScalar(0, s8, s64)
145  .widenScalarToNextPow2(0)
146  .clampNumElements(0, v2s32, v2s32);
147 
148  // Constants
149  getActionDefinitionsBuilder(G_CONSTANT)
150  .legalFor({p0, s32, s64})
151  .clampScalar(0, s32, s64)
152  .widenScalarToNextPow2(0);
153  getActionDefinitionsBuilder(G_FCONSTANT)
154  .legalFor({s32, s64})
155  .clampScalar(0, s32, s64);
156 
157  getActionDefinitionsBuilder(G_ICMP)
158  .legalFor({{s32, s32}, {s32, s64}, {s32, p0}})
159  .clampScalar(0, s32, s32)
160  .clampScalar(1, s32, s64)
161  .widenScalarToNextPow2(1);
162 
163  getActionDefinitionsBuilder(G_FCMP)
164  .legalFor({{s32, s32}, {s32, s64}})
165  .clampScalar(0, s32, s32)
166  .clampScalar(1, s32, s64)
167  .widenScalarToNextPow2(1);
168 
169  // Extensions
170  getActionDefinitionsBuilder({G_ZEXT, G_SEXT, G_ANYEXT})
171  .legalFor({s1, s8, s16, s32, s64})
172  .maxScalar(0, s64)
173  .widenScalarToNextPow2(0);
174 
175  // FP conversions
176  getActionDefinitionsBuilder(G_FPTRUNC).legalFor(
177  {{s16, s32}, {s16, s64}, {s32, s64}});
178  getActionDefinitionsBuilder(G_FPEXT).legalFor(
179  {{s32, s16}, {s64, s16}, {s64, s32}});
180 
181  // Conversions
182  getActionDefinitionsBuilder({G_FPTOSI, G_FPTOUI})
183  .legalForCartesianProduct({s32, s64})
184  .clampScalar(0, s32, s64)
185  .widenScalarToNextPow2(0)
186  .clampScalar(1, s32, s64)
187  .widenScalarToNextPow2(1);
188 
189  getActionDefinitionsBuilder({G_SITOFP, G_UITOFP})
190  .legalForCartesianProduct({s32, s64})
191  .clampScalar(1, s32, s64)
192  .widenScalarToNextPow2(1)
193  .clampScalar(0, s32, s64)
194  .widenScalarToNextPow2(0);
195 
196  // Control-flow
197  getActionDefinitionsBuilder(G_BRCOND).legalFor({s1, s8, s16, s32});
198  getActionDefinitionsBuilder(G_BRINDIRECT).legalFor({p0});
199 
200  // Select
201  getActionDefinitionsBuilder(G_SELECT)
202  .legalFor({{s32, s1}, {s64, s1}, {p0, s1}})
203  .clampScalar(0, s32, s64)
204  .widenScalarToNextPow2(0);
205 
206  // Pointer-handling
207  getActionDefinitionsBuilder(G_FRAME_INDEX).legalFor({p0});
208  getActionDefinitionsBuilder(G_GLOBAL_VALUE).legalFor({p0});
209 
210  getActionDefinitionsBuilder(G_PTRTOINT)
211  .legalForCartesianProduct({s1, s8, s16, s32, s64}, {p0})
212  .maxScalar(0, s64)
213  .widenScalarToNextPow2(0, /*Min*/ 8);
214 
215  getActionDefinitionsBuilder(G_INTTOPTR)
216  .unsupportedIf([&](const LegalityQuery &Query) {
217  return Query.Types[0].getSizeInBits() != Query.Types[1].getSizeInBits();
218  })
219  .legalFor({s64, p0});
220 
221  // Casts for 32 and 64-bit width type are just copies.
222  // Same for 128-bit width type, except they are on the FPR bank.
223  getActionDefinitionsBuilder(G_BITCAST)
224  // FIXME: This is wrong since G_BITCAST is not allowed to change the
225  // number of bits but it's what the previous code described and fixing
226  // it breaks tests.
227  .legalForCartesianProduct({s1, s8, s16, s32, s64, s128, v16s8, v8s8, v4s8,
228  v8s16, v4s16, v2s16, v4s32, v2s32, v2s64});
229 
230  getActionDefinitionsBuilder(G_VASTART).legalFor({p0});
231 
232  // va_list must be a pointer, but most sized types are pretty easy to handle
233  // as the destination.
234  getActionDefinitionsBuilder(G_VAARG)
235  .customForCartesianProduct({s8, s16, s32, s64, p0}, {p0})
236  .clampScalar(0, s8, s64)
237  .widenScalarToNextPow2(0, /*Min*/ 8);
238 
239  if (ST.hasLSE()) {
240  getActionDefinitionsBuilder(G_ATOMIC_CMPXCHG)
241  .legalForCartesianProduct({s8, s16, s32, s64}, {p0});
242  }
243 
244  if (ST.hasLSE()) {
245  for (auto Ty : {s8, s16, s32, s64}) {
246  setAction({G_ATOMIC_CMPXCHG_WITH_SUCCESS, Ty}, Lower);
247  }
248 
249  getActionDefinitionsBuilder(
250  {G_ATOMICRMW_XCHG, G_ATOMICRMW_ADD, G_ATOMICRMW_SUB, G_ATOMICRMW_AND,
251  G_ATOMICRMW_OR, G_ATOMICRMW_XOR, G_ATOMICRMW_MIN, G_ATOMICRMW_MAX,
252  G_ATOMICRMW_UMIN, G_ATOMICRMW_UMAX})
253  .legalForCartesianProduct({s8, s16, s32, s64}, {p0});
254  }
255 
256  // Merge/Unmerge
257  for (unsigned Op : {G_MERGE_VALUES, G_UNMERGE_VALUES}) {
258  unsigned BigTyIdx = Op == G_MERGE_VALUES ? 0 : 1;
259  unsigned LitTyIdx = Op == G_MERGE_VALUES ? 1 : 0;
260 
261  auto notValidElt = [](const LegalityQuery &Query, unsigned TypeIdx) {
262  const LLT &Ty = Query.Types[TypeIdx];
263  if (Ty.isVector()) {
264  const LLT &EltTy = Ty.getElementType();
265  if (EltTy.getSizeInBits() < 8 || EltTy.getSizeInBits() > 64)
266  return true;
267  if (!isPowerOf2_32(EltTy.getSizeInBits()))
268  return true;
269  }
270  return false;
271  };
272  auto scalarize =
273  [](const LegalityQuery &Query, unsigned TypeIdx) {
274  const LLT &Ty = Query.Types[TypeIdx];
275  return std::make_pair(TypeIdx, Ty.getElementType());
276  };
277 
278  // FIXME: This rule is horrible, but specifies the same as what we had
279  // before with the particularly strange definitions removed (e.g.
280  // s8 = G_MERGE_VALUES s32, s32).
281  // Part of the complexity comes from these ops being extremely flexible. For
282  // example, you can build/decompose vectors with it, concatenate vectors,
283  // etc. and in addition to this you can also bitcast with it at the same
284  // time. We've been considering breaking it up into multiple ops to make it
285  // more manageable throughout the backend.
286  getActionDefinitionsBuilder(Op)
287  // Break up vectors with weird elements into scalars
288  .fewerElementsIf(
289  [=](const LegalityQuery &Query) { return notValidElt(Query, 0); },
290  [=](const LegalityQuery &Query) { return scalarize(Query, 0); })
291  .fewerElementsIf(
292  [=](const LegalityQuery &Query) { return notValidElt(Query, 1); },
293  [=](const LegalityQuery &Query) { return scalarize(Query, 1); })
294  // Clamp the big scalar to s8-s512 and make it either a power of 2, 192,
295  // or 384.
296  .clampScalar(BigTyIdx, s8, s512)
297  .widenScalarIf(
298  [=](const LegalityQuery &Query) {
299  const LLT &Ty = Query.Types[BigTyIdx];
300  return !isPowerOf2_32(Ty.getSizeInBits()) &&
301  Ty.getSizeInBits() % 64 != 0;
302  },
303  [=](const LegalityQuery &Query) {
304  // Pick the next power of 2, or a multiple of 64 over 128.
305  // Whichever is smaller.
306  const LLT &Ty = Query.Types[BigTyIdx];
307  unsigned NewSizeInBits = 1
308  << Log2_32_Ceil(Ty.getSizeInBits() + 1);
309  if (NewSizeInBits >= 256) {
310  unsigned RoundedTo = alignTo<64>(Ty.getSizeInBits() + 1);
311  if (RoundedTo < NewSizeInBits)
312  NewSizeInBits = RoundedTo;
313  }
314  return std::make_pair(BigTyIdx, LLT::scalar(NewSizeInBits));
315  })
316  // Clamp the little scalar to s8-s256 and make it a power of 2. It's not
317  // worth considering the multiples of 64 since 2*192 and 2*384 are not
318  // valid.
319  .clampScalar(LitTyIdx, s8, s256)
320  .widenScalarToNextPow2(LitTyIdx, /*Min*/ 8)
321  // So at this point, we have s8, s16, s32, s64, s128, s192, s256, s384,
322  // s512, <X x s8>, <X x s16>, <X x s32>, or <X x s64>.
323  // At this point it's simple enough to accept the legal types.
324  .legalIf([=](const LegalityQuery &Query) {
325  const LLT &BigTy = Query.Types[BigTyIdx];
326  const LLT &LitTy = Query.Types[LitTyIdx];
327  if (BigTy.isVector() && BigTy.getSizeInBits() < 32)
328  return false;
329  if (LitTy.isVector() && LitTy.getSizeInBits() < 32)
330  return false;
331  return BigTy.getSizeInBits() % LitTy.getSizeInBits() == 0;
332  })
333  // Any vectors left are the wrong size. Scalarize them.
334  .fewerElementsIf([](const LegalityQuery &Query) { return true; },
335  [](const LegalityQuery &Query) {
336  return std::make_pair(
337  0, Query.Types[0].getElementType());
338  })
339  .fewerElementsIf([](const LegalityQuery &Query) { return true; },
340  [](const LegalityQuery &Query) {
341  return std::make_pair(
342  1, Query.Types[1].getElementType());
343  });
344  }
345 
346  computeTables();
347 }
348 
351  MachineIRBuilder &MIRBuilder) const {
352  switch (MI.getOpcode()) {
353  default:
354  // No idea what to do.
355  return false;
356  case TargetOpcode::G_VAARG:
357  return legalizeVaArg(MI, MRI, MIRBuilder);
358  }
359 
360  llvm_unreachable("expected switch to return");
361 }
362 
363 bool AArch64LegalizerInfo::legalizeVaArg(MachineInstr &MI,
365  MachineIRBuilder &MIRBuilder) const {
366  MIRBuilder.setInstr(MI);
367  MachineFunction &MF = MIRBuilder.getMF();
368  unsigned Align = MI.getOperand(2).getImm();
369  unsigned Dst = MI.getOperand(0).getReg();
370  unsigned ListPtr = MI.getOperand(1).getReg();
371 
372  LLT PtrTy = MRI.getType(ListPtr);
373  LLT IntPtrTy = LLT::scalar(PtrTy.getSizeInBits());
374 
375  const unsigned PtrSize = PtrTy.getSizeInBits() / 8;
376  unsigned List = MRI.createGenericVirtualRegister(PtrTy);
377  MIRBuilder.buildLoad(
378  List, ListPtr,
380  PtrSize, /* Align = */ PtrSize));
381 
382  unsigned DstPtr;
383  if (Align > PtrSize) {
384  // Realign the list to the actual required alignment.
385  auto AlignMinus1 = MIRBuilder.buildConstant(IntPtrTy, Align - 1);
386 
387  unsigned ListTmp = MRI.createGenericVirtualRegister(PtrTy);
388  MIRBuilder.buildGEP(ListTmp, List, AlignMinus1->getOperand(0).getReg());
389 
390  DstPtr = MRI.createGenericVirtualRegister(PtrTy);
391  MIRBuilder.buildPtrMask(DstPtr, ListTmp, Log2_64(Align));
392  } else
393  DstPtr = List;
394 
395  uint64_t ValSize = MRI.getType(Dst).getSizeInBits() / 8;
396  MIRBuilder.buildLoad(
397  Dst, DstPtr,
399  ValSize, std::max(Align, PtrSize)));
400 
401  unsigned SizeReg = MRI.createGenericVirtualRegister(IntPtrTy);
402  MIRBuilder.buildConstant(SizeReg, alignTo(ValSize, PtrSize));
403 
404  unsigned NewList = MRI.createGenericVirtualRegister(PtrTy);
405  MIRBuilder.buildGEP(NewList, DstPtr, SizeReg);
406 
407  MIRBuilder.buildStore(
408  NewList, ListPtr,
410  PtrSize, /* Align = */ PtrSize));
411 
412  MI.eraseFromParent();
413  return true;
414 }
unsigned Log2_32_Ceil(uint32_t Value)
Return the ceil log base 2 of the specified value, 32 if the value is zero.
Definition: MathExtras.h:544
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
GCNRegPressure max(const GCNRegPressure &P1, const GCNRegPressure &P2)
MachineInstrBuilder buildGEP(unsigned Res, unsigned Op0, unsigned Op1)
Build and insert Res = G_GEP Op0, Op1.
Compute iterated dominance frontiers using a linear time algorithm.
Definition: AllocatorList.h:24
The LegalityQuery object bundles together all the information that&#39;s needed to decide whether a given...
unsigned getReg() const
getReg - Returns the register number.
uint64_t alignTo(uint64_t Value, uint64_t Align, uint64_t Skew=0)
Returns the next integer (mod 2**64) that is greater than or equal to Value and is a multiple of Alig...
Definition: MathExtras.h:677
unsigned createGenericVirtualRegister(LLT Ty)
Create and return a new generic virtual register with low-level type Ty.
MachineInstrBuilder buildStore(unsigned Val, unsigned Addr, MachineMemOperand &MMO)
Build and insert G_STORE Val, Addr, MMO.
bool isVector() const
void eraseFromParent()
Unlink &#39;this&#39; from the containing basic block and delete it.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
Definition: MachineInstr.h:293
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.
LLT getElementType() const
Returns the vector&#39;s element type. Only valid for vector types.
This file declares the targeting of the Machinelegalizer class for AArch64.
MachineFunction & getMF()
Getter for the function we currently build.
static LLT scalar(unsigned SizeInBits)
Get a low-level scalar or aggregate "bag of bits".
The operation itself must be expressed in terms of simpler actions on this target.
Definition: LegalizerInfo.h:67
unsigned const MachineRegisterInfo * MRI
constexpr bool isPowerOf2_32(uint32_t Value)
Return true if the argument is a power of two > 0.
Definition: MathExtras.h:421
AArch64LegalizerInfo(const AArch64Subtarget &ST)
MachineInstrBuilder buildPtrMask(unsigned Res, unsigned Op0, uint32_t NumBits)
Build and insert Res = G_PTR_MASK Op0, NumBits.
Helper class to build MachineInstr.
void setInstr(MachineInstr &MI)
Set the insertion point to before MI.
This class contains a discriminated union of information about pointers in memory operands...
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
The memory access writes data.
bool legalizeCustom(MachineInstr &MI, MachineRegisterInfo &MRI, MachineIRBuilder &MIRBuilder) const override
unsigned getSizeInBits() const
Returns the total size of the type. Must only be called on sized types.
int64_t getImm() const
This file declares the MachineIRBuilder class.
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:60
ArrayRef< LLT > Types
MachineInstrBuilder buildConstant(unsigned Res, const ConstantInt &Val)
Build and insert Res = G_CONSTANT Val.
const NodeList & List
Definition: RDFGraph.cpp:210
LLT getType(unsigned VReg) const
Get the low-level type of VReg or LLT{} if VReg is not a generic (target independent) virtual registe...
LegalityPredicate typeInSet(unsigned TypeIdx, std::initializer_list< LLT > TypesInit)
True iff the given type index is one of the specified types.
static void Query(const MachineInstr &MI, AliasAnalysis &AA, bool &Read, bool &Write, bool &Effects, bool &StackPointer)
static LLT pointer(uint16_t AddressSpace, unsigned SizeInBits)
Get a low-level pointer in the given address space (defaulting to 0).
MachineInstrBuilder buildLoad(unsigned Res, unsigned Addr, MachineMemOperand &MMO)
Build and insert Res = G_LOAD Addr, MMO.
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.
const MachineOperand & getOperand(unsigned i) const
Definition: MachineInstr.h:298
The operation is expected to be selectable directly by the target, and no transformation is necessary...
Definition: LegalizerInfo.h:42
unsigned Log2_64(uint64_t Value)
Return the floor log base 2 of the specified value, -1 if the value is zero.
Definition: MathExtras.h:537