forked from stichnot/subzero
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathIceOperand.h
340 lines (309 loc) · 11.7 KB
/
IceOperand.h
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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
// -*- Mode: c++ -*-
/* Copyright 2014 The Native Client Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can
* be found in the LICENSE file.
*/
#ifndef _IceOperand_h
#define _IceOperand_h
#include "IceDefs.h"
#include "IceTypes.h"
/*
Operand (rvalue)
Constant
ActualInteger
ActualFloat (bits that go into module constant pool)
Symbolic
Symbolic+Integer (e.g. address)
Variable (stack or register - lvalue)
load/store instructions can take a global (constant?)
or maybe a TLS address
*/
class IceOperand {
public:
enum OperandKind {
Constant,
ConstantInteger,
ConstantFloat,
ConstantDouble,
ConstantRelocatable,
Constant_Num,
Variable,
// Target-specific operand classes can use Target as their
// starting type.
Target
};
IceType getType(void) const { return Type; }
OperandKind getKind(void) const { return Kind; }
IceVariable *getVar(unsigned I) const {
assert(I < getNumVars());
return Vars[I];
}
unsigned getNumVars(void) const { return NumVars; }
virtual void setUse(const IceInst *Inst, const IceCfgNode *Node) {}
virtual void emit(IceOstream &Str, uint32_t Option) const;
virtual void dump(IceOstream &Str) const;
virtual ~IceOperand() {}
protected:
IceOperand(IceCfg *Cfg, OperandKind Kind, IceType Type)
: Type(Type), Kind(Kind) {}
const IceType Type;
const OperandKind Kind;
IceVariable **Vars;
unsigned NumVars;
};
IceOstream &operator<<(IceOstream &Str, const IceOperand *O);
// TODO: better design of a minimal per-module constant pool,
// including synchronized access for parallel translation.
class IceConstant : public IceOperand {
public:
virtual void emit(IceOstream &Str, uint32_t Option) const = 0;
virtual void dump(IceOstream &Str) const = 0;
static bool classof(const IceOperand *Operand) {
OperandKind Kind = Operand->getKind();
return Kind >= Constant && Kind <= Constant_Num;
}
protected:
IceConstant(IceCfg *Cfg, OperandKind Kind, IceType Type)
: IceOperand(Cfg, Kind, Type) {
Vars = NULL;
NumVars = 0;
}
};
class IceConstantInteger : public IceConstant {
public:
static IceConstantInteger *create(IceCfg *Cfg, IceType Type,
uint64_t IntValue) {
return new IceConstantInteger(Cfg, Type, IntValue);
}
uint64_t getIntValue(void) const { return IntValue; }
virtual void emit(IceOstream &Str, uint32_t Option) const;
virtual void dump(IceOstream &Str) const;
static bool classof(const IceOperand *Operand) {
OperandKind Kind = Operand->getKind();
return Kind == ConstantInteger;
}
private:
IceConstantInteger(IceCfg *Cfg, IceType Type, uint64_t IntValue)
: IceConstant(Cfg, ConstantInteger, Type), IntValue(IntValue) {}
const uint64_t IntValue;
};
class IceConstantFloat : public IceConstant {
public:
static IceConstantFloat *create(IceCfg *Cfg, float FloatValue) {
return new IceConstantFloat(Cfg, FloatValue);
}
float getFloatValue(void) const { return FloatValue; }
virtual void emit(IceOstream &Str, uint32_t Option) const;
virtual void dump(IceOstream &Str) const;
static bool classof(const IceOperand *Operand) {
OperandKind Kind = Operand->getKind();
return Kind == ConstantFloat;
}
private:
IceConstantFloat(IceCfg *Cfg, float FloatValue)
: IceConstant(Cfg, ConstantFloat, IceType_f32), FloatValue(FloatValue) {}
const float FloatValue;
};
class IceConstantDouble : public IceConstant {
public:
static IceConstantDouble *create(IceCfg *Cfg, double DoubleValue) {
return new IceConstantDouble(Cfg, DoubleValue);
}
double getDoubleValue(void) const { return DoubleValue; }
virtual void emit(IceOstream &Str, uint32_t Option) const;
virtual void dump(IceOstream &Str) const;
static bool classof(const IceOperand *Operand) {
OperandKind Kind = Operand->getKind();
return Kind == ConstantDouble;
}
private:
IceConstantDouble(IceCfg *Cfg, double DoubleValue)
: IceConstant(Cfg, ConstantDouble, IceType_f32),
DoubleValue(DoubleValue) {}
const double DoubleValue;
};
class IceConstantRelocatable : public IceConstant {
public:
static IceConstantRelocatable *create(IceCfg *Cfg, uint32_t CPIndex,
IceType Type, const void *Handle,
int64_t Offset,
const IceString &Name = "") {
return new IceConstantRelocatable(Cfg, Type, Handle, Offset, Name, CPIndex);
}
uint32_t getCPIndex(void) const { return CPIndex; }
const void *getHandle(void) const { return Handle; }
int64_t getOffset(void) const { return Offset; }
IceString getName(void) const { return Name; }
virtual void emit(IceOstream &Str, uint32_t Option) const;
virtual void dump(IceOstream &Str) const;
static bool classof(const IceOperand *Operand) {
OperandKind Kind = Operand->getKind();
return Kind == ConstantRelocatable;
}
private:
IceConstantRelocatable(IceCfg *Cfg, IceType Type, const void *Handle,
int64_t Offset, const IceString &Name,
uint32_t CPIndex)
: IceConstant(Cfg, ConstantRelocatable, Type), CPIndex(CPIndex),
Handle(Handle), Offset(Offset), Name(Name) {}
const uint32_t CPIndex; // index into ICE constant pool
const void *const Handle; // opaque handle e.g. to LLVM
const int64_t Offset; // fixed offset to add
const IceString Name; // optional for debug/dump
};
class IceRegWeight {
public:
IceRegWeight(void) : Weight(0) {}
IceRegWeight(uint32_t Weight) : Weight(Weight) {}
const static uint32_t Inf = ~0;
void addWeight(uint32_t Delta) {
if (Delta == Inf)
Weight = Inf;
else if (Weight != Inf)
Weight += Delta;
}
void addWeight(const IceRegWeight &Other) { addWeight(Other.Weight); }
void setWeight(uint32_t Val) { Weight = Val; }
uint32_t getWeight(void) const { return Weight; }
bool isInf(void) const { return Weight == Inf; }
private:
uint32_t Weight;
};
IceOstream &operator<<(IceOstream &Str, const IceRegWeight &W);
bool operator<(const IceRegWeight &A, const IceRegWeight &B);
bool operator<=(const IceRegWeight &A, const IceRegWeight &B);
// USE_SET uses std::set to hold the segments instead of std::list.
// Using std::list will be slightly faster, but is more restrictive
// because new segments cannot be added in the middle.
//#define USE_SET
class IceLiveRange {
public:
IceLiveRange(void) : Weight(0) {}
int getStart(void) const { return Range.empty() ? -1 : Range.begin()->first; }
void reset(void) {
Range.clear();
Weight.setWeight(0);
}
void addSegment(int Start, int End);
bool endsBefore(const IceLiveRange &Other) const;
bool overlaps(const IceLiveRange &Other) const;
bool containsValue(int Value) const;
bool isEmpty(void) const { return Range.empty(); }
IceRegWeight getWeight(void) const { return Weight; }
void setWeight(const IceRegWeight &NewWeight) { Weight = NewWeight; }
void addWeight(uint32_t Delta) { Weight.addWeight(Delta); }
void dump(IceOstream &Str) const;
private:
typedef std::pair<int, int> RangeElementType;
#ifdef USE_SET
typedef std::set<RangeElementType> RangeType;
#else
typedef std::list<RangeElementType> RangeType;
#endif
RangeType Range;
IceRegWeight Weight;
};
IceOstream &operator<<(IceOstream &Str, const IceLiveRange &L);
// Stack operand, or virtual or physical register
class IceVariable : public IceOperand {
public:
static IceVariable *create(IceCfg *Cfg, IceType Type, const IceCfgNode *Node,
uint32_t Index, const IceString &Name) {
return new IceVariable(Cfg, Type, Node, Index, Name);
}
void setUse(const IceInst *Inst, const IceCfgNode *Node);
uint32_t getIndex(void) const { return Number; }
IceInst *getDefinition(void) const { return DefInst; }
void setDefinition(IceInst *Inst, const IceCfgNode *Node);
void replaceDefinition(IceInst *Inst, const IceCfgNode *Node);
// TODO: consider initializing IsArgument in the ctor.
bool getIsArg(void) const { return IsArgument; }
void setIsArg(IceCfg *Cfg);
IceVariable *getLow(void) const { return LowVar; }
IceVariable *getHigh(void) const { return HighVar; }
void setLow(IceVariable *Low) {
assert(LowVar == NULL);
LowVar = Low;
}
void setHigh(IceVariable *High) {
assert(HighVar == NULL);
HighVar = High;
}
bool isMultiblockLife(void) const { return (DefOrUseNode == NULL); }
const IceCfgNode *getLocalUseNode() const { return DefOrUseNode; }
void setRegNum(int NewRegNum) {
assert(RegNum < 0 ||
RegNum == NewRegNum); // shouldn't set it more than once
RegNum = NewRegNum;
}
int getRegNum(void) const { return RegNum; }
void setRegNumTmp(int NewRegNum) { RegNumTmp = NewRegNum; }
int getRegNumTmp(void) const { return RegNumTmp; }
void setStackOffset(int Offset) { StackOffset = Offset; }
int getStackOffset(void) const { return StackOffset; }
void setWeight(uint32_t NewWeight) { Weight = NewWeight; }
void setWeightInfinite(void) { Weight = IceRegWeight::Inf; }
IceRegWeight getWeight(void) const { return Weight; }
void setPreferredRegister(IceVariable *Prefer, bool Overlap) {
RegisterPreference = Prefer;
AllowRegisterOverlap = Overlap;
}
IceVariable *getPreferredRegister(void) const { return RegisterPreference; }
bool getRegisterOverlap(void) const { return AllowRegisterOverlap; }
void resetLiveRange(void) { LiveRange.reset(); }
void setLiveRange(const IceLiveRange &Range) { LiveRange = Range; }
void addLiveRange(int Start, int End, uint32_t WeightDelta) {
assert(WeightDelta != IceRegWeight::Inf);
LiveRange.addSegment(Start, End);
if (Weight.isInf())
LiveRange.setWeight(IceRegWeight::Inf);
else
LiveRange.addWeight(WeightDelta * Weight.getWeight());
}
const IceLiveRange &getLiveRange(void) const { return LiveRange; }
void setLiveRangeInfiniteWeight(void) {
LiveRange.setWeight(IceRegWeight::Inf);
}
IceString getName(void) const;
virtual void emit(IceOstream &Str, uint32_t Option) const;
virtual void dump(IceOstream &Str) const;
static bool classof(const IceOperand *Operand) {
return Operand->getKind() == Variable;
}
private:
IceVariable(IceCfg *Cfg, IceType Type, const IceCfgNode *Node, uint32_t Index,
const IceString &Name)
: IceOperand(Cfg, Variable, Type), Number(Index), Name(Name),
DefInst(NULL), DefOrUseNode(Node), IsArgument(false), StackOffset(0),
RegNum(-1), RegNumTmp(-1), Weight(1), RegisterPreference(NULL),
AllowRegisterOverlap(false), LowVar(NULL), HighVar(NULL) {
Vars = new IceVariable *[1];
Vars[0] = this;
NumVars = 1;
}
const uint32_t Number;
const IceString Name;
// TODO: A Phi instruction lowers into several assignment
// instructions with the same dest. These should all be tracked
// here so that they can all be deleted when this variable's use
// count reaches zero.
IceInst *DefInst;
const IceCfgNode *DefOrUseNode; // for detecting isMultiblockLife()
bool IsArgument;
int
StackOffset; // Canonical location on stack (only if RegNum==-1 || IsArgument)
int RegNum; // Allocated register; -1 for no allocation
int RegNumTmp; // Tentative assignment during register allocation
IceRegWeight Weight; // Register allocation priority
IceVariable *RegisterPreference;
bool AllowRegisterOverlap;
IceLiveRange LiveRange;
// When lowering from I64 to I32 on a 32-bit architecture, we split
// the variable into two machine-size pieces. LowVar is the
// low-order machine-size portion, and HighVar is the remaining
// high-order portion. TODO: It's wasteful to penalize all
// variables on all targets this way; use a sparser representation.
IceVariable *LowVar;
IceVariable *HighVar;
};
#endif // _IceOperand_h