blob: 5501f4709a9e393be3901cdf7a647cd1caf87a51 [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//===----------------------------------------------------------------------===//
Andrew Scull9612d322015-07-06 14:53:25 -07009///
10/// \file
Jim Stichnoth92a6e5b2015-12-02 16:52:44 -080011/// \brief Declares the Operand class and its target-independent subclasses.
12///
Andrew Scull6ef79492015-09-09 15:50:42 -070013/// The main classes are Variable, which represents an LLVM variable that is
14/// either register- or stack-allocated, and the Constant hierarchy, which
15/// represents integer, floating-point, and/or symbolic constants.
Andrew Scull9612d322015-07-06 14:53:25 -070016///
Jim Stichnothf7c9a142014-04-29 10:52:43 -070017//===----------------------------------------------------------------------===//
18
19#ifndef SUBZERO_SRC_ICEOPERAND_H
20#define SUBZERO_SRC_ICEOPERAND_H
21
22#include "IceDefs.h"
John Portoe82b5602016-02-24 15:58:55 -080023#include "IceCfg.h"
Jan Voungfe14fb82014-10-13 15:56:32 -070024#include "IceGlobalContext.h"
Jim Stichnoth467ffe52016-03-29 15:01:06 -070025#include "IceStringPool.h"
Jim Stichnothf7c9a142014-04-29 10:52:43 -070026#include "IceTypes.h"
27
Nicolas Capens4d708022016-09-07 15:03:32 -040028#include "llvm/Support/ErrorHandling.h"
Jim Stichnothb36757e2015-10-05 13:55:11 -070029#include "llvm/Support/Format.h"
30
John Porto27fddcc2016-02-02 15:06:09 -080031#include <limits>
Jim Stichnoth9f9aa2c2016-03-07 08:25:24 -080032#include <type_traits>
John Porto27fddcc2016-02-02 15:06:09 -080033
Jim Stichnothf7c9a142014-04-29 10:52:43 -070034namespace Ice {
35
36class Operand {
Jim Stichnothc6ead202015-02-24 09:30:30 -080037 Operand() = delete;
Jim Stichnoth7b451a92014-10-15 14:39:23 -070038 Operand(const Operand &) = delete;
39 Operand &operator=(const Operand &) = delete;
40
Jim Stichnothf7c9a142014-04-29 10:52:43 -070041public:
Andrew Scull6ef79492015-09-09 15:50:42 -070042 static constexpr size_t MaxTargetKinds = 10;
Jim Stichnothf7c9a142014-04-29 10:52:43 -070043 enum OperandKind {
44 kConst_Base,
Jan Voungbc004632014-09-16 15:09:10 -070045 kConstInteger32,
46 kConstInteger64,
Jim Stichnothf7c9a142014-04-29 10:52:43 -070047 kConstFloat,
48 kConstDouble,
49 kConstRelocatable,
Matt Walad8f4a7d2014-06-18 09:55:03 -070050 kConstUndef,
Jim Stichnoth800dab22014-09-20 12:25:02 -070051 kConst_Target, // leave space for target-specific constant kinds
Andrew Scull6ef79492015-09-09 15:50:42 -070052 kConst_Max = kConst_Target + MaxTargetKinds,
Jim Stichnothf7c9a142014-04-29 10:52:43 -070053 kVariable,
Andrew Scull6d47bcd2015-09-17 17:10:05 -070054 kVariable64On32,
Jaydeep Patil958ddb72016-10-03 07:52:48 -070055 kVariableVecOn32,
Eric Holk80ee5b32016-05-06 14:28:04 -070056 kVariableBoolean,
Jim Stichnoth800dab22014-09-20 12:25:02 -070057 kVariable_Target, // leave space for target-specific variable kinds
Andrew Scull6ef79492015-09-09 15:50:42 -070058 kVariable_Max = kVariable_Target + MaxTargetKinds,
Andrew Scull57e12682015-09-16 11:30:19 -070059 // Target-specific operand classes use kTarget as the starting point for
60 // their Kind enum space. Note that the value-spaces are shared across
61 // targets. To avoid confusion over the definition of shared values, an
62 // object specific to one target should never be passed to a different
63 // target.
Andrew Scull6ef79492015-09-09 15:50:42 -070064 kTarget,
65 kTarget_Max = std::numeric_limits<uint8_t>::max(),
Jim Stichnothf7c9a142014-04-29 10:52:43 -070066 };
Andrew Scull6ef79492015-09-09 15:50:42 -070067 static_assert(kTarget <= kTarget_Max, "Must not be above max.");
Jim Stichnothf7c9a142014-04-29 10:52:43 -070068 OperandKind getKind() const { return Kind; }
69 Type getType() const { return Ty; }
70
Andrew Scull6ef79492015-09-09 15:50:42 -070071 /// Every Operand keeps an array of the Variables referenced in the operand.
72 /// This is so that the liveness operations can get quick access to the
73 /// variables of interest, without having to dig so far into the operand.
Jim Stichnothf7c9a142014-04-29 10:52:43 -070074 SizeT getNumVars() const { return NumVars; }
75 Variable *getVar(SizeT I) const {
76 assert(I < getNumVars());
77 return Vars[I];
78 }
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -070079 virtual void emit(const Cfg *Func) const = 0;
Andrew Scull9612d322015-07-06 14:53:25 -070080
81 /// \name Dumping functions.
82 /// @{
83
Andrew Scull57e12682015-09-16 11:30:19 -070084 /// The dump(Func,Str) implementation must be sure to handle the situation
85 /// where Func==nullptr.
Jim Stichnoth2e8bfbb2014-09-16 10:16:00 -070086 virtual void dump(const Cfg *Func, Ostream &Str) const = 0;
87 void dump(const Cfg *Func) const {
Jim Stichnoth20b71f52015-06-24 15:52:24 -070088 if (!BuildDefs::dump())
Karl Schimpfb6c96af2014-11-17 10:58:39 -080089 return;
Jim Stichnoth2e8bfbb2014-09-16 10:16:00 -070090 assert(Func);
91 dump(Func, Func->getContext()->getStrDump());
92 }
Karl Schimpfb6c96af2014-11-17 10:58:39 -080093 void dump(Ostream &Str) const {
Jim Stichnoth20b71f52015-06-24 15:52:24 -070094 if (BuildDefs::dump())
Jim Stichnothae953202014-12-20 06:17:49 -080095 dump(nullptr, Str);
Karl Schimpfb6c96af2014-11-17 10:58:39 -080096 }
Andrew Scull9612d322015-07-06 14:53:25 -070097 /// @}
Jim Stichnothf7c9a142014-04-29 10:52:43 -070098
Sean Kleinfc707ff2016-02-29 16:44:07 -080099 virtual ~Operand() = default;
Andrew Scull00741a02015-09-16 19:04:09 -0700100
Eric Holk80ee5b32016-05-06 14:28:04 -0700101 virtual Variable *asBoolean() { return nullptr; }
102
Manasij Mukherjee032c3152016-05-24 14:25:04 -0700103 virtual SizeT hashValue() const {
104 llvm::report_fatal_error("Tried to hash unsupported operand type : " +
105 std::to_string(Kind));
106 return 0;
107 }
108
Alexis Hetu932640b2018-06-20 15:35:53 -0400109 inline void* getExternalData() const { return externalData; }
110 inline void setExternalData(void* data) { externalData = data; }
111
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700112protected:
Andrew Scull6ef79492015-09-09 15:50:42 -0700113 Operand(OperandKind Kind, Type Ty) : Ty(Ty), Kind(Kind) {
114 // It is undefined behavior to have a larger value in the enum
115 assert(Kind <= kTarget_Max);
116 }
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700117
118 const Type Ty;
119 const OperandKind Kind;
Andrew Scull9612d322015-07-06 14:53:25 -0700120 /// Vars and NumVars are initialized by the derived class.
Jim Stichnotheafb56c2015-06-22 10:35:22 -0700121 SizeT NumVars = 0;
122 Variable **Vars = nullptr;
Alexis Hetu932640b2018-06-20 15:35:53 -0400123
124 /// External data can be set by an optimizer to compute and retain any
125 /// information related to the current operand. All the memory used to
126 /// store this information must be managed by the optimizer.
127 void* externalData = nullptr;
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700128};
129
Jim Stichnothdd842db2015-01-27 12:53:53 -0800130template <class StreamType>
Karl Schimpf97501832014-09-16 13:35:32 -0700131inline StreamType &operator<<(StreamType &Str, const Operand &Op) {
132 Op.dump(Str);
133 return Str;
134}
135
Andrew Scull57e12682015-09-16 11:30:19 -0700136/// Constant is the abstract base class for constants. All constants are
137/// allocated from a global arena and are pooled.
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700138class Constant : public Operand {
Jim Stichnothc6ead202015-02-24 09:30:30 -0800139 Constant() = delete;
Jim Stichnoth7b451a92014-10-15 14:39:23 -0700140 Constant(const Constant &) = delete;
141 Constant &operator=(const Constant &) = delete;
142
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700143public:
Jim Stichnoth9f9aa2c2016-03-07 08:25:24 -0800144 // Declare the lookup counter to take minimal space in a non-DUMP build.
145 using CounterType =
146 std::conditional<BuildDefs::dump(), uint64_t, uint8_t>::type;
Jan Voung76bb0be2015-05-14 09:26:19 -0700147 void emit(const Cfg *Func) const override { emit(Func->getTarget()); }
148 virtual void emit(TargetLowering *Target) const = 0;
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700149
150 static bool classof(const Operand *Operand) {
151 OperandKind Kind = Operand->getKind();
Andrew Scull6ef79492015-09-09 15:50:42 -0700152 return Kind >= kConst_Base && Kind <= kConst_Max;
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700153 }
154
Jim Stichnoth467ffe52016-03-29 15:01:06 -0700155 const GlobalString getLabelName() const { return LabelName; }
156
Andrew Scull57e12682015-09-16 11:30:19 -0700157 /// Judge if this given immediate should be randomized or pooled By default
158 /// should return false, only constant integers should truly go through this
159 /// method.
Jim Stichnoth467ffe52016-03-29 15:01:06 -0700160 virtual bool shouldBeRandomizedOrPooled() const { return false; }
Qining Lu253dc8a2015-06-22 10:10:23 -0700161
Jim Stichnoth9f9aa2c2016-03-07 08:25:24 -0800162 bool getShouldBePooled() const { return ShouldBePooled; }
Qining Lu253dc8a2015-06-22 10:10:23 -0700163
Jim Stichnoth9f9aa2c2016-03-07 08:25:24 -0800164 // This should be thread-safe because the constant pool lock is acquired
165 // before the method is invoked.
166 void updateLookupCount() {
167 if (!BuildDefs::dump())
168 return;
169 ++LookupCount;
170 }
171 CounterType getLookupCount() const { return LookupCount; }
Manasij Mukherjee032c3152016-05-24 14:25:04 -0700172 SizeT hashValue() const override { return 0; }
Qining Lu253dc8a2015-06-22 10:10:23 -0700173
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700174protected:
Jim Stichnoth9f9aa2c2016-03-07 08:25:24 -0800175 Constant(OperandKind Kind, Type Ty) : Operand(Kind, Ty) {
Jim Stichnothae953202014-12-20 06:17:49 -0800176 Vars = nullptr;
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700177 NumVars = 0;
178 }
Jim Stichnoth467ffe52016-03-29 15:01:06 -0700179 /// Set the ShouldBePooled field to the proper value after the object is fully
180 /// initialized.
181 void initShouldBePooled();
182 GlobalString LabelName;
Andrew Scull9612d322015-07-06 14:53:25 -0700183 /// Whether we should pool this constant. Usually Float/Double and pooled
Jim Stichnoth467ffe52016-03-29 15:01:06 -0700184 /// Integers should be flagged true. Ideally this field would be const, but
185 /// it needs to be initialized only after the subclass is fully constructed.
Jim Stichnoth9f9aa2c2016-03-07 08:25:24 -0800186 bool ShouldBePooled = false;
187 /// Note: If ShouldBePooled is ever removed from the base class, we will want
188 /// to completely disable LookupCount in a non-DUMP build to save space.
189 CounterType LookupCount = 0;
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700190};
191
Andrew Scull9612d322015-07-06 14:53:25 -0700192/// ConstantPrimitive<> wraps a primitive type.
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700193template <typename T, Operand::OperandKind K>
194class ConstantPrimitive : public Constant {
Jim Stichnothc6ead202015-02-24 09:30:30 -0800195 ConstantPrimitive() = delete;
Jim Stichnoth7b451a92014-10-15 14:39:23 -0700196 ConstantPrimitive(const ConstantPrimitive &) = delete;
197 ConstantPrimitive &operator=(const ConstantPrimitive &) = delete;
198
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700199public:
Andrew Scull8072bae2015-09-14 16:01:26 -0700200 using PrimType = T;
Jan Voung91a3e2c2015-01-09 13:01:42 -0800201
Jim Stichnothb36757e2015-10-05 13:55:11 -0700202 static ConstantPrimitive *create(GlobalContext *Ctx, Type Ty,
203 PrimType Value) {
Jim Stichnoth467ffe52016-03-29 15:01:06 -0700204 auto *Const =
205 new (Ctx->allocate<ConstantPrimitive>()) ConstantPrimitive(Ty, Value);
206 Const->initShouldBePooled();
207 if (Const->getShouldBePooled())
208 Const->initName(Ctx);
209 return Const;
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700210 }
Jan Voung91a3e2c2015-01-09 13:01:42 -0800211 PrimType getValue() const { return Value; }
Jim Stichnoth467ffe52016-03-29 15:01:06 -0700212 using Constant::emit;
213 void emit(TargetLowering *Target) const final;
214 using Constant::dump;
215 void dump(const Cfg *, Ostream &Str) const override {
216 if (BuildDefs::dump())
217 Str << getValue();
218 }
219
220 static bool classof(const Operand *Operand) {
221 return Operand->getKind() == K;
222 }
223
Sagar Thakure160ed92016-05-30 07:54:47 -0700224 SizeT hashValue() const override { return std::hash<PrimType>()(Value); }
Manasij Mukherjee032c3152016-05-24 14:25:04 -0700225
Jim Stichnoth467ffe52016-03-29 15:01:06 -0700226 virtual bool shouldBeRandomizedOrPooled() const override { return false; }
227
228private:
229 ConstantPrimitive(Type Ty, PrimType Value) : Constant(K, Ty), Value(Value) {}
230
231 void initName(GlobalContext *Ctx) {
232 std::string Buffer;
233 llvm::raw_string_ostream Str(Buffer);
Jim Stichnothe922c232016-04-09 08:54:20 -0700234 constexpr bool IsCompact = !BuildDefs::dump();
235 if (IsCompact) {
236 switch (getType()) {
237 case IceType_f32:
238 Str << "$F";
239 break;
240 case IceType_f64:
241 Str << "$D";
242 break;
243 default:
244 // For constant pooling diversification
245 Str << ".L$" << getType() << "$";
246 break;
247 }
248 } else {
249 Str << ".L$" << getType() << "$";
250 }
Jim Stichnothb36757e2015-10-05 13:55:11 -0700251 // Print hex characters byte by byte, starting from the most significant
252 // byte. NOTE: This ordering assumes Subzero runs on a little-endian
253 // platform. That means the possibility of different label names depending
254 // on the endian-ness of the platform where Subzero runs.
255 for (unsigned i = 0; i < sizeof(Value); ++i) {
256 constexpr unsigned HexWidthChars = 2;
257 unsigned Offset = sizeof(Value) - 1 - i;
258 Str << llvm::format_hex_no_prefix(
259 *(Offset + (const unsigned char *)&Value), HexWidthChars);
260 }
261 // For a floating-point value in DecorateAsm mode, also append the value in
262 // human-readable sprintf form, changing '+' to 'p' and '-' to 'm' to
263 // maintain valid asm labels.
Jim Stichnothe922c232016-04-09 08:54:20 -0700264 if (BuildDefs::dump() && std::is_floating_point<PrimType>::value &&
Karl Schimpfd4699942016-04-02 09:55:31 -0700265 getFlags().getDecorateAsm()) {
Jim Stichnothb36757e2015-10-05 13:55:11 -0700266 char Buf[30];
267 snprintf(Buf, llvm::array_lengthof(Buf), "$%g", (double)Value);
268 for (unsigned i = 0; i < llvm::array_lengthof(Buf) && Buf[i]; ++i) {
269 if (Buf[i] == '-')
270 Buf[i] = 'm';
271 else if (Buf[i] == '+')
272 Buf[i] = 'p';
273 }
274 Str << Buf;
275 }
Jim Stichnoth467ffe52016-03-29 15:01:06 -0700276 LabelName = GlobalString::createWithString(Ctx, Str.str());
Karl Schimpfb6c96af2014-11-17 10:58:39 -0800277 }
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700278
Jan Voung91a3e2c2015-01-09 13:01:42 -0800279 const PrimType Value;
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700280};
281
Andrew Scull8072bae2015-09-14 16:01:26 -0700282using ConstantInteger32 = ConstantPrimitive<int32_t, Operand::kConstInteger32>;
283using ConstantInteger64 = ConstantPrimitive<int64_t, Operand::kConstInteger64>;
284using ConstantFloat = ConstantPrimitive<float, Operand::kConstFloat>;
285using ConstantDouble = ConstantPrimitive<double, Operand::kConstDouble>;
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700286
Jim Stichnothdd842db2015-01-27 12:53:53 -0800287template <>
288inline void ConstantInteger32::dump(const Cfg *, Ostream &Str) const {
Jim Stichnoth20b71f52015-06-24 15:52:24 -0700289 if (!BuildDefs::dump())
Karl Schimpfb6c96af2014-11-17 10:58:39 -0800290 return;
Jim Stichnothcabfa302014-09-03 15:19:12 -0700291 if (getType() == IceType_i1)
292 Str << (getValue() ? "true" : "false");
293 else
Jan Voungbc004632014-09-16 15:09:10 -0700294 Str << static_cast<int32_t>(getValue());
295}
296
Nicolas Capensef9d0042016-09-02 07:05:50 -0400297// =========== Immediate Randomization and Pooling routines ==============
298// Specialization of the template member function for ConstantInteger32
299// TODO(stichnot): try to move this specialization into a target-specific file.
300template <> inline bool ConstantInteger32::shouldBeRandomizedOrPooled() const {
301 uint32_t Threshold = getFlags().getRandomizeAndPoolImmediatesThreshold();
302 if (getFlags().getRandomizeAndPoolImmediatesOption() == RPI_None)
303 return false;
304 if (getType() != IceType_i32 && getType() != IceType_i16 &&
305 getType() != IceType_i8)
306 return false;
307 // The Following checks if the signed representation of Value is between
308 // -Threshold/2 and +Threshold/2
309 bool largerThanThreshold = Threshold / 2 + Value >= Threshold;
310 return largerThanThreshold;
311}
Qining Lu253dc8a2015-06-22 10:10:23 -0700312
Jim Stichnothdd842db2015-01-27 12:53:53 -0800313template <>
314inline void ConstantInteger64::dump(const Cfg *, Ostream &Str) const {
Jim Stichnoth20b71f52015-06-24 15:52:24 -0700315 if (!BuildDefs::dump())
Karl Schimpfb6c96af2014-11-17 10:58:39 -0800316 return;
Jan Voungbc004632014-09-16 15:09:10 -0700317 assert(getType() == IceType_i64);
318 Str << static_cast<int64_t>(getValue());
Jim Stichnothcabfa302014-09-03 15:19:12 -0700319}
320
John Porto27fddcc2016-02-02 15:06:09 -0800321/// RelocOffset allows symbolic references in ConstantRelocatables' offsets,
322/// e.g., 8 + LabelOffset, where label offset is the location (code or data)
323/// of a Label that is only determinable during ELF emission.
324class RelocOffset final {
325 RelocOffset(const RelocOffset &) = delete;
326 RelocOffset &operator=(const RelocOffset &) = delete;
327
328public:
Jim Stichnoth3e324002016-03-08 16:18:40 -0800329 template <typename T> static RelocOffset *create(T *AllocOwner) {
330 return new (AllocOwner->template allocate<RelocOffset>()) RelocOffset();
John Porto27fddcc2016-02-02 15:06:09 -0800331 }
332
333 static RelocOffset *create(GlobalContext *Ctx, RelocOffsetT Value) {
334 return new (Ctx->allocate<RelocOffset>()) RelocOffset(Value);
335 }
336
John Porto6e8d3fa2016-02-04 10:35:20 -0800337 void setSubtract(bool Value) { Subtract = Value; }
John Porto27fddcc2016-02-02 15:06:09 -0800338 bool hasOffset() const { return HasOffset; }
339
340 RelocOffsetT getOffset() const {
341 assert(HasOffset);
342 return Offset;
343 }
344
345 void setOffset(const RelocOffsetT Value) {
346 assert(!HasOffset);
John Porto6e8d3fa2016-02-04 10:35:20 -0800347 if (Subtract) {
348 assert(Value != std::numeric_limits<RelocOffsetT>::lowest());
349 Offset = -Value;
350 } else {
351 Offset = Value;
352 }
John Porto27fddcc2016-02-02 15:06:09 -0800353 HasOffset = true;
354 }
355
356private:
357 RelocOffset() = default;
358 explicit RelocOffset(RelocOffsetT Offset) { setOffset(Offset); }
359
John Porto6e8d3fa2016-02-04 10:35:20 -0800360 bool Subtract = false;
John Porto27fddcc2016-02-02 15:06:09 -0800361 bool HasOffset = false;
362 RelocOffsetT Offset;
363};
364
Andrew Scull57e12682015-09-16 11:30:19 -0700365/// RelocatableTuple bundles the parameters that are used to construct an
366/// ConstantRelocatable. It is done this way so that ConstantRelocatable can fit
367/// into the global constant pool template mechanism.
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700368class RelocatableTuple {
Jim Stichnothc6ead202015-02-24 09:30:30 -0800369 RelocatableTuple() = delete;
Jim Stichnoth0795ba02014-10-01 14:23:01 -0700370 RelocatableTuple &operator=(const RelocatableTuple &) = delete;
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700371
372public:
John Portoe82b5602016-02-24 15:58:55 -0800373 RelocatableTuple(const RelocOffsetT Offset,
Jim Stichnoth467ffe52016-03-29 15:01:06 -0700374 const RelocOffsetArray &OffsetExpr, GlobalString Name)
Jim Stichnoth98ba0062016-03-07 09:26:22 -0800375 : Offset(Offset), OffsetExpr(OffsetExpr), Name(Name) {}
John Porto27fddcc2016-02-02 15:06:09 -0800376
John Portoe82b5602016-02-24 15:58:55 -0800377 RelocatableTuple(const RelocOffsetT Offset,
Jim Stichnoth467ffe52016-03-29 15:01:06 -0700378 const RelocOffsetArray &OffsetExpr, GlobalString Name,
379 const std::string &EmitString)
John Portoe82b5602016-02-24 15:58:55 -0800380 : Offset(Offset), OffsetExpr(OffsetExpr), Name(Name),
Jim Stichnoth98ba0062016-03-07 09:26:22 -0800381 EmitString(EmitString) {}
John Portoe82b5602016-02-24 15:58:55 -0800382
Jim Stichnothd2cb4362014-11-20 11:24:42 -0800383 RelocatableTuple(const RelocatableTuple &) = default;
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700384
John Portoe82b5602016-02-24 15:58:55 -0800385 const RelocOffsetT Offset;
John Porto27fddcc2016-02-02 15:06:09 -0800386 const RelocOffsetArray OffsetExpr;
Jim Stichnoth467ffe52016-03-29 15:01:06 -0700387 const GlobalString Name;
388 const std::string EmitString;
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700389};
390
Jim Stichnothd2cb4362014-11-20 11:24:42 -0800391bool operator==(const RelocatableTuple &A, const RelocatableTuple &B);
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700392
Andrew Scull57e12682015-09-16 11:30:19 -0700393/// ConstantRelocatable represents a symbolic constant combined with a fixed
394/// offset.
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700395class ConstantRelocatable : public Constant {
Jim Stichnothc6ead202015-02-24 09:30:30 -0800396 ConstantRelocatable() = delete;
Jim Stichnoth7b451a92014-10-15 14:39:23 -0700397 ConstantRelocatable(const ConstantRelocatable &) = delete;
398 ConstantRelocatable &operator=(const ConstantRelocatable &) = delete;
399
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700400public:
Jim Stichnoth3e324002016-03-08 16:18:40 -0800401 template <typename T>
402 static ConstantRelocatable *create(T *AllocOwner, Type Ty,
Jim Stichnothb36757e2015-10-05 13:55:11 -0700403 const RelocatableTuple &Tuple) {
Jim Stichnoth3e324002016-03-08 16:18:40 -0800404 return new (AllocOwner->template allocate<ConstantRelocatable>())
405 ConstantRelocatable(Ty, Tuple.Offset, Tuple.OffsetExpr, Tuple.Name,
406 Tuple.EmitString);
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700407 }
Jan Voungfe14fb82014-10-13 15:56:32 -0700408
John Porto27fddcc2016-02-02 15:06:09 -0800409 RelocOffsetT getOffset() const {
John Portoe82b5602016-02-24 15:58:55 -0800410 RelocOffsetT Ret = Offset;
John Porto27fddcc2016-02-02 15:06:09 -0800411 for (const auto *const OffsetReloc : OffsetExpr) {
John Portoe82b5602016-02-24 15:58:55 -0800412 Ret += OffsetReloc->getOffset();
John Porto27fddcc2016-02-02 15:06:09 -0800413 }
John Portoe82b5602016-02-24 15:58:55 -0800414 return Ret;
John Porto27fddcc2016-02-02 15:06:09 -0800415 }
416
Jim Stichnoth467ffe52016-03-29 15:01:06 -0700417 const std::string &getEmitString() const { return EmitString; }
John Porto27fddcc2016-02-02 15:06:09 -0800418
Jim Stichnoth467ffe52016-03-29 15:01:06 -0700419 GlobalString getName() const { return Name; }
Jim Stichnothd97c7df2014-06-04 11:57:08 -0700420 using Constant::emit;
Jan Voung76bb0be2015-05-14 09:26:19 -0700421 void emit(TargetLowering *Target) const final;
Jim Stichnoth8ff4b282016-01-04 15:39:06 -0800422 void emitWithoutPrefix(const TargetLowering *Target,
423 const char *Suffix = "") const;
Jim Stichnothd97c7df2014-06-04 11:57:08 -0700424 using Constant::dump;
Jim Stichnothb56c8f42014-09-26 09:28:46 -0700425 void dump(const Cfg *Func, Ostream &Str) const override;
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700426
427 static bool classof(const Operand *Operand) {
428 OperandKind Kind = Operand->getKind();
429 return Kind == kConstRelocatable;
430 }
431
432private:
John Portoe82b5602016-02-24 15:58:55 -0800433 ConstantRelocatable(Type Ty, const RelocOffsetT Offset,
Jim Stichnoth467ffe52016-03-29 15:01:06 -0700434 const RelocOffsetArray &OffsetExpr, GlobalString Name,
435 const std::string &EmitString)
John Portoe82b5602016-02-24 15:58:55 -0800436 : Constant(kConstRelocatable, Ty), Offset(Offset), OffsetExpr(OffsetExpr),
Jim Stichnoth98ba0062016-03-07 09:26:22 -0800437 Name(Name), EmitString(EmitString) {}
John Porto27fddcc2016-02-02 15:06:09 -0800438
John Portoe82b5602016-02-24 15:58:55 -0800439 const RelocOffsetT Offset; /// fixed, known offset to add
440 const RelocOffsetArray OffsetExpr; /// fixed, unknown offset to add
Jim Stichnoth467ffe52016-03-29 15:01:06 -0700441 const GlobalString Name; /// optional for debug/dump
442 const std::string EmitString; /// optional for textual emission
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700443};
444
Andrew Scull57e12682015-09-16 11:30:19 -0700445/// ConstantUndef represents an unspecified bit pattern. Although it is legal to
446/// lower ConstantUndef to any value, backends should try to make code
447/// generation deterministic by lowering ConstantUndefs to 0.
Matt Walad8f4a7d2014-06-18 09:55:03 -0700448class ConstantUndef : public Constant {
Jim Stichnothc6ead202015-02-24 09:30:30 -0800449 ConstantUndef() = delete;
Jim Stichnoth7b451a92014-10-15 14:39:23 -0700450 ConstantUndef(const ConstantUndef &) = delete;
451 ConstantUndef &operator=(const ConstantUndef &) = delete;
452
Matt Walad8f4a7d2014-06-18 09:55:03 -0700453public:
Jim Stichnothb36757e2015-10-05 13:55:11 -0700454 static ConstantUndef *create(GlobalContext *Ctx, Type Ty) {
Jim Stichnothb36757e2015-10-05 13:55:11 -0700455 return new (Ctx->allocate<ConstantUndef>()) ConstantUndef(Ty);
Matt Walad8f4a7d2014-06-18 09:55:03 -0700456 }
457
458 using Constant::emit;
Jan Voung76bb0be2015-05-14 09:26:19 -0700459 void emit(TargetLowering *Target) const final;
Jim Stichnoth2e8bfbb2014-09-16 10:16:00 -0700460 using Constant::dump;
Karl Schimpfb6c96af2014-11-17 10:58:39 -0800461 void dump(const Cfg *, Ostream &Str) const override {
Jim Stichnoth20b71f52015-06-24 15:52:24 -0700462 if (BuildDefs::dump())
Karl Schimpfb6c96af2014-11-17 10:58:39 -0800463 Str << "undef";
464 }
Matt Walad8f4a7d2014-06-18 09:55:03 -0700465
466 static bool classof(const Operand *Operand) {
467 return Operand->getKind() == kConstUndef;
468 }
469
470private:
Jim Stichnothb36757e2015-10-05 13:55:11 -0700471 ConstantUndef(Type Ty) : Constant(kConstUndef, Ty) {}
Matt Walad8f4a7d2014-06-18 09:55:03 -0700472};
473
Jim Stichnoth8aa39662016-02-10 11:20:30 -0800474/// RegNumT is for holding target-specific register numbers, plus the sentinel
Reed Kotler5fa0a5f2016-02-15 20:01:24 -0800475/// value if no register is assigned. Its public ctor allows direct use of enum
476/// values, such as RegNumT(Reg_eax), but not things like RegNumT(Reg_eax+1).
477/// This is to try to prevent inappropriate assumptions about enum ordering. If
478/// needed, the fromInt() method can be used, such as when a RegNumT is based
479/// on a bitvector index.
Jim Stichnoth8aa39662016-02-10 11:20:30 -0800480class RegNumT {
481public:
482 using BaseType = uint32_t;
483 RegNumT() = default;
484 RegNumT(const RegNumT &) = default;
485 template <typename AnyEnum>
486 RegNumT(AnyEnum Value,
487 typename std::enable_if<std::is_enum<AnyEnum>::value, int>::type = 0)
488 : Value(Value) {
489 validate(Value);
490 }
491 RegNumT &operator=(const RegNumT &) = default;
492 operator unsigned() const { return Value; }
493 /// Asserts that the register is valid, i.e. not NoRegisterValue. Note that
494 /// the ctor already does the target-specific limit check.
495 void assertIsValid() const { assert(Value != NoRegisterValue); }
496 static RegNumT fromInt(BaseType Value) { return RegNumT(Value); }
497 /// Marks cases that inappropriately add/subtract RegNumT values, and
498 /// therefore need to be fixed because they make assumptions about register
499 /// enum value ordering. TODO(stichnot): Remove fixme() as soon as all
500 /// current uses are fixed/removed.
501 static RegNumT fixme(BaseType Value) { return RegNumT(Value); }
502 /// The target's staticInit() method should call setLimit() to register the
503 /// upper bound of allowable values.
504 static void setLimit(BaseType Value) {
505 // Make sure it's only called once.
506 assert(Limit == 0);
507 assert(Value != 0);
508 Limit = Value;
509 }
510 // Define NoRegisterValue as an enum value so that it can be used as an
511 // argument for the public ctor if desired.
Nicolas Capens5c4d6772017-01-18 16:57:52 -0500512 enum : BaseType { NoRegisterValue = std::numeric_limits<BaseType>::max() };
Reed Kotler5fa0a5f2016-02-15 20:01:24 -0800513
514 bool hasValue() const { return Value != NoRegisterValue; }
515 bool hasNoValue() const { return !hasValue(); }
Jim Stichnoth8aa39662016-02-10 11:20:30 -0800516
517private:
518 BaseType Value = NoRegisterValue;
519 static BaseType Limit;
520 /// Private ctor called only by fromInt() and fixme().
521 RegNumT(BaseType Value) : Value(Value) { validate(Value); }
522 /// The ctor calls this to validate against the target-supplied limit.
523 static void validate(BaseType Value) {
524 (void)Value;
525 assert(Value == NoRegisterValue || Value < Limit);
526 }
527 /// Disallow operators that inappropriately make assumptions about register
528 /// enum value ordering.
529 bool operator<(const RegNumT &) = delete;
530 bool operator<=(const RegNumT &) = delete;
531 bool operator>(const RegNumT &) = delete;
532 bool operator>=(const RegNumT &) = delete;
533};
534
John Portoe82b5602016-02-24 15:58:55 -0800535/// RegNumBVIter wraps SmallBitVector so that instead of this pattern:
Jim Stichnoth8aa39662016-02-10 11:20:30 -0800536///
537/// for (int i = V.find_first(); i != -1; i = V.find_next(i)) {
538/// RegNumT RegNum = RegNumT::fromInt(i);
539/// ...
540/// }
541///
542/// this cleaner pattern can be used:
543///
544/// for (RegNumT RegNum : RegNumBVIter(V)) {
545/// ...
546/// }
John Portoe82b5602016-02-24 15:58:55 -0800547template <class B> class RegNumBVIterImpl {
548 using T = B;
Jim Stichnoth8aa39662016-02-10 11:20:30 -0800549 static constexpr int Sentinel = -1;
John Portoe82b5602016-02-24 15:58:55 -0800550 RegNumBVIterImpl() = delete;
Jim Stichnoth8aa39662016-02-10 11:20:30 -0800551
552public:
553 class Iterator {
554 Iterator() = delete;
555 Iterator &operator=(const Iterator &) = delete;
556
557 public:
558 explicit Iterator(const T &V) : V(V), Current(V.find_first()) {}
559 Iterator(const T &V, int Value) : V(V), Current(Value) {}
560 Iterator(const Iterator &) = default;
561 RegNumT operator*() {
562 assert(Current != Sentinel);
563 return RegNumT::fromInt(Current);
564 }
565 Iterator &operator++() {
566 assert(Current != Sentinel);
567 Current = V.find_next(Current);
568 return *this;
569 }
570 bool operator!=(Iterator &Other) { return Current != Other.Current; }
571
572 private:
573 const T &V;
574 int Current;
575 };
576
John Portoe82b5602016-02-24 15:58:55 -0800577 RegNumBVIterImpl(const RegNumBVIterImpl &) = default;
578 RegNumBVIterImpl &operator=(const RegNumBVIterImpl &) = delete;
579 explicit RegNumBVIterImpl(const T &V) : V(V) {}
Jim Stichnoth8aa39662016-02-10 11:20:30 -0800580 Iterator begin() { return Iterator(V); }
581 Iterator end() { return Iterator(V, Sentinel); }
582
583private:
584 const T &V;
585};
586
John Portoe82b5602016-02-24 15:58:55 -0800587template <class B> RegNumBVIterImpl<B> RegNumBVIter(const B &BV) {
588 return RegNumBVIterImpl<B>(BV);
589}
590
Andrew Scull57e12682015-09-16 11:30:19 -0700591/// RegWeight is a wrapper for a uint32_t weight value, with a special value
592/// that represents infinite weight, and an addWeight() method that ensures that
593/// W+infinity=infinity.
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -0700594class RegWeight {
595public:
Jim Stichnoth8aa39662016-02-10 11:20:30 -0800596 using BaseType = uint32_t;
Jim Stichnotheafb56c2015-06-22 10:35:22 -0700597 RegWeight() = default;
Jim Stichnoth8aa39662016-02-10 11:20:30 -0800598 explicit RegWeight(BaseType Weight) : Weight(Weight) {}
Jim Stichnoth7e571362015-01-09 11:43:26 -0800599 RegWeight(const RegWeight &) = default;
600 RegWeight &operator=(const RegWeight &) = default;
Jim Stichnoth8aa39662016-02-10 11:20:30 -0800601 constexpr static BaseType Inf = ~0; /// Force regalloc to give a register
602 constexpr static BaseType Zero = 0; /// Force regalloc NOT to give a register
603 constexpr static BaseType Max = Inf - 1; /// Max natural weight.
604 void addWeight(BaseType Delta) {
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -0700605 if (Delta == Inf)
606 Weight = Inf;
607 else if (Weight != Inf)
Andrew Scullaa6c1092015-09-03 17:50:30 -0700608 if (Utils::add_overflow(Weight, Delta, &Weight) || Weight == Inf)
609 Weight = Max;
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -0700610 }
611 void addWeight(const RegWeight &Other) { addWeight(Other.Weight); }
Jim Stichnoth8aa39662016-02-10 11:20:30 -0800612 void setWeight(BaseType Val) { Weight = Val; }
613 BaseType getWeight() const { return Weight; }
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -0700614
615private:
Jim Stichnoth8aa39662016-02-10 11:20:30 -0800616 BaseType Weight = 0;
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -0700617};
618Ostream &operator<<(Ostream &Str, const RegWeight &W);
619bool operator<(const RegWeight &A, const RegWeight &B);
620bool operator<=(const RegWeight &A, const RegWeight &B);
621bool operator==(const RegWeight &A, const RegWeight &B);
622
Andrew Scull57e12682015-09-16 11:30:19 -0700623/// LiveRange is a set of instruction number intervals representing a variable's
624/// live range. Generally there is one interval per basic block where the
625/// variable is live, but adjacent intervals get coalesced into a single
626/// interval.
Jim Stichnothd97c7df2014-06-04 11:57:08 -0700627class LiveRange {
628public:
Manasij Mukherjee7cd926d2016-08-04 12:33:23 -0700629 using RangeElementType = std::pair<InstNumberT, InstNumberT>;
630 /// RangeType is arena-allocated from the Cfg's allocator.
631 using RangeType = CfgVector<RangeElementType>;
Jim Stichnotheafb56c2015-06-22 10:35:22 -0700632 LiveRange() = default;
Andrew Scull57e12682015-09-16 11:30:19 -0700633 /// Special constructor for building a kill set. The advantage is that we can
634 /// reserve the right amount of space in advance.
Andrew Scull00741a02015-09-16 19:04:09 -0700635 explicit LiveRange(const CfgVector<InstNumberT> &Kills) {
Jim Stichnoth2a7fcbb2014-12-04 11:45:03 -0800636 Range.reserve(Kills.size());
637 for (InstNumberT I : Kills)
638 addSegment(I, I);
639 }
Jim Stichnoth87ff3a12014-11-14 10:27:29 -0800640 LiveRange(const LiveRange &) = default;
641 LiveRange &operator=(const LiveRange &) = default;
Jim Stichnothd97c7df2014-06-04 11:57:08 -0700642
643 void reset() {
644 Range.clear();
Jim Stichnoth037fa1d2014-10-07 11:09:33 -0700645 untrim();
Jim Stichnothd97c7df2014-06-04 11:57:08 -0700646 }
Manasij Mukherjee7cd926d2016-08-04 12:33:23 -0700647 void addSegment(InstNumberT Start, InstNumberT End, CfgNode *Node = nullptr);
648 void addSegment(RangeElementType Segment, CfgNode *Node = nullptr) {
649 addSegment(Segment.first, Segment.second, Node);
650 }
Jim Stichnothd97c7df2014-06-04 11:57:08 -0700651
652 bool endsBefore(const LiveRange &Other) const;
Jim Stichnoth037fa1d2014-10-07 11:09:33 -0700653 bool overlaps(const LiveRange &Other, bool UseTrimmed = false) const;
654 bool overlapsInst(InstNumberT OtherBegin, bool UseTrimmed = false) const;
Jim Stichnoth47752552014-10-13 17:15:08 -0700655 bool containsValue(InstNumberT Value, bool IsDest) const;
Jim Stichnothd97c7df2014-06-04 11:57:08 -0700656 bool isEmpty() const { return Range.empty(); }
657 InstNumberT getStart() const {
658 return Range.empty() ? -1 : Range.begin()->first;
659 }
Jim Stichnotha3f57b92015-07-30 12:46:04 -0700660 InstNumberT getEnd() const {
661 return Range.empty() ? -1 : Range.rbegin()->second;
662 }
Jim Stichnothd97c7df2014-06-04 11:57:08 -0700663
Jim Stichnoth037fa1d2014-10-07 11:09:33 -0700664 void untrim() { TrimmedBegin = Range.begin(); }
665 void trim(InstNumberT Lower);
666
Jim Stichnothd97c7df2014-06-04 11:57:08 -0700667 void dump(Ostream &Str) const;
668
Manasij Mukherjee7cd926d2016-08-04 12:33:23 -0700669 SizeT getNumSegments() const { return Range.size(); }
670
671 const RangeType &getSegments() const { return Range; }
672 CfgNode *getNodeForSegment(InstNumberT Begin) {
673 auto Iter = NodeMap.find(Begin);
674 assert(Iter != NodeMap.end());
675 return Iter->second;
676 }
677
Jim Stichnothd97c7df2014-06-04 11:57:08 -0700678private:
Jim Stichnothd97c7df2014-06-04 11:57:08 -0700679 RangeType Range;
Manasij Mukherjee7cd926d2016-08-04 12:33:23 -0700680 CfgUnorderedMap<InstNumberT, CfgNode *> NodeMap;
Andrew Scull57e12682015-09-16 11:30:19 -0700681 /// TrimmedBegin is an optimization for the overlaps() computation. Since the
682 /// linear-scan algorithm always calls it as overlaps(Cur) and Cur advances
683 /// monotonically according to live range start, we can optimize overlaps() by
684 /// ignoring all segments that end before the start of Cur's range. The
685 /// linear-scan code enables this by calling trim() on the ranges of interest
686 /// as Cur advances. Note that linear-scan also has to initialize TrimmedBegin
687 /// at the beginning by calling untrim().
Jim Stichnoth037fa1d2014-10-07 11:09:33 -0700688 RangeType::const_iterator TrimmedBegin;
Jim Stichnothd97c7df2014-06-04 11:57:08 -0700689};
690
691Ostream &operator<<(Ostream &Str, const LiveRange &L);
692
Andrew Scull9612d322015-07-06 14:53:25 -0700693/// Variable represents an operand that is register-allocated or
Andrew Scull57e12682015-09-16 11:30:19 -0700694/// stack-allocated. If it is register-allocated, it will ultimately have a
Jim Stichnothe343e062016-06-28 21:40:33 -0700695/// valid RegNum field.
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700696class Variable : public Operand {
Jim Stichnothc6ead202015-02-24 09:30:30 -0800697 Variable() = delete;
Jim Stichnoth0795ba02014-10-01 14:23:01 -0700698 Variable(const Variable &) = delete;
699 Variable &operator=(const Variable &) = delete;
Jim Stichnoth800dab22014-09-20 12:25:02 -0700700
Andrew Scull6d47bcd2015-09-17 17:10:05 -0700701 enum RegRequirement : uint8_t {
Andrew Scull11c9a322015-08-28 14:24:14 -0700702 RR_MayHaveRegister,
703 RR_MustHaveRegister,
704 RR_MustNotHaveRegister,
705 };
706
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700707public:
Jim Stichnoth9a04c072014-12-11 15:51:42 -0800708 static Variable *create(Cfg *Func, Type Ty, SizeT Index) {
Jim Stichnoth467ffe52016-03-29 15:01:06 -0700709 return new (Func->allocate<Variable>())
710 Variable(Func, kVariable, Ty, Index);
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700711 }
712
713 SizeT getIndex() const { return Number; }
Jim Stichnotha91c3412016-04-05 15:31:43 -0700714 std::string getName() const {
715 if (Name.hasStdString())
716 return Name.toString();
717 return "__" + std::to_string(getIndex());
718 }
Jim Stichnoth467ffe52016-03-29 15:01:06 -0700719 virtual void setName(const Cfg *Func, const std::string &NewName) {
Jim Stichnoth467ffe52016-03-29 15:01:06 -0700720 if (NewName.empty())
721 return;
722 Name = VariableString::createWithString(Func, NewName);
Karl Schimpfc132b762014-09-11 09:43:47 -0700723 }
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700724
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700725 bool getIsArg() const { return IsArgument; }
Andrew Scull6d47bcd2015-09-17 17:10:05 -0700726 virtual void setIsArg(bool Val = true) { IsArgument = Val; }
Jim Stichnoth144cdce2014-09-22 16:02:59 -0700727 bool getIsImplicitArg() const { return IsImplicitArgument; }
728 void setIsImplicitArg(bool Val = true) { IsImplicitArgument = Val; }
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700729
Jim Stichnoth47752552014-10-13 17:15:08 -0700730 void setIgnoreLiveness() { IgnoreLiveness = true; }
Jim Stichnothcc89c952016-03-31 11:55:23 -0700731 bool getIgnoreLiveness() const {
732 return IgnoreLiveness || IsRematerializable;
733 }
Jim Stichnoth47752552014-10-13 17:15:08 -0700734
Jim Stichnothb9a84722016-08-01 13:18:36 -0700735 /// Returns true if the variable either has a definite stack offset, or has
736 /// the UndeterminedStackOffset such that it is guaranteed to have a definite
737 /// stack offset at emission time.
Jim Stichnothfe62f0a2016-07-10 05:13:18 -0700738 bool hasStackOffset() const { return StackOffset != InvalidStackOffset; }
Jim Stichnothb9a84722016-08-01 13:18:36 -0700739 /// Returns true if the variable has a stack offset that is known at this
740 /// time.
741 bool hasKnownStackOffset() const {
742 return StackOffset != InvalidStackOffset &&
743 StackOffset != UndeterminedStackOffset;
744 }
Jim Stichnothfe62f0a2016-07-10 05:13:18 -0700745 int32_t getStackOffset() const {
Jim Stichnothb9a84722016-08-01 13:18:36 -0700746 assert(hasKnownStackOffset());
Jim Stichnothfe62f0a2016-07-10 05:13:18 -0700747 return StackOffset;
748 }
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -0700749 void setStackOffset(int32_t Offset) { StackOffset = Offset; }
Jim Stichnothb9a84722016-08-01 13:18:36 -0700750 /// Set a "placeholder" stack offset before its actual offset has been
751 /// determined.
752 void setHasStackOffset() {
753 if (!hasStackOffset())
754 StackOffset = UndeterminedStackOffset;
755 }
Jim Stichnoth238b4c12015-10-01 07:46:38 -0700756 /// Returns the variable's stack offset in symbolic form, to improve
757 /// readability in DecorateAsm mode.
Jim Stichnotha91c3412016-04-05 15:31:43 -0700758 std::string getSymbolicStackOffset() const {
Jim Stichnoth98ba0062016-03-07 09:26:22 -0800759 if (!BuildDefs::dump())
760 return "";
Jim Stichnoth00b9edb2016-06-25 10:14:39 -0700761 return ".L$lv$" + getName();
Jim Stichnoth238b4c12015-10-01 07:46:38 -0700762 }
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -0700763
Reed Kotler5fa0a5f2016-02-15 20:01:24 -0800764 bool hasReg() const { return getRegNum().hasValue(); }
Jim Stichnoth8aa39662016-02-10 11:20:30 -0800765 RegNumT getRegNum() const { return RegNum; }
766 void setRegNum(RegNumT NewRegNum) {
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -0700767 // Regnum shouldn't be set more than once.
768 assert(!hasReg() || RegNum == NewRegNum);
769 RegNum = NewRegNum;
770 }
Reed Kotler5fa0a5f2016-02-15 20:01:24 -0800771 bool hasRegTmp() const { return getRegNumTmp().hasValue(); }
Jim Stichnoth8aa39662016-02-10 11:20:30 -0800772 RegNumT getRegNumTmp() const { return RegNumTmp; }
773 void setRegNumTmp(RegNumT NewRegNum) { RegNumTmp = NewRegNum; }
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -0700774
Andrew Scull11c9a322015-08-28 14:24:14 -0700775 RegWeight getWeight(const Cfg *Func) const;
776
777 void setMustHaveReg() { RegRequirement = RR_MustHaveRegister; }
778 bool mustHaveReg() const { return RegRequirement == RR_MustHaveRegister; }
779 void setMustNotHaveReg() { RegRequirement = RR_MustNotHaveRegister; }
780 bool mustNotHaveReg() const {
781 return RegRequirement == RR_MustNotHaveRegister;
782 }
Jim Stichnothb9a84722016-08-01 13:18:36 -0700783 bool mayHaveReg() const { return RegRequirement == RR_MayHaveRegister; }
Jim Stichnoth8aa39662016-02-10 11:20:30 -0800784 void setRematerializable(RegNumT NewRegNum, int32_t NewOffset) {
David Sehr4318a412015-11-11 15:01:55 -0800785 IsRematerializable = true;
786 setRegNum(NewRegNum);
787 setStackOffset(NewOffset);
788 setMustHaveReg();
789 }
790 bool isRematerializable() const { return IsRematerializable; }
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -0700791
Jim Stichnothc59288b2015-11-09 11:38:40 -0800792 void setRegClass(uint8_t RC) { RegisterClass = static_cast<RegClass>(RC); }
793 RegClass getRegClass() const { return RegisterClass; }
794
Jim Stichnoth5ce0abb2014-10-15 10:16:54 -0700795 LiveRange &getLiveRange() { return Live; }
Jim Stichnothd97c7df2014-06-04 11:57:08 -0700796 const LiveRange &getLiveRange() const { return Live; }
797 void setLiveRange(const LiveRange &Range) { Live = Range; }
798 void resetLiveRange() { Live.reset(); }
Manasij Mukherjee7cd926d2016-08-04 12:33:23 -0700799 void addLiveRange(InstNumberT Start, InstNumberT End,
800 CfgNode *Node = nullptr) {
Jim Stichnothf9df4522015-08-06 17:50:14 -0700801 assert(!getIgnoreLiveness());
Manasij Mukherjee7cd926d2016-08-04 12:33:23 -0700802 Live.addSegment(Start, End, Node);
Jim Stichnothc6ead202015-02-24 09:30:30 -0800803 }
Jim Stichnoth037fa1d2014-10-07 11:09:33 -0700804 void trimLiveRange(InstNumberT Start) { Live.trim(Start); }
805 void untrimLiveRange() { Live.untrim(); }
Jim Stichnoth5ce0abb2014-10-15 10:16:54 -0700806 bool rangeEndsBefore(const Variable *Other) const {
807 return Live.endsBefore(Other->Live);
808 }
809 bool rangeOverlaps(const Variable *Other) const {
Jim Stichnoth5bff61c2015-10-28 09:26:00 -0700810 constexpr bool UseTrimmed = true;
Jim Stichnoth5ce0abb2014-10-15 10:16:54 -0700811 return Live.overlaps(Other->Live, UseTrimmed);
812 }
813 bool rangeOverlapsStart(const Variable *Other) const {
Jim Stichnoth5bff61c2015-10-28 09:26:00 -0700814 constexpr bool UseTrimmed = true;
Jim Stichnoth5ce0abb2014-10-15 10:16:54 -0700815 return Live.overlapsInst(Other->Live.getStart(), UseTrimmed);
816 }
Jim Stichnothd97c7df2014-06-04 11:57:08 -0700817
Andrew Scull57e12682015-09-16 11:30:19 -0700818 /// Creates a temporary copy of the variable with a different type. Used
819 /// primarily for syntactic correctness of textual assembly emission. Note
820 /// that only basic information is copied, in particular not IsArgument,
821 /// IsImplicitArgument, IgnoreLiveness, RegNumTmp, Live, LoVar, HiVar,
Reed Kotler5fa0a5f2016-02-15 20:01:24 -0800822 /// VarsReal. If NewRegNum.hasValue(), then that register assignment is made
Jim Stichnoth5bff61c2015-10-28 09:26:00 -0700823 /// instead of copying the existing assignment.
Jim Stichnoth467ffe52016-03-29 15:01:06 -0700824 const Variable *asType(const Cfg *Func, Type Ty, RegNumT NewRegNum) const;
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -0700825
Jim Stichnothb56c8f42014-09-26 09:28:46 -0700826 void emit(const Cfg *Func) const override;
Jim Stichnoth2e8bfbb2014-09-16 10:16:00 -0700827 using Operand::dump;
Jim Stichnothb56c8f42014-09-26 09:28:46 -0700828 void dump(const Cfg *Func, Ostream &Str) const override;
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700829
Jan Voung28068ad2015-07-31 12:58:46 -0700830 /// Return reg num of base register, if different from stack/frame register.
Reed Kotler5fa0a5f2016-02-15 20:01:24 -0800831 virtual RegNumT getBaseRegNum() const { return RegNumT(); }
Jan Voung28068ad2015-07-31 12:58:46 -0700832
Jim Stichnothfe62f0a2016-07-10 05:13:18 -0700833 /// Access the LinkedTo field.
834 void setLinkedTo(Variable *Var) { LinkedTo = Var; }
835 Variable *getLinkedTo() const { return LinkedTo; }
836 /// Follow the LinkedTo chain up to the furthest ancestor.
837 Variable *getLinkedToRoot() const {
838 Variable *Root = LinkedTo;
839 if (Root == nullptr)
840 return nullptr;
841 while (Root->LinkedTo != nullptr)
842 Root = Root->LinkedTo;
843 return Root;
Jim Stichnothe343e062016-06-28 21:40:33 -0700844 }
Jim Stichnothb9a84722016-08-01 13:18:36 -0700845 /// Follow the LinkedTo chain up to the furthest stack-allocated ancestor.
846 /// This is only certain to be accurate after register allocation and stack
847 /// slot assignment have completed.
848 Variable *getLinkedToStackRoot() const {
849 Variable *FurthestStackVar = nullptr;
850 for (Variable *Root = LinkedTo; Root != nullptr; Root = Root->LinkedTo) {
851 if (!Root->hasReg() && Root->hasStackOffset()) {
852 FurthestStackVar = Root;
853 }
854 }
855 return FurthestStackVar;
856 }
Jim Stichnothe343e062016-06-28 21:40:33 -0700857
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700858 static bool classof(const Operand *Operand) {
Jim Stichnoth800dab22014-09-20 12:25:02 -0700859 OperandKind Kind = Operand->getKind();
Andrew Scull6ef79492015-09-09 15:50:42 -0700860 return Kind >= kVariable && Kind <= kVariable_Max;
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700861 }
862
Sagar Thakure160ed92016-05-30 07:54:47 -0700863 SizeT hashValue() const override { return std::hash<SizeT>()(getIndex()); }
Manasij Mukherjee032c3152016-05-24 14:25:04 -0700864
Alexis Hetu932640b2018-06-20 15:35:53 -0400865 inline void* getExternalData() const { return externalData; }
866 inline void setExternalData(void* data) { externalData = data; }
867
Jim Stichnoth800dab22014-09-20 12:25:02 -0700868protected:
Jim Stichnoth467ffe52016-03-29 15:01:06 -0700869 Variable(const Cfg *Func, OperandKind K, Type Ty, SizeT Index)
Jim Stichnothc59288b2015-11-09 11:38:40 -0800870 : Operand(K, Ty), Number(Index),
Jim Stichnoth467ffe52016-03-29 15:01:06 -0700871 Name(VariableString::createWithoutString(Func)),
Jim Stichnothc59288b2015-11-09 11:38:40 -0800872 RegisterClass(static_cast<RegClass>(Ty)) {
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700873 Vars = VarsReal;
874 Vars[0] = this;
875 NumVars = 1;
876 }
Andrew Scull57e12682015-09-16 11:30:19 -0700877 /// Number is unique across all variables, and is used as a (bit)vector index
878 /// for liveness analysis.
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700879 const SizeT Number;
Jim Stichnoth467ffe52016-03-29 15:01:06 -0700880 VariableString Name;
Jim Stichnotheafb56c2015-06-22 10:35:22 -0700881 bool IsArgument = false;
882 bool IsImplicitArgument = false;
Andrew Scull57e12682015-09-16 11:30:19 -0700883 /// IgnoreLiveness means that the variable should be ignored when constructing
884 /// and validating live ranges. This is usually reserved for the stack
Jim Stichnoth69660552015-09-18 06:41:02 -0700885 /// pointer and other physical registers specifically referenced by name.
Jim Stichnotheafb56c2015-06-22 10:35:22 -0700886 bool IgnoreLiveness = false;
David Sehr4318a412015-11-11 15:01:55 -0800887 // If IsRematerializable, RegNum keeps track of which register (stack or frame
888 // pointer), and StackOffset is the known offset from that register.
889 bool IsRematerializable = false;
Andrew Scull6d47bcd2015-09-17 17:10:05 -0700890 RegRequirement RegRequirement = RR_MayHaveRegister;
Jim Stichnothc59288b2015-11-09 11:38:40 -0800891 RegClass RegisterClass;
Reed Kotler5fa0a5f2016-02-15 20:01:24 -0800892 /// RegNum is the allocated register, (as long as RegNum.hasValue() is true).
893 RegNumT RegNum;
Andrew Scull9612d322015-07-06 14:53:25 -0700894 /// RegNumTmp is the tentative assignment during register allocation.
Reed Kotler5fa0a5f2016-02-15 20:01:24 -0800895 RegNumT RegNumTmp;
Jim Stichnothb9a84722016-08-01 13:18:36 -0700896 static constexpr int32_t InvalidStackOffset =
897 std::numeric_limits<int32_t>::min();
898 static constexpr int32_t UndeterminedStackOffset =
899 1 + std::numeric_limits<int32_t>::min();
Andrew Scull6d47bcd2015-09-17 17:10:05 -0700900 /// StackOffset is the canonical location on stack (only if
Reed Kotler5fa0a5f2016-02-15 20:01:24 -0800901 /// RegNum.hasNoValue() || IsArgument).
Jim Stichnothfe62f0a2016-07-10 05:13:18 -0700902 int32_t StackOffset = InvalidStackOffset;
Jim Stichnothd97c7df2014-06-04 11:57:08 -0700903 LiveRange Live;
Andrew Scull57e12682015-09-16 11:30:19 -0700904 /// VarsReal (and Operand::Vars) are set up such that Vars[0] == this.
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700905 Variable *VarsReal[1];
Jim Stichnothe343e062016-06-28 21:40:33 -0700906 /// This Variable may be "linked" to another Variable, such that if neither
907 /// Variable gets a register, they are guaranteed to share a stack location.
Jim Stichnothfe62f0a2016-07-10 05:13:18 -0700908 Variable *LinkedTo = nullptr;
Alexis Hetu932640b2018-06-20 15:35:53 -0400909 /// External data can be set by an optimizer to compute and retain any
910 /// information related to the current variable. All the memory used to
911 /// store this information must be managed by the optimizer.
912 void* externalData = nullptr;
Jim Stichnothf7c9a142014-04-29 10:52:43 -0700913};
914
Andrew Scull6d47bcd2015-09-17 17:10:05 -0700915// Variable64On32 represents a 64-bit variable on a 32-bit architecture. In
916// this situation the variable must be split into a low and a high word.
917class Variable64On32 : public Variable {
918 Variable64On32() = delete;
919 Variable64On32(const Variable64On32 &) = delete;
920 Variable64On32 &operator=(const Variable64On32 &) = delete;
921
922public:
923 static Variable64On32 *create(Cfg *Func, Type Ty, SizeT Index) {
John Portoa83bfde2015-09-18 08:43:02 -0700924 return new (Func->allocate<Variable64On32>())
Jim Stichnoth467ffe52016-03-29 15:01:06 -0700925 Variable64On32(Func, kVariable64On32, Ty, Index);
Andrew Scull6d47bcd2015-09-17 17:10:05 -0700926 }
927
Jim Stichnoth467ffe52016-03-29 15:01:06 -0700928 void setName(const Cfg *Func, const std::string &NewName) override {
Andrew Scull6d47bcd2015-09-17 17:10:05 -0700929 Variable::setName(Func, NewName);
930 if (LoVar && HiVar) {
Jim Stichnotha91c3412016-04-05 15:31:43 -0700931 LoVar->setName(Func, getName() + "__lo");
932 HiVar->setName(Func, getName() + "__hi");
Andrew Scull6d47bcd2015-09-17 17:10:05 -0700933 }
934 }
935
936 void setIsArg(bool Val = true) override {
937 Variable::setIsArg(Val);
938 if (LoVar && HiVar) {
939 LoVar->setIsArg(Val);
940 HiVar->setIsArg(Val);
941 }
942 }
943
944 Variable *getLo() const {
945 assert(LoVar != nullptr);
946 return LoVar;
947 }
948 Variable *getHi() const {
949 assert(HiVar != nullptr);
950 return HiVar;
951 }
952
953 void initHiLo(Cfg *Func) {
954 assert(LoVar == nullptr);
955 assert(HiVar == nullptr);
956 LoVar = Func->makeVariable(IceType_i32);
957 HiVar = Func->makeVariable(IceType_i32);
958 LoVar->setIsArg(getIsArg());
959 HiVar->setIsArg(getIsArg());
Jim Stichnoth467ffe52016-03-29 15:01:06 -0700960 if (BuildDefs::dump()) {
Jim Stichnotha91c3412016-04-05 15:31:43 -0700961 LoVar->setName(Func, getName() + "__lo");
962 HiVar->setName(Func, getName() + "__hi");
Jim Stichnoth467ffe52016-03-29 15:01:06 -0700963 }
Andrew Scull6d47bcd2015-09-17 17:10:05 -0700964 }
965
966 static bool classof(const Operand *Operand) {
967 OperandKind Kind = Operand->getKind();
968 return Kind == kVariable64On32;
969 }
970
971protected:
Jim Stichnoth467ffe52016-03-29 15:01:06 -0700972 Variable64On32(const Cfg *Func, OperandKind K, Type Ty, SizeT Index)
973 : Variable(Func, K, Ty, Index) {
Andrew Scull6d47bcd2015-09-17 17:10:05 -0700974 assert(typeWidthInBytes(Ty) == 8);
975 }
976
977 Variable *LoVar = nullptr;
978 Variable *HiVar = nullptr;
979};
980
Jaydeep Patil958ddb72016-10-03 07:52:48 -0700981// VariableVecOn32 represents a 128-bit vector variable on a 32-bit
982// architecture. In this case the variable must be split into 4 containers.
983class VariableVecOn32 : public Variable {
984 VariableVecOn32() = delete;
985 VariableVecOn32(const VariableVecOn32 &) = delete;
986 VariableVecOn32 &operator=(const VariableVecOn32 &) = delete;
987
988public:
989 static VariableVecOn32 *create(Cfg *Func, Type Ty, SizeT Index) {
990 return new (Func->allocate<VariableVecOn32>())
991 VariableVecOn32(Func, kVariableVecOn32, Ty, Index);
992 }
993
994 void setName(const Cfg *Func, const std::string &NewName) override {
995 Variable::setName(Func, NewName);
996 if (!Containers.empty()) {
Jaydeep Patil3a01f332016-10-17 06:33:50 -0700997 for (SizeT i = 0; i < ContainersPerVector; ++i) {
Jaydeep Patil958ddb72016-10-03 07:52:48 -0700998 Containers[i]->setName(Func, getName() + "__cont" + std::to_string(i));
999 }
1000 }
1001 }
1002
1003 void setIsArg(bool Val = true) override {
1004 Variable::setIsArg(Val);
1005 for (Variable *Var : Containers) {
1006 Var->setIsArg(getIsArg());
1007 }
1008 }
1009
1010 const VarList &getContainers() const { return Containers; }
1011
1012 void initVecElement(Cfg *Func) {
Jaydeep Patil3a01f332016-10-17 06:33:50 -07001013 for (SizeT i = 0; i < ContainersPerVector; ++i) {
Jaydeep Patil958ddb72016-10-03 07:52:48 -07001014 Variable *Var = Func->makeVariable(IceType_i32);
1015 Var->setIsArg(getIsArg());
1016 if (BuildDefs::dump()) {
1017 Var->setName(Func, getName() + "__cont" + std::to_string(i));
1018 }
1019 Containers.push_back(Var);
1020 }
1021 }
1022
1023 static bool classof(const Operand *Operand) {
1024 OperandKind Kind = Operand->getKind();
1025 return Kind == kVariableVecOn32;
1026 }
1027
1028 // A 128-bit vector value is mapped onto 4 32-bit register values.
Jaydeep Patil3a01f332016-10-17 06:33:50 -07001029 static constexpr SizeT ContainersPerVector = 4;
Jaydeep Patil958ddb72016-10-03 07:52:48 -07001030
1031protected:
1032 VariableVecOn32(const Cfg *Func, OperandKind K, Type Ty, SizeT Index)
1033 : Variable(Func, K, Ty, Index) {
1034 assert(typeWidthInBytes(Ty) ==
Jaydeep Patil3a01f332016-10-17 06:33:50 -07001035 ContainersPerVector * typeWidthInBytes(IceType_i32));
Jaydeep Patil958ddb72016-10-03 07:52:48 -07001036 }
1037
1038 VarList Containers;
1039};
1040
Jim Stichnoth877b04e2014-10-15 15:13:06 -07001041enum MetadataKind {
Andrew Scull9612d322015-07-06 14:53:25 -07001042 VMK_Uses, /// Track only uses, not defs
1043 VMK_SingleDefs, /// Track uses+defs, but only record single def
1044 VMK_All /// Track uses+defs, including full def list
Jim Stichnoth877b04e2014-10-15 15:13:06 -07001045};
Andrew Scull00741a02015-09-16 19:04:09 -07001046using InstDefList = CfgVector<const Inst *>;
Jim Stichnothad403532014-09-25 12:44:17 -07001047
Andrew Scull9612d322015-07-06 14:53:25 -07001048/// VariableTracking tracks the metadata for a single variable. It is
1049/// only meant to be used internally by VariablesMetadata.
Jim Stichnoth144cdce2014-09-22 16:02:59 -07001050class VariableTracking {
1051public:
1052 enum MultiDefState {
1053 // TODO(stichnot): Consider using just a simple counter.
1054 MDS_Unknown,
1055 MDS_SingleDef,
Jim Stichnothad403532014-09-25 12:44:17 -07001056 MDS_MultiDefSingleBlock,
1057 MDS_MultiDefMultiBlock
Jim Stichnoth144cdce2014-09-22 16:02:59 -07001058 };
Jim Stichnothcc89c952016-03-31 11:55:23 -07001059 enum MultiBlockState {
1060 MBS_Unknown, // Not yet initialized, so be conservative
1061 MBS_NoUses, // Known to have no uses
1062 MBS_SingleBlock, // All uses in are in a single block
1063 MBS_MultiBlock // Several uses across several blocks
1064 };
Jim Stichnotheafb56c2015-06-22 10:35:22 -07001065 VariableTracking() = default;
Jim Stichnoth7e571362015-01-09 11:43:26 -08001066 VariableTracking(const VariableTracking &) = default;
Jim Stichnothcc89c952016-03-31 11:55:23 -07001067 VariableTracking &operator=(const VariableTracking &) = default;
1068 VariableTracking(MultiBlockState MultiBlock) : MultiBlock(MultiBlock) {}
Jim Stichnoth144cdce2014-09-22 16:02:59 -07001069 MultiDefState getMultiDef() const { return MultiDef; }
1070 MultiBlockState getMultiBlock() const { return MultiBlock; }
Jim Stichnoth48e3ae52015-10-01 13:33:35 -07001071 const Inst *getFirstDefinitionSingleBlock() const;
Jim Stichnothad403532014-09-25 12:44:17 -07001072 const Inst *getSingleDefinition() const;
Jim Stichnoth48e3ae52015-10-01 13:33:35 -07001073 const Inst *getFirstDefinition() const;
Jim Stichnoth877b04e2014-10-15 15:13:06 -07001074 const InstDefList &getLatterDefinitions() const { return Definitions; }
Jim Stichnotha3f57b92015-07-30 12:46:04 -07001075 CfgNode *getNode() const { return SingleUseNode; }
Andrew Scullaa6c1092015-09-03 17:50:30 -07001076 RegWeight getUseWeight() const { return UseWeight; }
Jim Stichnotha3f57b92015-07-30 12:46:04 -07001077 void markUse(MetadataKind TrackingKind, const Inst *Instr, CfgNode *Node,
1078 bool IsImplicit);
1079 void markDef(MetadataKind TrackingKind, const Inst *Instr, CfgNode *Node);
Jim Stichnoth144cdce2014-09-22 16:02:59 -07001080
1081private:
Jim Stichnotheafb56c2015-06-22 10:35:22 -07001082 MultiDefState MultiDef = MDS_Unknown;
1083 MultiBlockState MultiBlock = MBS_Unknown;
Jim Stichnotha3f57b92015-07-30 12:46:04 -07001084 CfgNode *SingleUseNode = nullptr;
1085 CfgNode *SingleDefNode = nullptr;
Jim Stichnoth48e3ae52015-10-01 13:33:35 -07001086 /// All definitions of the variable are collected in Definitions[] (except for
1087 /// the earliest definition), in increasing order of instruction number.
Andrew Scull9612d322015-07-06 14:53:25 -07001088 InstDefList Definitions; /// Only used if Kind==VMK_All
Jim Stichnoth48e3ae52015-10-01 13:33:35 -07001089 const Inst *FirstOrSingleDefinition = nullptr;
Andrew Scullaa6c1092015-09-03 17:50:30 -07001090 RegWeight UseWeight;
Jim Stichnoth144cdce2014-09-22 16:02:59 -07001091};
1092
Andrew Scull11c9a322015-08-28 14:24:14 -07001093/// VariablesMetadata analyzes and summarizes the metadata for the complete set
1094/// of Variables.
Jim Stichnoth144cdce2014-09-22 16:02:59 -07001095class VariablesMetadata {
Jim Stichnothc6ead202015-02-24 09:30:30 -08001096 VariablesMetadata() = delete;
Jim Stichnoth7b451a92014-10-15 14:39:23 -07001097 VariablesMetadata(const VariablesMetadata &) = delete;
1098 VariablesMetadata &operator=(const VariablesMetadata &) = delete;
1099
Jim Stichnoth144cdce2014-09-22 16:02:59 -07001100public:
Jim Stichnothc6ead202015-02-24 09:30:30 -08001101 explicit VariablesMetadata(const Cfg *Func) : Func(Func) {}
Andrew Scull57e12682015-09-16 11:30:19 -07001102 /// Initialize the state by traversing all instructions/variables in the CFG.
Jim Stichnoth877b04e2014-10-15 15:13:06 -07001103 void init(MetadataKind TrackingKind);
Andrew Scull57e12682015-09-16 11:30:19 -07001104 /// Add a single node. This is called by init(), and can be called
Andrew Scull9612d322015-07-06 14:53:25 -07001105 /// incrementally from elsewhere, e.g. after edge-splitting.
Jim Stichnoth336f6c42014-10-30 15:01:31 -07001106 void addNode(CfgNode *Node);
Jim Stichnoth48e3ae52015-10-01 13:33:35 -07001107 MetadataKind getKind() const { return Kind; }
Andrew Scull57e12682015-09-16 11:30:19 -07001108 /// Returns whether the given Variable is tracked in this object. It should
Andrew Scull11c9a322015-08-28 14:24:14 -07001109 /// only return false if changes were made to the CFG after running init(), in
1110 /// which case the state is stale and the results shouldn't be trusted (but it
1111 /// may be OK e.g. for dumping).
Jim Stichnoth144cdce2014-09-22 16:02:59 -07001112 bool isTracked(const Variable *Var) const {
1113 return Var->getIndex() < Metadata.size();
1114 }
Jim Stichnothad403532014-09-25 12:44:17 -07001115
Andrew Scull9612d322015-07-06 14:53:25 -07001116 /// Returns whether the given Variable has multiple definitions.
Jim Stichnoth144cdce2014-09-22 16:02:59 -07001117 bool isMultiDef(const Variable *Var) const;
Andrew Scull57e12682015-09-16 11:30:19 -07001118 /// Returns the first definition instruction of the given Variable. This is
Andrew Scull11c9a322015-08-28 14:24:14 -07001119 /// only valid for variables whose definitions are all within the same block,
1120 /// e.g. T after the lowered sequence "T=B; T+=C; A=T", for which
Jim Stichnoth48e3ae52015-10-01 13:33:35 -07001121 /// getFirstDefinitionSingleBlock(T) would return the "T=B" instruction. For
1122 /// variables with definitions span multiple blocks, nullptr is returned.
1123 const Inst *getFirstDefinitionSingleBlock(const Variable *Var) const;
Andrew Scull57e12682015-09-16 11:30:19 -07001124 /// Returns the definition instruction of the given Variable, when the
1125 /// variable has exactly one definition. Otherwise, nullptr is returned.
Jim Stichnothad403532014-09-25 12:44:17 -07001126 const Inst *getSingleDefinition(const Variable *Var) const;
Jim Stichnoth48e3ae52015-10-01 13:33:35 -07001127 /// getFirstDefinition() and getLatterDefinitions() are used together to
1128 /// return the complete set of instructions that define the given Variable,
1129 /// regardless of whether the definitions are within the same block (in
1130 /// contrast to getFirstDefinitionSingleBlock).
1131 const Inst *getFirstDefinition(const Variable *Var) const;
Jim Stichnoth877b04e2014-10-15 15:13:06 -07001132 const InstDefList &getLatterDefinitions(const Variable *Var) const;
Jim Stichnothad403532014-09-25 12:44:17 -07001133
Andrew Scull57e12682015-09-16 11:30:19 -07001134 /// Returns whether the given Variable is live across multiple blocks. Mainly,
1135 /// this is used to partition Variables into single-block versus multi-block
1136 /// sets for leveraging sparsity in liveness analysis, and for implementing
1137 /// simple stack slot coalescing. As a special case, function arguments are
1138 /// always considered multi-block because they are live coming into the entry
1139 /// block.
Jim Stichnoth144cdce2014-09-22 16:02:59 -07001140 bool isMultiBlock(const Variable *Var) const;
Jim Stichnothcc89c952016-03-31 11:55:23 -07001141 bool isSingleBlock(const Variable *Var) const;
Andrew Scull9612d322015-07-06 14:53:25 -07001142 /// Returns the node that the given Variable is used in, assuming
Andrew Scull57e12682015-09-16 11:30:19 -07001143 /// isMultiBlock() returns false. Otherwise, nullptr is returned.
Jim Stichnotha3f57b92015-07-30 12:46:04 -07001144 CfgNode *getLocalUseNode(const Variable *Var) const;
Jim Stichnoth144cdce2014-09-22 16:02:59 -07001145
Andrew Scull11c9a322015-08-28 14:24:14 -07001146 /// Returns the total use weight computed as the sum of uses multiplied by a
1147 /// loop nest depth factor for each use.
Andrew Scullaa6c1092015-09-03 17:50:30 -07001148 RegWeight getUseWeight(const Variable *Var) const;
Andrew Scull11c9a322015-08-28 14:24:14 -07001149
Jim Stichnoth144cdce2014-09-22 16:02:59 -07001150private:
1151 const Cfg *Func;
Jim Stichnoth877b04e2014-10-15 15:13:06 -07001152 MetadataKind Kind;
Andrew Scull00741a02015-09-16 19:04:09 -07001153 CfgVector<VariableTracking> Metadata;
Nicolas Capens86e5d882016-09-08 12:47:42 -04001154 static const InstDefList *NoDefinitions;
Jim Stichnoth144cdce2014-09-22 16:02:59 -07001155};
1156
Eric Holk80ee5b32016-05-06 14:28:04 -07001157/// BooleanVariable represents a variable that was the zero-extended result of a
1158/// comparison. It maintains a pointer to its original i1 source so that the
1159/// WASM frontend can avoid adding needless comparisons.
1160class BooleanVariable : public Variable {
1161 BooleanVariable() = delete;
1162 BooleanVariable(const BooleanVariable &) = delete;
1163 BooleanVariable &operator=(const BooleanVariable &) = delete;
1164
1165 BooleanVariable(const Cfg *Func, OperandKind K, Type Ty, SizeT Index)
1166 : Variable(Func, K, Ty, Index) {}
1167
1168public:
1169 static BooleanVariable *create(Cfg *Func, Type Ty, SizeT Index) {
1170 return new (Func->allocate<BooleanVariable>())
1171 BooleanVariable(Func, kVariable, Ty, Index);
1172 }
1173
1174 virtual Variable *asBoolean() { return BoolSource; }
1175
1176 void setBoolSource(Variable *Src) { BoolSource = Src; }
1177
1178 static bool classof(const Operand *Operand) {
1179 return Operand->getKind() == kVariableBoolean;
1180 }
1181
1182private:
1183 Variable *BoolSource = nullptr;
1184};
1185
Jim Stichnothf7c9a142014-04-29 10:52:43 -07001186} // end of namespace Ice
1187
1188#endif // SUBZERO_SRC_ICEOPERAND_H