1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
|
//===---- lib/CodeGen/GlobalISel/MachineLegalizer.cpp - IRTranslator -------==//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Implement an interface to specify and query how an illegal operation on a
// given type should be expanded.
//
// Issues to be resolved:
// + Make it fast.
// + Support weird types like i3, <7 x i3>, ...
// + Operations with more than one type (ICMP, CMPXCHG, intrinsics, ...)
//
//===----------------------------------------------------------------------===//
#include "llvm/CodeGen/GlobalISel/MachineLegalizer.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/ValueTypes.h"
#include "llvm/IR/Type.h"
#include "llvm/Target/TargetOpcodes.h"
using namespace llvm;
MachineLegalizer::MachineLegalizer() : TablesInitialized(false) {
// FIXME: these two can be legalized to the fundamental load/store Jakob
// proposed. Once loads & stores are supported.
DefaultActions[TargetOpcode::G_ANYEXT] = Legal;
DefaultActions[TargetOpcode::G_TRUNC] = Legal;
// G_TYPE is essentially an annotated COPY so it's always legal.
DefaultActions[TargetOpcode::G_TYPE] = Legal;
DefaultActions[TargetOpcode::G_INTRINSIC] = Legal;
DefaultActions[TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS] = Legal;
DefaultActions[TargetOpcode::G_ADD] = NarrowScalar;
DefaultActions[TargetOpcode::G_BRCOND] = WidenScalar;
}
void MachineLegalizer::computeTables() {
for (unsigned Opcode = 0; Opcode <= LastOp - FirstOp; ++Opcode) {
for (unsigned Idx = 0; Idx != Actions[Opcode].size(); ++Idx) {
for (auto &Action : Actions[Opcode][Idx]) {
LLT Ty = Action.first;
if (!Ty.isVector())
continue;
auto &Entry = MaxLegalVectorElts[std::make_pair(Opcode + FirstOp,
Ty.getElementType())];
Entry = std::max(Entry, Ty.getNumElements());
}
}
}
TablesInitialized = true;
}
// FIXME: inefficient implementation for now. Without ComputeValueVTs we're
// probably going to need specialized lookup structures for various types before
// we have any hope of doing well with something like <13 x i3>. Even the common
// cases should do better than what we have now.
std::pair<MachineLegalizer::LegalizeAction, LLT>
MachineLegalizer::getAction(const InstrAspect &Aspect) const {
assert(TablesInitialized && "backend forgot to call computeTables");
// These *have* to be implemented for now, they're the fundamental basis of
// how everything else is transformed.
// FIXME: the long-term plan calls for expansion in terms of load/store (if
// they're not legal).
if (Aspect.Opcode == TargetOpcode::G_SEQUENCE ||
Aspect.Opcode == TargetOpcode::G_EXTRACT)
return std::make_pair(Legal, Aspect.Type);
LegalizeAction Action = findInActions(Aspect);
if (Action != NotFound)
return findLegalAction(Aspect, Action);
unsigned Opcode = Aspect.Opcode;
LLT Ty = Aspect.Type;
if (!Ty.isVector()) {
auto DefaultAction = DefaultActions.find(Aspect.Opcode);
if (DefaultAction != DefaultActions.end() && DefaultAction->second == Legal)
return std::make_pair(Legal, Ty);
assert(DefaultAction->second == NarrowScalar && "unexpected default");
return findLegalAction(Aspect, NarrowScalar);
}
LLT EltTy = Ty.getElementType();
int NumElts = Ty.getNumElements();
auto ScalarAction = ScalarInVectorActions.find(std::make_pair(Opcode, EltTy));
if (ScalarAction != ScalarInVectorActions.end() &&
ScalarAction->second != Legal)
return findLegalAction(Aspect, ScalarAction->second);
// The element type is legal in principle, but the number of elements is
// wrong.
auto MaxLegalElts = MaxLegalVectorElts.lookup(std::make_pair(Opcode, EltTy));
if (MaxLegalElts > NumElts)
return findLegalAction(Aspect, MoreElements);
if (MaxLegalElts == 0) {
// Scalarize if there's no legal vector type, which is just a special case
// of FewerElements.
return std::make_pair(FewerElements, EltTy);
}
return findLegalAction(Aspect, FewerElements);
}
std::tuple<MachineLegalizer::LegalizeAction, unsigned, LLT>
MachineLegalizer::getAction(const MachineInstr &MI) const {
for (unsigned i = 0; i < MI.getNumTypes(); ++i) {
auto Action = getAction({MI.getOpcode(), i, MI.getType(i)});
if (Action.first != Legal)
return std::make_tuple(Action.first, i, Action.second);
}
return std::make_tuple(Legal, 0, LLT{});
}
bool MachineLegalizer::isLegal(const MachineInstr &MI) const {
return std::get<0>(getAction(MI)) == Legal;
}
LLT MachineLegalizer::findLegalType(const InstrAspect &Aspect,
LegalizeAction Action) const {
switch(Action) {
default:
llvm_unreachable("Cannot find legal type");
case Legal:
case Lower:
case Libcall:
return Aspect.Type;
case NarrowScalar: {
return findLegalType(Aspect,
[&](LLT Ty) -> LLT { return Ty.halfScalarSize(); });
}
case WidenScalar: {
return findLegalType(Aspect, [&](LLT Ty) -> LLT {
return Ty.getSizeInBits() < 8 ? LLT::scalar(8) : Ty.doubleScalarSize();
});
}
case FewerElements: {
return findLegalType(Aspect,
[&](LLT Ty) -> LLT { return Ty.halfElements(); });
}
case MoreElements: {
return findLegalType(Aspect,
[&](LLT Ty) -> LLT { return Ty.doubleElements(); });
}
}
}
|