blob: 786f51b5772bde7c3ae77b6c3b3674a9826fd8af [file] [log] [blame]
Jim Stichnothf7c9a142014-04-29 10:52:43 -07001//===- subzero/src/IceOperand.h - High-level operands -----------*- C++ -*-===//
2//
3// The Subzero Code Generator
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file declares the Operand class and its target-independent
11// subclasses. The main classes are Variable, which represents an
12// LLVM variable that is either register- or stack-allocated, and the
13// Constant hierarchy, which represents integer, floating-point,
14// and/or symbolic constants.
15//
16//===----------------------------------------------------------------------===//
17
18#ifndef SUBZERO_SRC_ICEOPERAND_H
19#define SUBZERO_SRC_ICEOPERAND_H
20
Jan Voungfe14fb82014-10-13 15:56:32 -070021#include "IceCfg.h"
Jim Stichnothf7c9a142014-04-29 10:52:43 -070022#include "IceDefs.h"
Jan Voungfe14fb82014-10-13 15:56:32 -070023#include "IceGlobalContext.h"
Jim Stichnothf7c9a142014-04-29 10:52:43 -070024#include "IceTypes.h"
25
26namespace Ice {
27
28class Operand {
Jim Stichnothc6ead202015-02-24 09:30:30 -080029 Operand() = delete;
Jim Stichnoth7b451a92014-10-15 14:39:23 -070030 Operand(const Operand &) = delete;
31 Operand &operator=(const Operand &) = delete;
32
Jim Stichnothf7c9a142014-04-29 10:52:43 -070033public:
Jim Stichnoth800dab22014-09-20 12:25:02 -070034 static const size_t MaxTargetKinds = 10;
Jim Stichnothf7c9a142014-04-29 10:52:43 -070035 enum OperandKind {
36 kConst_Base,
Jan Voungbc004632014-09-16 15:09:10 -070037 kConstInteger32,
38 kConstInteger64,
Jim Stichnothf7c9a142014-04-29 10:52:43 -070039 kConstFloat,
40 kConstDouble,
41 kConstRelocatable,
Matt Walad8f4a7d2014-06-18 09:55:03 -070042 kConstUndef,
Jim Stichnoth800dab22014-09-20 12:25:02 -070043 kConst_Target, // leave space for target-specific constant kinds
44 kConst_Num = kConst_Target + MaxTargetKinds,
Jim Stichnothf7c9a142014-04-29 10:52:43 -070045 kVariable,
Jim Stichnoth800dab22014-09-20 12:25:02 -070046 kVariable_Target, // leave space for target-specific variable kinds
47 kVariable_Num = kVariable_Target + MaxTargetKinds,
Jim Stichnothf7c9a142014-04-29 10:52:43 -070048 // Target-specific operand classes use kTarget as the starting
Jan Voungb3401d22015-05-18 09:38:21 -070049 // point for their Kind enum space. Note that the value-spaces are shared
50 // across targets. To avoid confusion over the definition of shared
51 // values, an object specific to one target should never be passed
52 // to a different target.
Jim Stichnothf7c9a142014-04-29 10:52:43 -070053 kTarget
54 };
55 OperandKind getKind() const { return Kind; }
56 Type getType() const { return Ty; }
57
58 // Every Operand keeps an array of the Variables referenced in
59 // the operand. This is so that the liveness operations can get
60 // quick access to the variables of interest, without having to dig
61 // so far into the operand.
62 SizeT getNumVars() const { return NumVars; }
63 Variable *getVar(SizeT I) const {
64 assert(I < getNumVars());
65 return Vars[I];
66 }
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -070067 virtual void emit(const Cfg *Func) const = 0;
Jim Stichnoth2e8bfbb2014-09-16 10:16:00 -070068 // The dump(Func,Str) implementation must be sure to handle the
Jim Stichnothae953202014-12-20 06:17:49 -080069 // situation where Func==nullptr.
Jim Stichnoth2e8bfbb2014-09-16 10:16:00 -070070 virtual void dump(const Cfg *Func, Ostream &Str) const = 0;
71 void dump(const Cfg *Func) const {
Jim Stichnoth20b71f52015-06-24 15:52:24 -070072 if (!BuildDefs::dump())
Karl Schimpfb6c96af2014-11-17 10:58:39 -080073 return;
Jim Stichnoth2e8bfbb2014-09-16 10:16:00 -070074 assert(Func);
75 dump(Func, Func->getContext()->getStrDump());
76 }
Karl Schimpfb6c96af2014-11-17 10:58:39 -080077 void dump(Ostream &Str) const {
Jim Stichnoth20b71f52015-06-24 15:52:24 -070078 if (BuildDefs::dump())
Jim Stichnothae953202014-12-20 06:17:49 -080079 dump(nullptr, Str);
Karl Schimpfb6c96af2014-11-17 10:58:39 -080080 }
Jim Stichnothf7c9a142014-04-29 10:52:43 -070081
Jim Stichnothf7c9a142014-04-29 10:52:43 -070082protected:
Jim Stichnotheafb56c2015-06-22 10:35:22 -070083 Operand(OperandKind Kind, Type Ty) : Ty(Ty), Kind(Kind) {}
Jim Stichnothf7c9a142014-04-29 10:52:43 -070084
85 const Type Ty;
86 const OperandKind Kind;
87 // Vars and NumVars are initialized by the derived class.
Jim Stichnotheafb56c2015-06-22 10:35:22 -070088 SizeT NumVars = 0;
89 Variable **Vars = nullptr;
Jim Stichnothf7c9a142014-04-29 10:52:43 -070090};
91
Jim Stichnothdd842db2015-01-27 12:53:53 -080092template <class StreamType>
Karl Schimpf97501832014-09-16 13:35:32 -070093inline StreamType &operator<<(StreamType &Str, const Operand &Op) {
94 Op.dump(Str);
95 return Str;
96}
97
Jim Stichnothf7c9a142014-04-29 10:52:43 -070098// Constant is the abstract base class for constants. All
99// constants are allocated from a global arena and are pooled.
100class Constant : public Operand {
Jim Stichnothc6ead202015-02-24 09:30:30 -0800101 Constant() = delete;
Jim Stichnoth7b451a92014-10-15 14:39:23 -0700102 Constant(const Constant &) = delete;
103 Constant &operator=(const Constant &) = delete;
104
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700105public:
Jan Voung1d62cf02015-01-09 14:57:32 -0800106 void emitPoolLabel(Ostream &Str) const {
107 Str << ".L$" << getType() << "$" << PoolEntryID;
108 }
Jan Voung76bb0be2015-05-14 09:26:19 -0700109 void emit(const Cfg *Func) const override { emit(Func->getTarget()); }
110 virtual void emit(TargetLowering *Target) const = 0;
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700111
112 static bool classof(const Operand *Operand) {
113 OperandKind Kind = Operand->getKind();
114 return Kind >= kConst_Base && Kind <= kConst_Num;
115 }
116
Qining Lu253dc8a2015-06-22 10:10:23 -0700117 // Judge if this given immediate should be randomized or pooled
118 // By default should return false, only constant integers should
119 // truly go through this method.
120 virtual bool shouldBeRandomizedOrPooled(const GlobalContext *Ctx) {
121 (void)Ctx;
122 return false;
123 }
124
125 void setShouldBePooled(bool R) { shouldBePooled = R; }
126
127 bool getShouldBePooled() const { return shouldBePooled; }
128
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700129protected:
Jim Stichnothf61d5b22014-05-23 13:31:24 -0700130 Constant(OperandKind Kind, Type Ty, uint32_t PoolEntryID)
Qining Lu253dc8a2015-06-22 10:10:23 -0700131 : Operand(Kind, Ty), PoolEntryID(PoolEntryID), shouldBePooled(false) {
Jim Stichnothae953202014-12-20 06:17:49 -0800132 Vars = nullptr;
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700133 NumVars = 0;
134 }
Jim Stichnothf61d5b22014-05-23 13:31:24 -0700135 // PoolEntryID is an integer that uniquely identifies the constant
136 // within its constant pool. It is used for building the constant
137 // pool in the object code and for referencing its entries.
138 const uint32_t PoolEntryID;
Qining Lu253dc8a2015-06-22 10:10:23 -0700139 // Whether we should pool this constant. Usually Float/Double and pooled
140 // Integers should be flagged true.
141 bool shouldBePooled;
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700142};
143
144// ConstantPrimitive<> wraps a primitive type.
145template <typename T, Operand::OperandKind K>
146class ConstantPrimitive : public Constant {
Jim Stichnothc6ead202015-02-24 09:30:30 -0800147 ConstantPrimitive() = delete;
Jim Stichnoth7b451a92014-10-15 14:39:23 -0700148 ConstantPrimitive(const ConstantPrimitive &) = delete;
149 ConstantPrimitive &operator=(const ConstantPrimitive &) = delete;
150
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700151public:
Jan Voung91a3e2c2015-01-09 13:01:42 -0800152 typedef T PrimType;
153
154 static ConstantPrimitive *create(GlobalContext *Ctx, Type Ty, PrimType Value,
Jim Stichnothf61d5b22014-05-23 13:31:24 -0700155 uint32_t PoolEntryID) {
Karl Schimpf6fcbddd2014-11-06 09:49:24 -0800156 assert(!Ctx->isIRGenerationDisabled() &&
157 "Attempt to build primitive constant when IR generation disabled");
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700158 return new (Ctx->allocate<ConstantPrimitive>())
Jim Stichnothf61d5b22014-05-23 13:31:24 -0700159 ConstantPrimitive(Ty, Value, PoolEntryID);
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700160 }
Jan Voung91a3e2c2015-01-09 13:01:42 -0800161 PrimType getValue() const { return Value; }
Jim Stichnothd97c7df2014-06-04 11:57:08 -0700162 using Constant::emit;
Jan Voung76bb0be2015-05-14 09:26:19 -0700163 void emit(TargetLowering *Target) const final;
Jim Stichnothd97c7df2014-06-04 11:57:08 -0700164 using Constant::dump;
Karl Schimpfb6c96af2014-11-17 10:58:39 -0800165 void dump(const Cfg *, Ostream &Str) const override {
Jim Stichnoth20b71f52015-06-24 15:52:24 -0700166 if (BuildDefs::dump())
Karl Schimpfb6c96af2014-11-17 10:58:39 -0800167 Str << getValue();
168 }
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700169
170 static bool classof(const Operand *Operand) {
171 return Operand->getKind() == K;
172 }
173
Qining Lu253dc8a2015-06-22 10:10:23 -0700174 virtual bool shouldBeRandomizedOrPooled(const GlobalContext *Ctx) override {
175 (void)Ctx;
176 return false;
177 }
178
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700179private:
Jan Voung91a3e2c2015-01-09 13:01:42 -0800180 ConstantPrimitive(Type Ty, PrimType Value, uint32_t PoolEntryID)
Jim Stichnothf61d5b22014-05-23 13:31:24 -0700181 : Constant(K, Ty, PoolEntryID), Value(Value) {}
Jan Voung91a3e2c2015-01-09 13:01:42 -0800182 const PrimType Value;
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700183};
184
Jim Stichnothd2cb4362014-11-20 11:24:42 -0800185typedef ConstantPrimitive<int32_t, Operand::kConstInteger32> ConstantInteger32;
186typedef ConstantPrimitive<int64_t, Operand::kConstInteger64> ConstantInteger64;
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700187typedef ConstantPrimitive<float, Operand::kConstFloat> ConstantFloat;
188typedef ConstantPrimitive<double, Operand::kConstDouble> ConstantDouble;
189
Jim Stichnothdd842db2015-01-27 12:53:53 -0800190template <>
191inline void ConstantInteger32::dump(const Cfg *, Ostream &Str) const {
Jim Stichnoth20b71f52015-06-24 15:52:24 -0700192 if (!BuildDefs::dump())
Karl Schimpfb6c96af2014-11-17 10:58:39 -0800193 return;
Jim Stichnothcabfa302014-09-03 15:19:12 -0700194 if (getType() == IceType_i1)
195 Str << (getValue() ? "true" : "false");
196 else
Jan Voungbc004632014-09-16 15:09:10 -0700197 Str << static_cast<int32_t>(getValue());
198}
199
Qining Lu253dc8a2015-06-22 10:10:23 -0700200// Specialization of the template member function for ConstantInteger32
201template <>
202bool ConstantInteger32::shouldBeRandomizedOrPooled(const GlobalContext *Ctx);
203
Jim Stichnothdd842db2015-01-27 12:53:53 -0800204template <>
205inline void ConstantInteger64::dump(const Cfg *, Ostream &Str) const {
Jim Stichnoth20b71f52015-06-24 15:52:24 -0700206 if (!BuildDefs::dump())
Karl Schimpfb6c96af2014-11-17 10:58:39 -0800207 return;
Jan Voungbc004632014-09-16 15:09:10 -0700208 assert(getType() == IceType_i64);
209 Str << static_cast<int64_t>(getValue());
Jim Stichnothcabfa302014-09-03 15:19:12 -0700210}
211
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700212// RelocatableTuple bundles the parameters that are used to
213// construct an ConstantRelocatable. It is done this way so that
214// ConstantRelocatable can fit into the global constant pool
215// template mechanism.
216class RelocatableTuple {
Jim Stichnothc6ead202015-02-24 09:30:30 -0800217 RelocatableTuple() = delete;
Jim Stichnoth0795ba02014-10-01 14:23:01 -0700218 RelocatableTuple &operator=(const RelocatableTuple &) = delete;
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700219
220public:
Jan Voungfe14fb82014-10-13 15:56:32 -0700221 RelocatableTuple(const RelocOffsetT Offset, const IceString &Name,
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700222 bool SuppressMangling)
223 : Offset(Offset), Name(Name), SuppressMangling(SuppressMangling) {}
Jim Stichnothd2cb4362014-11-20 11:24:42 -0800224 RelocatableTuple(const RelocatableTuple &) = default;
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700225
Jan Voungfe14fb82014-10-13 15:56:32 -0700226 const RelocOffsetT Offset;
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700227 const IceString Name;
228 bool SuppressMangling;
229};
230
Jim Stichnothd2cb4362014-11-20 11:24:42 -0800231bool operator==(const RelocatableTuple &A, const RelocatableTuple &B);
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700232
233// ConstantRelocatable represents a symbolic constant combined with
234// a fixed offset.
235class ConstantRelocatable : public Constant {
Jim Stichnothc6ead202015-02-24 09:30:30 -0800236 ConstantRelocatable() = delete;
Jim Stichnoth7b451a92014-10-15 14:39:23 -0700237 ConstantRelocatable(const ConstantRelocatable &) = delete;
238 ConstantRelocatable &operator=(const ConstantRelocatable &) = delete;
239
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700240public:
241 static ConstantRelocatable *create(GlobalContext *Ctx, Type Ty,
Jim Stichnothf61d5b22014-05-23 13:31:24 -0700242 const RelocatableTuple &Tuple,
243 uint32_t PoolEntryID) {
Karl Schimpf6fcbddd2014-11-06 09:49:24 -0800244 assert(!Ctx->isIRGenerationDisabled() &&
245 "Attempt to build relocatable constant when IR generation disabled");
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700246 return new (Ctx->allocate<ConstantRelocatable>()) ConstantRelocatable(
Jim Stichnothf61d5b22014-05-23 13:31:24 -0700247 Ty, Tuple.Offset, Tuple.Name, Tuple.SuppressMangling, PoolEntryID);
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700248 }
Jan Voungfe14fb82014-10-13 15:56:32 -0700249
250 RelocOffsetT getOffset() const { return Offset; }
Jan Voungc9ec5792015-02-05 17:31:28 -0800251 const IceString &getName() const { return Name; }
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700252 void setSuppressMangling(bool Value) { SuppressMangling = Value; }
253 bool getSuppressMangling() const { return SuppressMangling; }
Jim Stichnothd97c7df2014-06-04 11:57:08 -0700254 using Constant::emit;
Jan Voung76bb0be2015-05-14 09:26:19 -0700255 void emit(TargetLowering *Target) const final;
256 void emitWithoutPrefix(TargetLowering *Target) const;
Jim Stichnothd97c7df2014-06-04 11:57:08 -0700257 using Constant::dump;
Jim Stichnothb56c8f42014-09-26 09:28:46 -0700258 void dump(const Cfg *Func, Ostream &Str) const override;
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700259
260 static bool classof(const Operand *Operand) {
261 OperandKind Kind = Operand->getKind();
262 return Kind == kConstRelocatable;
263 }
264
265private:
Jan Voungfe14fb82014-10-13 15:56:32 -0700266 ConstantRelocatable(Type Ty, RelocOffsetT Offset, const IceString &Name,
Jim Stichnothf61d5b22014-05-23 13:31:24 -0700267 bool SuppressMangling, uint32_t PoolEntryID)
268 : Constant(kConstRelocatable, Ty, PoolEntryID), Offset(Offset),
269 Name(Name), SuppressMangling(SuppressMangling) {}
Jan Voungfe14fb82014-10-13 15:56:32 -0700270 const RelocOffsetT Offset; // fixed offset to add
Jim Stichnothdd842db2015-01-27 12:53:53 -0800271 const IceString Name; // optional for debug/dump
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700272 bool SuppressMangling;
273};
274
Matt Walad8f4a7d2014-06-18 09:55:03 -0700275// ConstantUndef represents an unspecified bit pattern. Although it is
276// legal to lower ConstantUndef to any value, backends should try to
277// make code generation deterministic by lowering ConstantUndefs to 0.
278class ConstantUndef : public Constant {
Jim Stichnothc6ead202015-02-24 09:30:30 -0800279 ConstantUndef() = delete;
Jim Stichnoth7b451a92014-10-15 14:39:23 -0700280 ConstantUndef(const ConstantUndef &) = delete;
281 ConstantUndef &operator=(const ConstantUndef &) = delete;
282
Matt Walad8f4a7d2014-06-18 09:55:03 -0700283public:
284 static ConstantUndef *create(GlobalContext *Ctx, Type Ty,
285 uint32_t PoolEntryID) {
Karl Schimpf6fcbddd2014-11-06 09:49:24 -0800286 assert(!Ctx->isIRGenerationDisabled() &&
287 "Attempt to build undefined constant when IR generation disabled");
Matt Walad8f4a7d2014-06-18 09:55:03 -0700288 return new (Ctx->allocate<ConstantUndef>()) ConstantUndef(Ty, PoolEntryID);
289 }
290
291 using Constant::emit;
Jan Voung76bb0be2015-05-14 09:26:19 -0700292 void emit(TargetLowering *Target) const final;
Jim Stichnoth2e8bfbb2014-09-16 10:16:00 -0700293 using Constant::dump;
Karl Schimpfb6c96af2014-11-17 10:58:39 -0800294 void dump(const Cfg *, Ostream &Str) const override {
Jim Stichnoth20b71f52015-06-24 15:52:24 -0700295 if (BuildDefs::dump())
Karl Schimpfb6c96af2014-11-17 10:58:39 -0800296 Str << "undef";
297 }
Matt Walad8f4a7d2014-06-18 09:55:03 -0700298
299 static bool classof(const Operand *Operand) {
300 return Operand->getKind() == kConstUndef;
301 }
302
303private:
304 ConstantUndef(Type Ty, uint32_t PoolEntryID)
305 : Constant(kConstUndef, Ty, PoolEntryID) {}
Matt Walad8f4a7d2014-06-18 09:55:03 -0700306};
307
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -0700308// RegWeight is a wrapper for a uint32_t weight value, with a
309// special value that represents infinite weight, and an addWeight()
310// method that ensures that W+infinity=infinity.
311class RegWeight {
312public:
Jim Stichnotheafb56c2015-06-22 10:35:22 -0700313 RegWeight() = default;
Jim Stichnothc6ead202015-02-24 09:30:30 -0800314 explicit RegWeight(uint32_t Weight) : Weight(Weight) {}
Jim Stichnoth7e571362015-01-09 11:43:26 -0800315 RegWeight(const RegWeight &) = default;
316 RegWeight &operator=(const RegWeight &) = default;
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -0700317 const static uint32_t Inf = ~0; // Force regalloc to give a register
318 const static uint32_t Zero = 0; // Force regalloc NOT to give a register
319 void addWeight(uint32_t Delta) {
320 if (Delta == Inf)
321 Weight = Inf;
322 else if (Weight != Inf)
323 Weight += Delta;
324 }
325 void addWeight(const RegWeight &Other) { addWeight(Other.Weight); }
326 void setWeight(uint32_t Val) { Weight = Val; }
327 uint32_t getWeight() const { return Weight; }
328 bool isInf() const { return Weight == Inf; }
Jim Stichnothc6ead202015-02-24 09:30:30 -0800329 bool isZero() const { return Weight == Zero; }
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -0700330
331private:
Jim Stichnotheafb56c2015-06-22 10:35:22 -0700332 uint32_t Weight = 0;
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -0700333};
334Ostream &operator<<(Ostream &Str, const RegWeight &W);
335bool operator<(const RegWeight &A, const RegWeight &B);
336bool operator<=(const RegWeight &A, const RegWeight &B);
337bool operator==(const RegWeight &A, const RegWeight &B);
338
Jim Stichnothd97c7df2014-06-04 11:57:08 -0700339// LiveRange is a set of instruction number intervals representing
340// a variable's live range. Generally there is one interval per basic
341// block where the variable is live, but adjacent intervals get
342// coalesced into a single interval. LiveRange also includes a
343// weight, in case e.g. we want a live range to have higher weight
344// inside a loop.
345class LiveRange {
346public:
Jim Stichnotheafb56c2015-06-22 10:35:22 -0700347 LiveRange() = default;
Jim Stichnoth2a7fcbb2014-12-04 11:45:03 -0800348 // Special constructor for building a kill set. The advantage is
349 // that we can reserve the right amount of space in advance.
Jim Stichnotheafb56c2015-06-22 10:35:22 -0700350 explicit LiveRange(const std::vector<InstNumberT> &Kills) {
Jim Stichnoth2a7fcbb2014-12-04 11:45:03 -0800351 Range.reserve(Kills.size());
352 for (InstNumberT I : Kills)
353 addSegment(I, I);
354 }
Jim Stichnoth87ff3a12014-11-14 10:27:29 -0800355 LiveRange(const LiveRange &) = default;
356 LiveRange &operator=(const LiveRange &) = default;
Jim Stichnothd97c7df2014-06-04 11:57:08 -0700357
358 void reset() {
359 Range.clear();
360 Weight.setWeight(0);
Jim Stichnoth037fa1d2014-10-07 11:09:33 -0700361 untrim();
Jim Stichnothd97c7df2014-06-04 11:57:08 -0700362 }
363 void addSegment(InstNumberT Start, InstNumberT End);
364
365 bool endsBefore(const LiveRange &Other) const;
Jim Stichnoth037fa1d2014-10-07 11:09:33 -0700366 bool overlaps(const LiveRange &Other, bool UseTrimmed = false) const;
367 bool overlapsInst(InstNumberT OtherBegin, bool UseTrimmed = false) const;
Jim Stichnoth47752552014-10-13 17:15:08 -0700368 bool containsValue(InstNumberT Value, bool IsDest) const;
Jim Stichnothd97c7df2014-06-04 11:57:08 -0700369 bool isEmpty() const { return Range.empty(); }
370 InstNumberT getStart() const {
371 return Range.empty() ? -1 : Range.begin()->first;
372 }
373
Jim Stichnoth037fa1d2014-10-07 11:09:33 -0700374 void untrim() { TrimmedBegin = Range.begin(); }
375 void trim(InstNumberT Lower);
376
Jim Stichnothd97c7df2014-06-04 11:57:08 -0700377 RegWeight getWeight() const { return Weight; }
378 void setWeight(const RegWeight &NewWeight) { Weight = NewWeight; }
379 void addWeight(uint32_t Delta) { Weight.addWeight(Delta); }
380 void dump(Ostream &Str) const;
381
Jim Stichnothd97c7df2014-06-04 11:57:08 -0700382private:
383 typedef std::pair<InstNumberT, InstNumberT> RangeElementType;
Jim Stichnoth31c95592014-12-19 12:51:35 -0800384 // RangeType is arena-allocated from the Cfg's allocator.
385 typedef std::vector<RangeElementType, CfgLocalAllocator<RangeElementType>>
Jim Stichnothdd842db2015-01-27 12:53:53 -0800386 RangeType;
Jim Stichnothd97c7df2014-06-04 11:57:08 -0700387 RangeType Range;
Jim Stichnotheafb56c2015-06-22 10:35:22 -0700388 RegWeight Weight = RegWeight(0);
Jim Stichnoth037fa1d2014-10-07 11:09:33 -0700389 // TrimmedBegin is an optimization for the overlaps() computation.
390 // Since the linear-scan algorithm always calls it as overlaps(Cur)
391 // and Cur advances monotonically according to live range start, we
392 // can optimize overlaps() by ignoring all segments that end before
393 // the start of Cur's range. The linear-scan code enables this by
394 // calling trim() on the ranges of interest as Cur advances. Note
395 // that linear-scan also has to initialize TrimmedBegin at the
396 // beginning by calling untrim().
397 RangeType::const_iterator TrimmedBegin;
Jim Stichnothd97c7df2014-06-04 11:57:08 -0700398};
399
400Ostream &operator<<(Ostream &Str, const LiveRange &L);
401
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700402// Variable represents an operand that is register-allocated or
403// stack-allocated. If it is register-allocated, it will ultimately
404// have a non-negative RegNum field.
405class Variable : public Operand {
Jim Stichnothc6ead202015-02-24 09:30:30 -0800406 Variable() = delete;
Jim Stichnoth0795ba02014-10-01 14:23:01 -0700407 Variable(const Variable &) = delete;
408 Variable &operator=(const Variable &) = delete;
Jim Stichnoth800dab22014-09-20 12:25:02 -0700409
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700410public:
Jim Stichnoth9a04c072014-12-11 15:51:42 -0800411 static Variable *create(Cfg *Func, Type Ty, SizeT Index) {
412 return new (Func->allocate<Variable>()) Variable(kVariable, Ty, Index);
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700413 }
414
415 SizeT getIndex() const { return Number; }
Jim Stichnoth9a04c072014-12-11 15:51:42 -0800416 IceString getName(const Cfg *Func) const;
417 void setName(Cfg *Func, const IceString &NewName) {
Karl Schimpfc132b762014-09-11 09:43:47 -0700418 // Make sure that the name can only be set once.
Jim Stichnoth9a04c072014-12-11 15:51:42 -0800419 assert(NameIndex == Cfg::IdentifierIndexInvalid);
420 if (!NewName.empty())
421 NameIndex = Func->addIdentifierName(NewName);
Karl Schimpfc132b762014-09-11 09:43:47 -0700422 }
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700423
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700424 bool getIsArg() const { return IsArgument; }
Jim Stichnoth144cdce2014-09-22 16:02:59 -0700425 void setIsArg(bool Val = true) { IsArgument = Val; }
426 bool getIsImplicitArg() const { return IsImplicitArgument; }
427 void setIsImplicitArg(bool Val = true) { IsImplicitArgument = Val; }
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700428
Jim Stichnoth47752552014-10-13 17:15:08 -0700429 void setIgnoreLiveness() { IgnoreLiveness = true; }
430 bool getIgnoreLiveness() const { return IgnoreLiveness; }
431
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -0700432 int32_t getStackOffset() const { return StackOffset; }
433 void setStackOffset(int32_t Offset) { StackOffset = Offset; }
434
435 static const int32_t NoRegister = -1;
436 bool hasReg() const { return getRegNum() != NoRegister; }
437 int32_t getRegNum() const { return RegNum; }
438 void setRegNum(int32_t NewRegNum) {
439 // Regnum shouldn't be set more than once.
440 assert(!hasReg() || RegNum == NewRegNum);
441 RegNum = NewRegNum;
442 }
Jim Stichnothd97c7df2014-06-04 11:57:08 -0700443 bool hasRegTmp() const { return getRegNumTmp() != NoRegister; }
444 int32_t getRegNumTmp() const { return RegNumTmp; }
445 void setRegNumTmp(int32_t NewRegNum) { RegNumTmp = NewRegNum; }
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -0700446
447 RegWeight getWeight() const { return Weight; }
Jim Stichnothc6ead202015-02-24 09:30:30 -0800448 void setWeight(uint32_t NewWeight) { Weight = RegWeight(NewWeight); }
449 void setWeightInfinite() { setWeight(RegWeight::Inf); }
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -0700450
Jim Stichnoth5ce0abb2014-10-15 10:16:54 -0700451 LiveRange &getLiveRange() { return Live; }
Jim Stichnothd97c7df2014-06-04 11:57:08 -0700452 const LiveRange &getLiveRange() const { return Live; }
453 void setLiveRange(const LiveRange &Range) { Live = Range; }
454 void resetLiveRange() { Live.reset(); }
455 void addLiveRange(InstNumberT Start, InstNumberT End, uint32_t WeightDelta) {
456 assert(WeightDelta != RegWeight::Inf);
457 Live.addSegment(Start, End);
458 if (Weight.isInf())
Jim Stichnothc6ead202015-02-24 09:30:30 -0800459 Live.setWeight(RegWeight(RegWeight::Inf));
Jim Stichnothd97c7df2014-06-04 11:57:08 -0700460 else
461 Live.addWeight(WeightDelta * Weight.getWeight());
462 }
Jim Stichnothc6ead202015-02-24 09:30:30 -0800463 void setLiveRangeInfiniteWeight() {
464 Live.setWeight(RegWeight(RegWeight::Inf));
465 }
Jim Stichnoth037fa1d2014-10-07 11:09:33 -0700466 void trimLiveRange(InstNumberT Start) { Live.trim(Start); }
467 void untrimLiveRange() { Live.untrim(); }
Jim Stichnoth5ce0abb2014-10-15 10:16:54 -0700468 bool rangeEndsBefore(const Variable *Other) const {
469 return Live.endsBefore(Other->Live);
470 }
471 bool rangeOverlaps(const Variable *Other) const {
472 const bool UseTrimmed = true;
473 return Live.overlaps(Other->Live, UseTrimmed);
474 }
475 bool rangeOverlapsStart(const Variable *Other) const {
476 const bool UseTrimmed = true;
477 return Live.overlapsInst(Other->Live.getStart(), UseTrimmed);
478 }
Jim Stichnothd97c7df2014-06-04 11:57:08 -0700479
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -0700480 Variable *getLo() const { return LoVar; }
481 Variable *getHi() const { return HiVar; }
482 void setLoHi(Variable *Lo, Variable *Hi) {
Jim Stichnothae953202014-12-20 06:17:49 -0800483 assert(LoVar == nullptr);
484 assert(HiVar == nullptr);
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -0700485 LoVar = Lo;
486 HiVar = Hi;
487 }
488 // Creates a temporary copy of the variable with a different type.
489 // Used primarily for syntactic correctness of textual assembly
490 // emission. Note that only basic information is copied, in
Jim Stichnoth31c95592014-12-19 12:51:35 -0800491 // particular not IsArgument, IsImplicitArgument, IgnoreLiveness,
492 // RegNumTmp, Weight, Live, LoVar, HiVar, VarsReal.
493 Variable *asType(Type Ty);
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -0700494
Jim Stichnothb56c8f42014-09-26 09:28:46 -0700495 void emit(const Cfg *Func) const override;
Jim Stichnoth2e8bfbb2014-09-16 10:16:00 -0700496 using Operand::dump;
Jim Stichnothb56c8f42014-09-26 09:28:46 -0700497 void dump(const Cfg *Func, Ostream &Str) const override;
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700498
499 static bool classof(const Operand *Operand) {
Jim Stichnoth800dab22014-09-20 12:25:02 -0700500 OperandKind Kind = Operand->getKind();
501 return Kind >= kVariable && Kind <= kVariable_Num;
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700502 }
503
Jim Stichnoth800dab22014-09-20 12:25:02 -0700504protected:
Jim Stichnoth9a04c072014-12-11 15:51:42 -0800505 Variable(OperandKind K, Type Ty, SizeT Index)
Jim Stichnotheafb56c2015-06-22 10:35:22 -0700506 : Operand(K, Ty), Number(Index) {
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700507 Vars = VarsReal;
508 Vars[0] = this;
509 NumVars = 1;
510 }
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700511 // Number is unique across all variables, and is used as a
512 // (bit)vector index for liveness analysis.
513 const SizeT Number;
Jim Stichnotheafb56c2015-06-22 10:35:22 -0700514 Cfg::IdentifierIndexType NameIndex = Cfg::IdentifierIndexInvalid;
515 bool IsArgument = false;
516 bool IsImplicitArgument = false;
Jim Stichnoth47752552014-10-13 17:15:08 -0700517 // IgnoreLiveness means that the variable should be ignored when
518 // constructing and validating live ranges. This is usually
519 // reserved for the stack pointer.
Jim Stichnotheafb56c2015-06-22 10:35:22 -0700520 bool IgnoreLiveness = false;
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -0700521 // StackOffset is the canonical location on stack (only if
Jim Stichnothad403532014-09-25 12:44:17 -0700522 // RegNum==NoRegister || IsArgument).
Jim Stichnotheafb56c2015-06-22 10:35:22 -0700523 int32_t StackOffset = 0;
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -0700524 // RegNum is the allocated register, or NoRegister if it isn't
525 // register-allocated.
Jim Stichnotheafb56c2015-06-22 10:35:22 -0700526 int32_t RegNum = NoRegister;
Jim Stichnothd97c7df2014-06-04 11:57:08 -0700527 // RegNumTmp is the tentative assignment during register allocation.
Jim Stichnotheafb56c2015-06-22 10:35:22 -0700528 int32_t RegNumTmp = NoRegister;
529 RegWeight Weight = RegWeight(1); // Register allocation priority
Jim Stichnothd97c7df2014-06-04 11:57:08 -0700530 LiveRange Live;
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -0700531 // LoVar and HiVar are needed for lowering from 64 to 32 bits. When
532 // lowering from I64 to I32 on a 32-bit architecture, we split the
533 // variable into two machine-size pieces. LoVar is the low-order
534 // machine-size portion, and HiVar is the remaining high-order
535 // portion. TODO: It's wasteful to penalize all variables on all
536 // targets this way; use a sparser representation. It's also
537 // wasteful for a 64-bit target.
Jim Stichnotheafb56c2015-06-22 10:35:22 -0700538 Variable *LoVar = nullptr;
539 Variable *HiVar = nullptr;
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700540 // VarsReal (and Operand::Vars) are set up such that Vars[0] ==
541 // this.
542 Variable *VarsReal[1];
543};
544
Jim Stichnoth877b04e2014-10-15 15:13:06 -0700545enum MetadataKind {
546 VMK_Uses, // Track only uses, not defs
547 VMK_SingleDefs, // Track uses+defs, but only record single def
548 VMK_All // Track uses+defs, including full def list
549};
Jim Stichnothe4a8f402015-01-20 12:52:51 -0800550typedef std::vector<const Inst *, CfgLocalAllocator<const Inst *>> InstDefList;
Jim Stichnothad403532014-09-25 12:44:17 -0700551
552// VariableTracking tracks the metadata for a single variable. It is
553// only meant to be used internally by VariablesMetadata.
Jim Stichnoth144cdce2014-09-22 16:02:59 -0700554class VariableTracking {
Jim Stichnoth7b451a92014-10-15 14:39:23 -0700555 VariableTracking &operator=(const VariableTracking &) = delete;
556
Jim Stichnoth144cdce2014-09-22 16:02:59 -0700557public:
558 enum MultiDefState {
559 // TODO(stichnot): Consider using just a simple counter.
560 MDS_Unknown,
561 MDS_SingleDef,
Jim Stichnothad403532014-09-25 12:44:17 -0700562 MDS_MultiDefSingleBlock,
563 MDS_MultiDefMultiBlock
Jim Stichnoth144cdce2014-09-22 16:02:59 -0700564 };
Jim Stichnothdd842db2015-01-27 12:53:53 -0800565 enum MultiBlockState { MBS_Unknown, MBS_SingleBlock, MBS_MultiBlock };
Jim Stichnotheafb56c2015-06-22 10:35:22 -0700566 VariableTracking() = default;
Jim Stichnoth7e571362015-01-09 11:43:26 -0800567 VariableTracking(const VariableTracking &) = default;
Jim Stichnoth144cdce2014-09-22 16:02:59 -0700568 MultiDefState getMultiDef() const { return MultiDef; }
569 MultiBlockState getMultiBlock() const { return MultiBlock; }
Jim Stichnothad403532014-09-25 12:44:17 -0700570 const Inst *getFirstDefinition() const;
571 const Inst *getSingleDefinition() const;
Jim Stichnoth877b04e2014-10-15 15:13:06 -0700572 const InstDefList &getLatterDefinitions() const { return Definitions; }
Jim Stichnoth144cdce2014-09-22 16:02:59 -0700573 const CfgNode *getNode() const { return SingleUseNode; }
Jim Stichnoth877b04e2014-10-15 15:13:06 -0700574 void markUse(MetadataKind TrackingKind, const Inst *Instr,
575 const CfgNode *Node, bool IsFromDef, bool IsImplicit);
576 void markDef(MetadataKind TrackingKind, const Inst *Instr,
577 const CfgNode *Node);
Jim Stichnoth144cdce2014-09-22 16:02:59 -0700578
579private:
Jim Stichnotheafb56c2015-06-22 10:35:22 -0700580 MultiDefState MultiDef = MDS_Unknown;
581 MultiBlockState MultiBlock = MBS_Unknown;
582 const CfgNode *SingleUseNode = nullptr;
583 const CfgNode *SingleDefNode = nullptr;
Jim Stichnoth037fa1d2014-10-07 11:09:33 -0700584 // All definitions of the variable are collected here, in increasing
585 // order of instruction number.
Jim Stichnotheafb56c2015-06-22 10:35:22 -0700586 InstDefList Definitions; // Only used if Kind==VMK_All
587 const Inst *FirstOrSingleDefinition =
588 nullptr; // Is a copy of Definitions[0] if Kind==VMK_All
Jim Stichnoth144cdce2014-09-22 16:02:59 -0700589};
590
591// VariablesMetadata analyzes and summarizes the metadata for the
592// complete set of Variables.
593class VariablesMetadata {
Jim Stichnothc6ead202015-02-24 09:30:30 -0800594 VariablesMetadata() = delete;
Jim Stichnoth7b451a92014-10-15 14:39:23 -0700595 VariablesMetadata(const VariablesMetadata &) = delete;
596 VariablesMetadata &operator=(const VariablesMetadata &) = delete;
597
Jim Stichnoth144cdce2014-09-22 16:02:59 -0700598public:
Jim Stichnothc6ead202015-02-24 09:30:30 -0800599 explicit VariablesMetadata(const Cfg *Func) : Func(Func) {}
Jim Stichnothad403532014-09-25 12:44:17 -0700600 // Initialize the state by traversing all instructions/variables in
601 // the CFG.
Jim Stichnoth877b04e2014-10-15 15:13:06 -0700602 void init(MetadataKind TrackingKind);
Jim Stichnoth336f6c42014-10-30 15:01:31 -0700603 // Add a single node. This is called by init(), and can be called
604 // incrementally from elsewhere, e.g. after edge-splitting.
605 void addNode(CfgNode *Node);
Jim Stichnothad403532014-09-25 12:44:17 -0700606 // Returns whether the given Variable is tracked in this object. It
607 // should only return false if changes were made to the CFG after
608 // running init(), in which case the state is stale and the results
609 // shouldn't be trusted (but it may be OK e.g. for dumping).
Jim Stichnoth144cdce2014-09-22 16:02:59 -0700610 bool isTracked(const Variable *Var) const {
611 return Var->getIndex() < Metadata.size();
612 }
Jim Stichnothad403532014-09-25 12:44:17 -0700613
614 // Returns whether the given Variable has multiple definitions.
Jim Stichnoth144cdce2014-09-22 16:02:59 -0700615 bool isMultiDef(const Variable *Var) const;
Jim Stichnothad403532014-09-25 12:44:17 -0700616 // Returns the first definition instruction of the given Variable.
617 // This is only valid for variables whose definitions are all within
618 // the same block, e.g. T after the lowered sequence "T=B; T+=C;
619 // A=T", for which getFirstDefinition(T) would return the "T=B"
620 // instruction. For variables with definitions span multiple
Jim Stichnothae953202014-12-20 06:17:49 -0800621 // blocks, nullptr is returned.
Jim Stichnothad403532014-09-25 12:44:17 -0700622 const Inst *getFirstDefinition(const Variable *Var) const;
623 // Returns the definition instruction of the given Variable, when
Jim Stichnothae953202014-12-20 06:17:49 -0800624 // the variable has exactly one definition. Otherwise, nullptr is
Jim Stichnothad403532014-09-25 12:44:17 -0700625 // returned.
626 const Inst *getSingleDefinition(const Variable *Var) const;
627 // Returns the list of all definition instructions of the given
628 // Variable.
Jim Stichnoth877b04e2014-10-15 15:13:06 -0700629 const InstDefList &getLatterDefinitions(const Variable *Var) const;
Jim Stichnothad403532014-09-25 12:44:17 -0700630
631 // Returns whether the given Variable is live across multiple
632 // blocks. Mainly, this is used to partition Variables into
633 // single-block versus multi-block sets for leveraging sparsity in
634 // liveness analysis, and for implementing simple stack slot
635 // coalescing. As a special case, function arguments are always
636 // considered multi-block because they are live coming into the
637 // entry block.
Jim Stichnoth144cdce2014-09-22 16:02:59 -0700638 bool isMultiBlock(const Variable *Var) const;
Jim Stichnothad403532014-09-25 12:44:17 -0700639 // Returns the node that the given Variable is used in, assuming
Jim Stichnothae953202014-12-20 06:17:49 -0800640 // isMultiBlock() returns false. Otherwise, nullptr is returned.
Jim Stichnoth144cdce2014-09-22 16:02:59 -0700641 const CfgNode *getLocalUseNode(const Variable *Var) const;
642
643private:
644 const Cfg *Func;
Jim Stichnoth877b04e2014-10-15 15:13:06 -0700645 MetadataKind Kind;
Jim Stichnoth144cdce2014-09-22 16:02:59 -0700646 std::vector<VariableTracking> Metadata;
Jim Stichnothad403532014-09-25 12:44:17 -0700647 const static InstDefList NoDefinitions;
Jim Stichnoth144cdce2014-09-22 16:02:59 -0700648};
649
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700650} // end of namespace Ice
651
652#endif // SUBZERO_SRC_ICEOPERAND_H