| OLD | NEW |
| 1 //===- subzero/src/IceOperand.h - High-level operands -----------*- C++ -*-===// | 1 //===- subzero/src/IceOperand.h - High-level operands -----------*- C++ -*-===// |
| 2 // | 2 // |
| 3 // The Subzero Code Generator | 3 // The Subzero Code Generator |
| 4 // | 4 // |
| 5 // This file is distributed under the University of Illinois Open Source | 5 // This file is distributed under the University of Illinois Open Source |
| 6 // License. See LICENSE.TXT for details. | 6 // License. See LICENSE.TXT for details. |
| 7 // | 7 // |
| 8 //===----------------------------------------------------------------------===// | 8 //===----------------------------------------------------------------------===// |
| 9 /// | 9 /// |
| 10 /// \file | 10 /// \file |
| 11 /// \brief Declares the Operand class and its target-independent subclasses. | 11 /// \brief Declares the Operand class and its target-independent subclasses. |
| 12 /// | 12 /// |
| 13 /// The main classes are Variable, which represents an LLVM variable that is | 13 /// The main classes are Variable, which represents an LLVM variable that is |
| 14 /// either register- or stack-allocated, and the Constant hierarchy, which | 14 /// either register- or stack-allocated, and the Constant hierarchy, which |
| 15 /// represents integer, floating-point, and/or symbolic constants. | 15 /// represents integer, floating-point, and/or symbolic constants. |
| 16 /// | 16 /// |
| 17 //===----------------------------------------------------------------------===// | 17 //===----------------------------------------------------------------------===// |
| 18 | 18 |
| 19 #ifndef SUBZERO_SRC_ICEOPERAND_H | 19 #ifndef SUBZERO_SRC_ICEOPERAND_H |
| 20 #define SUBZERO_SRC_ICEOPERAND_H | 20 #define SUBZERO_SRC_ICEOPERAND_H |
| 21 | 21 |
| 22 #include "IceDefs.h" | 22 #include "IceDefs.h" |
| 23 #include "IceCfg.h" | 23 #include "IceCfg.h" |
| 24 #include "IceGlobalContext.h" | 24 #include "IceGlobalContext.h" |
| 25 #include "IceStringPool.h" |
| 25 #include "IceTypes.h" | 26 #include "IceTypes.h" |
| 26 | 27 |
| 27 #include "llvm/Support/Format.h" | 28 #include "llvm/Support/Format.h" |
| 28 | 29 |
| 29 #include <limits> | 30 #include <limits> |
| 30 #include <type_traits> | 31 #include <type_traits> |
| 31 | 32 |
| 32 namespace Ice { | 33 namespace Ice { |
| 33 | 34 |
| 34 class Operand { | 35 class Operand { |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 114 } | 115 } |
| 115 | 116 |
| 116 /// Constant is the abstract base class for constants. All constants are | 117 /// Constant is the abstract base class for constants. All constants are |
| 117 /// allocated from a global arena and are pooled. | 118 /// allocated from a global arena and are pooled. |
| 118 class Constant : public Operand { | 119 class Constant : public Operand { |
| 119 Constant() = delete; | 120 Constant() = delete; |
| 120 Constant(const Constant &) = delete; | 121 Constant(const Constant &) = delete; |
| 121 Constant &operator=(const Constant &) = delete; | 122 Constant &operator=(const Constant &) = delete; |
| 122 | 123 |
| 123 public: | 124 public: |
| 124 virtual void emitPoolLabel(Ostream &Str) const { | |
| 125 (void)Str; | |
| 126 llvm::report_fatal_error("emitPoolLabel not defined for type"); | |
| 127 }; | |
| 128 // Declare the lookup counter to take minimal space in a non-DUMP build. | 125 // Declare the lookup counter to take minimal space in a non-DUMP build. |
| 129 using CounterType = | 126 using CounterType = |
| 130 std::conditional<BuildDefs::dump(), uint64_t, uint8_t>::type; | 127 std::conditional<BuildDefs::dump(), uint64_t, uint8_t>::type; |
| 131 void emit(const Cfg *Func) const override { emit(Func->getTarget()); } | 128 void emit(const Cfg *Func) const override { emit(Func->getTarget()); } |
| 132 virtual void emit(TargetLowering *Target) const = 0; | 129 virtual void emit(TargetLowering *Target) const = 0; |
| 133 | 130 |
| 134 static bool classof(const Operand *Operand) { | 131 static bool classof(const Operand *Operand) { |
| 135 OperandKind Kind = Operand->getKind(); | 132 OperandKind Kind = Operand->getKind(); |
| 136 return Kind >= kConst_Base && Kind <= kConst_Max; | 133 return Kind >= kConst_Base && Kind <= kConst_Max; |
| 137 } | 134 } |
| 138 | 135 |
| 136 const GlobalString getLabelName() const { return LabelName; } |
| 137 |
| 139 /// Judge if this given immediate should be randomized or pooled By default | 138 /// Judge if this given immediate should be randomized or pooled By default |
| 140 /// should return false, only constant integers should truly go through this | 139 /// should return false, only constant integers should truly go through this |
| 141 /// method. | 140 /// method. |
| 142 virtual bool shouldBeRandomizedOrPooled(const GlobalContext *Ctx) { | 141 virtual bool shouldBeRandomizedOrPooled() const { return false; } |
| 143 (void)Ctx; | |
| 144 return false; | |
| 145 } | |
| 146 | 142 |
| 147 void setShouldBePooled(bool R) { ShouldBePooled = R; } | 143 void initShouldBePooled(); |
| 148 bool getShouldBePooled() const { return ShouldBePooled; } | 144 bool getShouldBePooled() const { return ShouldBePooled; } |
| 149 | 145 |
| 150 // This should be thread-safe because the constant pool lock is acquired | 146 // This should be thread-safe because the constant pool lock is acquired |
| 151 // before the method is invoked. | 147 // before the method is invoked. |
| 152 void updateLookupCount() { | 148 void updateLookupCount() { |
| 153 if (!BuildDefs::dump()) | 149 if (!BuildDefs::dump()) |
| 154 return; | 150 return; |
| 155 ++LookupCount; | 151 ++LookupCount; |
| 156 } | 152 } |
| 157 CounterType getLookupCount() const { return LookupCount; } | 153 CounterType getLookupCount() const { return LookupCount; } |
| 158 | 154 |
| 159 protected: | 155 protected: |
| 160 Constant(OperandKind Kind, Type Ty) : Operand(Kind, Ty) { | 156 Constant(GlobalContext *, OperandKind Kind, Type Ty) : Operand(Kind, Ty) { |
| 161 Vars = nullptr; | 157 Vars = nullptr; |
| 162 NumVars = 0; | 158 NumVars = 0; |
| 163 } | 159 } |
| 160 GlobalString LabelName; |
| 164 /// Whether we should pool this constant. Usually Float/Double and pooled | 161 /// Whether we should pool this constant. Usually Float/Double and pooled |
| 165 /// Integers should be flagged true. | 162 /// Integers should be flagged true. Ideally this field would be const, but |
| 163 /// it needs to be initialized only after the subclass is fully constructed. |
| 166 bool ShouldBePooled = false; | 164 bool ShouldBePooled = false; |
| 167 /// Note: If ShouldBePooled is ever removed from the base class, we will want | 165 /// Note: If ShouldBePooled is ever removed from the base class, we will want |
| 168 /// to completely disable LookupCount in a non-DUMP build to save space. | 166 /// to completely disable LookupCount in a non-DUMP build to save space. |
| 169 CounterType LookupCount = 0; | 167 CounterType LookupCount = 0; |
| 170 }; | 168 }; |
| 171 | 169 |
| 172 /// ConstantPrimitive<> wraps a primitive type. | 170 /// ConstantPrimitive<> wraps a primitive type. |
| 173 template <typename T, Operand::OperandKind K> | 171 template <typename T, Operand::OperandKind K> |
| 174 class ConstantPrimitive : public Constant { | 172 class ConstantPrimitive : public Constant { |
| 175 ConstantPrimitive() = delete; | 173 ConstantPrimitive() = delete; |
| 176 ConstantPrimitive(const ConstantPrimitive &) = delete; | 174 ConstantPrimitive(const ConstantPrimitive &) = delete; |
| 177 ConstantPrimitive &operator=(const ConstantPrimitive &) = delete; | 175 ConstantPrimitive &operator=(const ConstantPrimitive &) = delete; |
| 178 | 176 |
| 179 public: | 177 public: |
| 180 using PrimType = T; | 178 using PrimType = T; |
| 181 | 179 |
| 182 static ConstantPrimitive *create(GlobalContext *Ctx, Type Ty, | 180 static ConstantPrimitive *create(GlobalContext *Ctx, Type Ty, |
| 183 PrimType Value) { | 181 PrimType Value) { |
| 184 return new (Ctx->allocate<ConstantPrimitive>()) | 182 auto *Const = new (Ctx->allocate<ConstantPrimitive>()) |
| 185 ConstantPrimitive(Ty, Value); | 183 ConstantPrimitive(Ctx, Ty, Value); |
| 184 Const->initShouldBePooled(); |
| 185 if (Const->getShouldBePooled()) |
| 186 Const->initName(Ctx); |
| 187 return Const; |
| 186 } | 188 } |
| 187 PrimType getValue() const { return Value; } | 189 PrimType getValue() const { return Value; } |
| 188 void emitPoolLabel(Ostream &Str) const final { | 190 using Constant::emit; |
| 191 void emit(TargetLowering *Target) const final; |
| 192 using Constant::dump; |
| 193 void dump(const Cfg *, Ostream &Str) const override { |
| 194 if (BuildDefs::dump()) |
| 195 Str << getValue(); |
| 196 } |
| 197 |
| 198 static bool classof(const Operand *Operand) { |
| 199 return Operand->getKind() == K; |
| 200 } |
| 201 |
| 202 virtual bool shouldBeRandomizedOrPooled() const override { return false; } |
| 203 |
| 204 private: |
| 205 ConstantPrimitive(GlobalContext *Ctx, Type Ty, PrimType Value) |
| 206 : Constant(Ctx, K, Ty), Value(Value) {} |
| 207 |
| 208 void initName(GlobalContext *Ctx) { |
| 209 std::string Buffer; |
| 210 llvm::raw_string_ostream Str(Buffer); |
| 189 Str << ".L$" << getType() << "$"; | 211 Str << ".L$" << getType() << "$"; |
| 190 // Print hex characters byte by byte, starting from the most significant | 212 // Print hex characters byte by byte, starting from the most significant |
| 191 // byte. NOTE: This ordering assumes Subzero runs on a little-endian | 213 // byte. NOTE: This ordering assumes Subzero runs on a little-endian |
| 192 // platform. That means the possibility of different label names depending | 214 // platform. That means the possibility of different label names depending |
| 193 // on the endian-ness of the platform where Subzero runs. | 215 // on the endian-ness of the platform where Subzero runs. |
| 194 for (unsigned i = 0; i < sizeof(Value); ++i) { | 216 for (unsigned i = 0; i < sizeof(Value); ++i) { |
| 195 constexpr unsigned HexWidthChars = 2; | 217 constexpr unsigned HexWidthChars = 2; |
| 196 unsigned Offset = sizeof(Value) - 1 - i; | 218 unsigned Offset = sizeof(Value) - 1 - i; |
| 197 Str << llvm::format_hex_no_prefix( | 219 Str << llvm::format_hex_no_prefix( |
| 198 *(Offset + (const unsigned char *)&Value), HexWidthChars); | 220 *(Offset + (const unsigned char *)&Value), HexWidthChars); |
| 199 } | 221 } |
| 200 // For a floating-point value in DecorateAsm mode, also append the value in | 222 // For a floating-point value in DecorateAsm mode, also append the value in |
| 201 // human-readable sprintf form, changing '+' to 'p' and '-' to 'm' to | 223 // human-readable sprintf form, changing '+' to 'p' and '-' to 'm' to |
| 202 // maintain valid asm labels. | 224 // maintain valid asm labels. |
| 203 if (std::is_floating_point<PrimType>::value && !BuildDefs::minimal() && | 225 if (std::is_floating_point<PrimType>::value && !BuildDefs::minimal() && |
| 204 GlobalContext::getFlags().getDecorateAsm()) { | 226 GlobalContext::getFlags().getDecorateAsm()) { |
| 205 char Buf[30]; | 227 char Buf[30]; |
| 206 snprintf(Buf, llvm::array_lengthof(Buf), "$%g", (double)Value); | 228 snprintf(Buf, llvm::array_lengthof(Buf), "$%g", (double)Value); |
| 207 for (unsigned i = 0; i < llvm::array_lengthof(Buf) && Buf[i]; ++i) { | 229 for (unsigned i = 0; i < llvm::array_lengthof(Buf) && Buf[i]; ++i) { |
| 208 if (Buf[i] == '-') | 230 if (Buf[i] == '-') |
| 209 Buf[i] = 'm'; | 231 Buf[i] = 'm'; |
| 210 else if (Buf[i] == '+') | 232 else if (Buf[i] == '+') |
| 211 Buf[i] = 'p'; | 233 Buf[i] = 'p'; |
| 212 } | 234 } |
| 213 Str << Buf; | 235 Str << Buf; |
| 214 } | 236 } |
| 215 } | 237 LabelName = GlobalString(Ctx, Str.str()); |
| 216 using Constant::emit; | |
| 217 void emit(TargetLowering *Target) const final; | |
| 218 using Constant::dump; | |
| 219 void dump(const Cfg *, Ostream &Str) const override { | |
| 220 if (BuildDefs::dump()) | |
| 221 Str << getValue(); | |
| 222 } | 238 } |
| 223 | 239 |
| 224 static bool classof(const Operand *Operand) { | |
| 225 return Operand->getKind() == K; | |
| 226 } | |
| 227 | |
| 228 virtual bool shouldBeRandomizedOrPooled(const GlobalContext *Ctx) override { | |
| 229 (void)Ctx; | |
| 230 return false; | |
| 231 } | |
| 232 | |
| 233 private: | |
| 234 ConstantPrimitive(Type Ty, PrimType Value) : Constant(K, Ty), Value(Value) {} | |
| 235 const PrimType Value; | 240 const PrimType Value; |
| 236 }; | 241 }; |
| 237 | 242 |
| 238 using ConstantInteger32 = ConstantPrimitive<int32_t, Operand::kConstInteger32>; | 243 using ConstantInteger32 = ConstantPrimitive<int32_t, Operand::kConstInteger32>; |
| 239 using ConstantInteger64 = ConstantPrimitive<int64_t, Operand::kConstInteger64>; | 244 using ConstantInteger64 = ConstantPrimitive<int64_t, Operand::kConstInteger64>; |
| 240 using ConstantFloat = ConstantPrimitive<float, Operand::kConstFloat>; | 245 using ConstantFloat = ConstantPrimitive<float, Operand::kConstFloat>; |
| 241 using ConstantDouble = ConstantPrimitive<double, Operand::kConstDouble>; | 246 using ConstantDouble = ConstantPrimitive<double, Operand::kConstDouble>; |
| 242 | 247 |
| 243 template <> | 248 template <> |
| 244 inline void ConstantInteger32::dump(const Cfg *, Ostream &Str) const { | 249 inline void ConstantInteger32::dump(const Cfg *, Ostream &Str) const { |
| 245 if (!BuildDefs::dump()) | 250 if (!BuildDefs::dump()) |
| 246 return; | 251 return; |
| 247 if (getType() == IceType_i1) | 252 if (getType() == IceType_i1) |
| 248 Str << (getValue() ? "true" : "false"); | 253 Str << (getValue() ? "true" : "false"); |
| 249 else | 254 else |
| 250 Str << static_cast<int32_t>(getValue()); | 255 Str << static_cast<int32_t>(getValue()); |
| 251 } | 256 } |
| 252 | 257 |
| 253 /// Specialization of the template member function for ConstantInteger32 | 258 /// Specialization of the template member function for ConstantInteger32 |
| 254 template <> | 259 template <> bool ConstantInteger32::shouldBeRandomizedOrPooled() const; |
| 255 bool ConstantInteger32::shouldBeRandomizedOrPooled(const GlobalContext *Ctx); | |
| 256 | 260 |
| 257 template <> | 261 template <> |
| 258 inline void ConstantInteger64::dump(const Cfg *, Ostream &Str) const { | 262 inline void ConstantInteger64::dump(const Cfg *, Ostream &Str) const { |
| 259 if (!BuildDefs::dump()) | 263 if (!BuildDefs::dump()) |
| 260 return; | 264 return; |
| 261 assert(getType() == IceType_i64); | 265 assert(getType() == IceType_i64); |
| 262 Str << static_cast<int64_t>(getValue()); | 266 Str << static_cast<int64_t>(getValue()); |
| 263 } | 267 } |
| 264 | 268 |
| 265 /// RelocOffset allows symbolic references in ConstantRelocatables' offsets, | 269 /// RelocOffset allows symbolic references in ConstantRelocatables' offsets, |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 308 | 312 |
| 309 /// RelocatableTuple bundles the parameters that are used to construct an | 313 /// RelocatableTuple bundles the parameters that are used to construct an |
| 310 /// ConstantRelocatable. It is done this way so that ConstantRelocatable can fit | 314 /// ConstantRelocatable. It is done this way so that ConstantRelocatable can fit |
| 311 /// into the global constant pool template mechanism. | 315 /// into the global constant pool template mechanism. |
| 312 class RelocatableTuple { | 316 class RelocatableTuple { |
| 313 RelocatableTuple() = delete; | 317 RelocatableTuple() = delete; |
| 314 RelocatableTuple &operator=(const RelocatableTuple &) = delete; | 318 RelocatableTuple &operator=(const RelocatableTuple &) = delete; |
| 315 | 319 |
| 316 public: | 320 public: |
| 317 RelocatableTuple(const RelocOffsetT Offset, | 321 RelocatableTuple(const RelocOffsetT Offset, |
| 318 const RelocOffsetArray &OffsetExpr, const IceString &Name) | 322 const RelocOffsetArray &OffsetExpr, GlobalString Name) |
| 319 : Offset(Offset), OffsetExpr(OffsetExpr), Name(Name) {} | 323 : Offset(Offset), OffsetExpr(OffsetExpr), Name(Name) {} |
| 320 | 324 |
| 321 RelocatableTuple(const RelocOffsetT Offset, | 325 RelocatableTuple(const RelocOffsetT Offset, |
| 322 const RelocOffsetArray &OffsetExpr, const IceString &Name, | 326 const RelocOffsetArray &OffsetExpr, GlobalString Name, |
| 323 const IceString &EmitString) | 327 const std::string &EmitString) |
| 324 : Offset(Offset), OffsetExpr(OffsetExpr), Name(Name), | 328 : Offset(Offset), OffsetExpr(OffsetExpr), Name(Name), |
| 325 EmitString(EmitString) {} | 329 EmitString(EmitString) {} |
| 326 | 330 |
| 327 RelocatableTuple(const RelocatableTuple &) = default; | 331 RelocatableTuple(const RelocatableTuple &) = default; |
| 328 | 332 |
| 329 const RelocOffsetT Offset; | 333 const RelocOffsetT Offset; |
| 330 const RelocOffsetArray OffsetExpr; | 334 const RelocOffsetArray OffsetExpr; |
| 331 const IceString Name; | 335 const GlobalString Name; |
| 332 const IceString EmitString; | 336 const std::string EmitString; |
| 333 }; | 337 }; |
| 334 | 338 |
| 335 bool operator==(const RelocatableTuple &A, const RelocatableTuple &B); | 339 bool operator==(const RelocatableTuple &A, const RelocatableTuple &B); |
| 336 | 340 |
| 337 /// ConstantRelocatable represents a symbolic constant combined with a fixed | 341 /// ConstantRelocatable represents a symbolic constant combined with a fixed |
| 338 /// offset. | 342 /// offset. |
| 339 class ConstantRelocatable : public Constant { | 343 class ConstantRelocatable : public Constant { |
| 340 ConstantRelocatable() = delete; | 344 ConstantRelocatable() = delete; |
| 341 ConstantRelocatable(const ConstantRelocatable &) = delete; | 345 ConstantRelocatable(const ConstantRelocatable &) = delete; |
| 342 ConstantRelocatable &operator=(const ConstantRelocatable &) = delete; | 346 ConstantRelocatable &operator=(const ConstantRelocatable &) = delete; |
| 343 | 347 |
| 344 public: | 348 public: |
| 345 template <typename T> | 349 template <typename T> |
| 346 static ConstantRelocatable *create(T *AllocOwner, Type Ty, | 350 static ConstantRelocatable *create(T *AllocOwner, GlobalContext *Ctx, Type Ty, |
| 347 const RelocatableTuple &Tuple) { | 351 const RelocatableTuple &Tuple) { |
| 348 return new (AllocOwner->template allocate<ConstantRelocatable>()) | 352 return new (AllocOwner->template allocate<ConstantRelocatable>()) |
| 349 ConstantRelocatable(Ty, Tuple.Offset, Tuple.OffsetExpr, Tuple.Name, | 353 ConstantRelocatable(Ctx, Ty, Tuple.Offset, Tuple.OffsetExpr, Tuple.Name, |
| 350 Tuple.EmitString); | 354 Tuple.EmitString); |
| 351 } | 355 } |
| 356 static ConstantRelocatable *create(GlobalContext *Ctx, Type Ty, |
| 357 const RelocatableTuple &Tuple) { |
| 358 return create(Ctx, Ctx, Ty, Tuple); |
| 359 } |
| 352 | 360 |
| 353 RelocOffsetT getOffset() const { | 361 RelocOffsetT getOffset() const { |
| 354 RelocOffsetT Ret = Offset; | 362 RelocOffsetT Ret = Offset; |
| 355 for (const auto *const OffsetReloc : OffsetExpr) { | 363 for (const auto *const OffsetReloc : OffsetExpr) { |
| 356 Ret += OffsetReloc->getOffset(); | 364 Ret += OffsetReloc->getOffset(); |
| 357 } | 365 } |
| 358 return Ret; | 366 return Ret; |
| 359 } | 367 } |
| 360 | 368 |
| 361 const IceString &getEmitString() const { return EmitString; } | 369 const std::string &getEmitString() const { return EmitString; } |
| 362 | 370 |
| 363 const IceString &getName() const { return Name; } | 371 GlobalString getName() const { return Name; } |
| 364 using Constant::emit; | 372 using Constant::emit; |
| 365 void emit(TargetLowering *Target) const final; | 373 void emit(TargetLowering *Target) const final; |
| 366 void emitWithoutPrefix(const TargetLowering *Target, | 374 void emitWithoutPrefix(const TargetLowering *Target, |
| 367 const char *Suffix = "") const; | 375 const char *Suffix = "") const; |
| 368 using Constant::dump; | 376 using Constant::dump; |
| 369 void dump(const Cfg *Func, Ostream &Str) const override; | 377 void dump(const Cfg *Func, Ostream &Str) const override; |
| 370 | 378 |
| 371 static bool classof(const Operand *Operand) { | 379 static bool classof(const Operand *Operand) { |
| 372 OperandKind Kind = Operand->getKind(); | 380 OperandKind Kind = Operand->getKind(); |
| 373 return Kind == kConstRelocatable; | 381 return Kind == kConstRelocatable; |
| 374 } | 382 } |
| 375 | 383 |
| 376 private: | 384 private: |
| 377 ConstantRelocatable(Type Ty, const RelocOffsetT Offset, | 385 ConstantRelocatable(GlobalContext *Ctx, Type Ty, const RelocOffsetT Offset, |
| 378 const RelocOffsetArray &OffsetExpr, const IceString &Name, | 386 const RelocOffsetArray &OffsetExpr, GlobalString Name, |
| 379 const IceString &EmitString) | 387 const std::string &EmitString) |
| 380 : Constant(kConstRelocatable, Ty), Offset(Offset), OffsetExpr(OffsetExpr), | 388 : Constant(Ctx, kConstRelocatable, Ty), Offset(Offset), |
| 381 Name(Name), EmitString(EmitString) {} | 389 OffsetExpr(OffsetExpr), Name(Name), EmitString(EmitString) {} |
| 382 | 390 |
| 383 const RelocOffsetT Offset; /// fixed, known offset to add | 391 const RelocOffsetT Offset; /// fixed, known offset to add |
| 384 const RelocOffsetArray OffsetExpr; /// fixed, unknown offset to add | 392 const RelocOffsetArray OffsetExpr; /// fixed, unknown offset to add |
| 385 const IceString Name; /// optional for debug/dump | 393 const GlobalString Name; /// optional for debug/dump |
| 386 const IceString EmitString; /// optional for textual emission | 394 const std::string EmitString; /// optional for textual emission |
| 387 }; | 395 }; |
| 388 | 396 |
| 389 /// ConstantUndef represents an unspecified bit pattern. Although it is legal to | 397 /// ConstantUndef represents an unspecified bit pattern. Although it is legal to |
| 390 /// lower ConstantUndef to any value, backends should try to make code | 398 /// lower ConstantUndef to any value, backends should try to make code |
| 391 /// generation deterministic by lowering ConstantUndefs to 0. | 399 /// generation deterministic by lowering ConstantUndefs to 0. |
| 392 class ConstantUndef : public Constant { | 400 class ConstantUndef : public Constant { |
| 393 ConstantUndef() = delete; | 401 ConstantUndef() = delete; |
| 394 ConstantUndef(const ConstantUndef &) = delete; | 402 ConstantUndef(const ConstantUndef &) = delete; |
| 395 ConstantUndef &operator=(const ConstantUndef &) = delete; | 403 ConstantUndef &operator=(const ConstantUndef &) = delete; |
| 396 | 404 |
| 397 public: | 405 public: |
| 398 static ConstantUndef *create(GlobalContext *Ctx, Type Ty) { | 406 static ConstantUndef *create(GlobalContext *Ctx, Type Ty) { |
| 399 return new (Ctx->allocate<ConstantUndef>()) ConstantUndef(Ty); | 407 return new (Ctx->allocate<ConstantUndef>()) ConstantUndef(Ctx, Ty); |
| 400 } | 408 } |
| 401 | 409 |
| 402 using Constant::emit; | 410 using Constant::emit; |
| 403 void emit(TargetLowering *Target) const final; | 411 void emit(TargetLowering *Target) const final; |
| 404 using Constant::dump; | 412 using Constant::dump; |
| 405 void dump(const Cfg *, Ostream &Str) const override { | 413 void dump(const Cfg *, Ostream &Str) const override { |
| 406 if (BuildDefs::dump()) | 414 if (BuildDefs::dump()) |
| 407 Str << "undef"; | 415 Str << "undef"; |
| 408 } | 416 } |
| 409 | 417 |
| 410 static bool classof(const Operand *Operand) { | 418 static bool classof(const Operand *Operand) { |
| 411 return Operand->getKind() == kConstUndef; | 419 return Operand->getKind() == kConstUndef; |
| 412 } | 420 } |
| 413 | 421 |
| 414 private: | 422 private: |
| 415 ConstantUndef(Type Ty) : Constant(kConstUndef, Ty) {} | 423 ConstantUndef(GlobalContext *Ctx, Type Ty) : Constant(Ctx, kConstUndef, Ty) {} |
| 416 }; | 424 }; |
| 417 | 425 |
| 418 /// RegNumT is for holding target-specific register numbers, plus the sentinel | 426 /// RegNumT is for holding target-specific register numbers, plus the sentinel |
| 419 /// value if no register is assigned. Its public ctor allows direct use of enum | 427 /// value if no register is assigned. Its public ctor allows direct use of enum |
| 420 /// values, such as RegNumT(Reg_eax), but not things like RegNumT(Reg_eax+1). | 428 /// values, such as RegNumT(Reg_eax), but not things like RegNumT(Reg_eax+1). |
| 421 /// This is to try to prevent inappropriate assumptions about enum ordering. If | 429 /// This is to try to prevent inappropriate assumptions about enum ordering. If |
| 422 /// needed, the fromInt() method can be used, such as when a RegNumT is based | 430 /// needed, the fromInt() method can be used, such as when a RegNumT is based |
| 423 /// on a bitvector index. | 431 /// on a bitvector index. |
| 424 class RegNumT { | 432 class RegNumT { |
| 425 public: | 433 public: |
| (...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 630 Variable &operator=(const Variable &) = delete; | 638 Variable &operator=(const Variable &) = delete; |
| 631 | 639 |
| 632 enum RegRequirement : uint8_t { | 640 enum RegRequirement : uint8_t { |
| 633 RR_MayHaveRegister, | 641 RR_MayHaveRegister, |
| 634 RR_MustHaveRegister, | 642 RR_MustHaveRegister, |
| 635 RR_MustNotHaveRegister, | 643 RR_MustNotHaveRegister, |
| 636 }; | 644 }; |
| 637 | 645 |
| 638 public: | 646 public: |
| 639 static Variable *create(Cfg *Func, Type Ty, SizeT Index) { | 647 static Variable *create(Cfg *Func, Type Ty, SizeT Index) { |
| 640 return new (Func->allocate<Variable>()) Variable(kVariable, Ty, Index); | 648 return new (Func->allocate<Variable>()) |
| 649 Variable(Func, kVariable, Ty, Index); |
| 641 } | 650 } |
| 642 | 651 |
| 643 SizeT getIndex() const { return Number; } | 652 SizeT getIndex() const { return Number; } |
| 644 IceString getName(const Cfg *Func) const; | 653 std::string getName(const Cfg *Func) const; |
| 645 virtual void setName(Cfg *Func, const IceString &NewName) { | 654 virtual void setName(const Cfg *Func, const std::string &NewName) { |
| 646 // Make sure that the name can only be set once. | 655 (void)Func; |
| 647 assert(NameIndex == Cfg::IdentifierIndexInvalid); | 656 if (NewName.empty()) |
| 648 if (!NewName.empty()) | 657 return; |
| 649 NameIndex = Func->addIdentifierName(NewName); | 658 Name = VariableString(Func, NewName); |
| 650 } | 659 } |
| 651 | 660 |
| 652 bool getIsArg() const { return IsArgument; } | 661 bool getIsArg() const { return IsArgument; } |
| 653 virtual void setIsArg(bool Val = true) { IsArgument = Val; } | 662 virtual void setIsArg(bool Val = true) { IsArgument = Val; } |
| 654 bool getIsImplicitArg() const { return IsImplicitArgument; } | 663 bool getIsImplicitArg() const { return IsImplicitArgument; } |
| 655 void setIsImplicitArg(bool Val = true) { IsImplicitArgument = Val; } | 664 void setIsImplicitArg(bool Val = true) { IsImplicitArgument = Val; } |
| 656 | 665 |
| 657 void setIgnoreLiveness() { IgnoreLiveness = true; } | 666 void setIgnoreLiveness() { IgnoreLiveness = true; } |
| 658 bool getIgnoreLiveness() const { return IgnoreLiveness; } | 667 bool getIgnoreLiveness() const { return IgnoreLiveness; } |
| 659 | 668 |
| 660 int32_t getStackOffset() const { return StackOffset; } | 669 int32_t getStackOffset() const { return StackOffset; } |
| 661 void setStackOffset(int32_t Offset) { StackOffset = Offset; } | 670 void setStackOffset(int32_t Offset) { StackOffset = Offset; } |
| 662 /// Returns the variable's stack offset in symbolic form, to improve | 671 /// Returns the variable's stack offset in symbolic form, to improve |
| 663 /// readability in DecorateAsm mode. | 672 /// readability in DecorateAsm mode. |
| 664 IceString getSymbolicStackOffset(const Cfg *Func) const { | 673 std::string getSymbolicStackOffset(const Cfg *Func) const { |
| 665 if (!BuildDefs::dump()) | 674 if (!BuildDefs::dump()) |
| 666 return ""; | 675 return ""; |
| 667 return "lv$" + getName(Func); | 676 return "lv$" + getName(Func); |
| 668 } | 677 } |
| 669 | 678 |
| 670 bool hasReg() const { return getRegNum().hasValue(); } | 679 bool hasReg() const { return getRegNum().hasValue(); } |
| 671 RegNumT getRegNum() const { return RegNum; } | 680 RegNumT getRegNum() const { return RegNum; } |
| 672 void setRegNum(RegNumT NewRegNum) { | 681 void setRegNum(RegNumT NewRegNum) { |
| 673 // Regnum shouldn't be set more than once. | 682 // Regnum shouldn't be set more than once. |
| 674 assert(!hasReg() || RegNum == NewRegNum); | 683 assert(!hasReg() || RegNum == NewRegNum); |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 718 constexpr bool UseTrimmed = true; | 727 constexpr bool UseTrimmed = true; |
| 719 return Live.overlapsInst(Other->Live.getStart(), UseTrimmed); | 728 return Live.overlapsInst(Other->Live.getStart(), UseTrimmed); |
| 720 } | 729 } |
| 721 | 730 |
| 722 /// Creates a temporary copy of the variable with a different type. Used | 731 /// Creates a temporary copy of the variable with a different type. Used |
| 723 /// primarily for syntactic correctness of textual assembly emission. Note | 732 /// primarily for syntactic correctness of textual assembly emission. Note |
| 724 /// that only basic information is copied, in particular not IsArgument, | 733 /// that only basic information is copied, in particular not IsArgument, |
| 725 /// IsImplicitArgument, IgnoreLiveness, RegNumTmp, Live, LoVar, HiVar, | 734 /// IsImplicitArgument, IgnoreLiveness, RegNumTmp, Live, LoVar, HiVar, |
| 726 /// VarsReal. If NewRegNum.hasValue(), then that register assignment is made | 735 /// VarsReal. If NewRegNum.hasValue(), then that register assignment is made |
| 727 /// instead of copying the existing assignment. | 736 /// instead of copying the existing assignment. |
| 728 const Variable *asType(Type Ty, RegNumT NewRegNum) const; | 737 const Variable *asType(const Cfg *Func, Type Ty, RegNumT NewRegNum) const; |
| 729 | 738 |
| 730 void emit(const Cfg *Func) const override; | 739 void emit(const Cfg *Func) const override; |
| 731 using Operand::dump; | 740 using Operand::dump; |
| 732 void dump(const Cfg *Func, Ostream &Str) const override; | 741 void dump(const Cfg *Func, Ostream &Str) const override; |
| 733 | 742 |
| 734 /// Return reg num of base register, if different from stack/frame register. | 743 /// Return reg num of base register, if different from stack/frame register. |
| 735 virtual RegNumT getBaseRegNum() const { return RegNumT(); } | 744 virtual RegNumT getBaseRegNum() const { return RegNumT(); } |
| 736 | 745 |
| 737 static bool classof(const Operand *Operand) { | 746 static bool classof(const Operand *Operand) { |
| 738 OperandKind Kind = Operand->getKind(); | 747 OperandKind Kind = Operand->getKind(); |
| 739 return Kind >= kVariable && Kind <= kVariable_Max; | 748 return Kind >= kVariable && Kind <= kVariable_Max; |
| 740 } | 749 } |
| 741 | 750 |
| 742 protected: | 751 protected: |
| 743 Variable(OperandKind K, Type Ty, SizeT Index) | 752 Variable(const Cfg *Func, OperandKind K, Type Ty, SizeT Index) |
| 744 : Operand(K, Ty), Number(Index), | 753 : Operand(K, Ty), Number(Index), Name(Func), |
| 745 RegisterClass(static_cast<RegClass>(Ty)) { | 754 RegisterClass(static_cast<RegClass>(Ty)) { |
| 746 Vars = VarsReal; | 755 Vars = VarsReal; |
| 747 Vars[0] = this; | 756 Vars[0] = this; |
| 748 NumVars = 1; | 757 NumVars = 1; |
| 758 if (BuildDefs::dump()) { |
| 759 Name = VariableString(Func, "__" + std::to_string(getIndex())); |
| 760 } else { |
| 761 Name = VariableString(Func); |
| 762 } |
| 749 } | 763 } |
| 750 /// Number is unique across all variables, and is used as a (bit)vector index | 764 /// Number is unique across all variables, and is used as a (bit)vector index |
| 751 /// for liveness analysis. | 765 /// for liveness analysis. |
| 752 const SizeT Number; | 766 const SizeT Number; |
| 753 Cfg::IdentifierIndexType NameIndex = Cfg::IdentifierIndexInvalid; | 767 VariableString Name; |
| 754 bool IsArgument = false; | 768 bool IsArgument = false; |
| 755 bool IsImplicitArgument = false; | 769 bool IsImplicitArgument = false; |
| 756 /// IgnoreLiveness means that the variable should be ignored when constructing | 770 /// IgnoreLiveness means that the variable should be ignored when constructing |
| 757 /// and validating live ranges. This is usually reserved for the stack | 771 /// and validating live ranges. This is usually reserved for the stack |
| 758 /// pointer and other physical registers specifically referenced by name. | 772 /// pointer and other physical registers specifically referenced by name. |
| 759 bool IgnoreLiveness = false; | 773 bool IgnoreLiveness = false; |
| 760 // If IsRematerializable, RegNum keeps track of which register (stack or frame | 774 // If IsRematerializable, RegNum keeps track of which register (stack or frame |
| 761 // pointer), and StackOffset is the known offset from that register. | 775 // pointer), and StackOffset is the known offset from that register. |
| 762 bool IsRematerializable = false; | 776 bool IsRematerializable = false; |
| 763 RegRequirement RegRequirement = RR_MayHaveRegister; | 777 RegRequirement RegRequirement = RR_MayHaveRegister; |
| (...skipping 13 matching lines...) Expand all Loading... |
| 777 // Variable64On32 represents a 64-bit variable on a 32-bit architecture. In | 791 // Variable64On32 represents a 64-bit variable on a 32-bit architecture. In |
| 778 // this situation the variable must be split into a low and a high word. | 792 // this situation the variable must be split into a low and a high word. |
| 779 class Variable64On32 : public Variable { | 793 class Variable64On32 : public Variable { |
| 780 Variable64On32() = delete; | 794 Variable64On32() = delete; |
| 781 Variable64On32(const Variable64On32 &) = delete; | 795 Variable64On32(const Variable64On32 &) = delete; |
| 782 Variable64On32 &operator=(const Variable64On32 &) = delete; | 796 Variable64On32 &operator=(const Variable64On32 &) = delete; |
| 783 | 797 |
| 784 public: | 798 public: |
| 785 static Variable64On32 *create(Cfg *Func, Type Ty, SizeT Index) { | 799 static Variable64On32 *create(Cfg *Func, Type Ty, SizeT Index) { |
| 786 return new (Func->allocate<Variable64On32>()) | 800 return new (Func->allocate<Variable64On32>()) |
| 787 Variable64On32(kVariable64On32, Ty, Index); | 801 Variable64On32(Func, kVariable64On32, Ty, Index); |
| 788 } | 802 } |
| 789 | 803 |
| 790 void setName(Cfg *Func, const IceString &NewName) override { | 804 void setName(const Cfg *Func, const std::string &NewName) override { |
| 791 Variable::setName(Func, NewName); | 805 Variable::setName(Func, NewName); |
| 792 if (LoVar && HiVar) { | 806 if (LoVar && HiVar) { |
| 793 LoVar->setName(Func, getName(Func) + "__lo"); | 807 LoVar->setName(Func, getName(Func) + "__lo"); |
| 794 HiVar->setName(Func, getName(Func) + "__hi"); | 808 HiVar->setName(Func, getName(Func) + "__hi"); |
| 795 } | 809 } |
| 796 } | 810 } |
| 797 | 811 |
| 798 void setIsArg(bool Val = true) override { | 812 void setIsArg(bool Val = true) override { |
| 799 Variable::setIsArg(Val); | 813 Variable::setIsArg(Val); |
| 800 if (LoVar && HiVar) { | 814 if (LoVar && HiVar) { |
| (...skipping 11 matching lines...) Expand all Loading... |
| 812 return HiVar; | 826 return HiVar; |
| 813 } | 827 } |
| 814 | 828 |
| 815 void initHiLo(Cfg *Func) { | 829 void initHiLo(Cfg *Func) { |
| 816 assert(LoVar == nullptr); | 830 assert(LoVar == nullptr); |
| 817 assert(HiVar == nullptr); | 831 assert(HiVar == nullptr); |
| 818 LoVar = Func->makeVariable(IceType_i32); | 832 LoVar = Func->makeVariable(IceType_i32); |
| 819 HiVar = Func->makeVariable(IceType_i32); | 833 HiVar = Func->makeVariable(IceType_i32); |
| 820 LoVar->setIsArg(getIsArg()); | 834 LoVar->setIsArg(getIsArg()); |
| 821 HiVar->setIsArg(getIsArg()); | 835 HiVar->setIsArg(getIsArg()); |
| 822 LoVar->setName(Func, getName(Func) + "__lo"); | 836 if (BuildDefs::dump()) { |
| 823 HiVar->setName(Func, getName(Func) + "__hi"); | 837 LoVar->setName(Func, getName(Func) + "__lo"); |
| 838 HiVar->setName(Func, getName(Func) + "__hi"); |
| 839 } |
| 824 } | 840 } |
| 825 | 841 |
| 826 static bool classof(const Operand *Operand) { | 842 static bool classof(const Operand *Operand) { |
| 827 OperandKind Kind = Operand->getKind(); | 843 OperandKind Kind = Operand->getKind(); |
| 828 return Kind == kVariable64On32; | 844 return Kind == kVariable64On32; |
| 829 } | 845 } |
| 830 | 846 |
| 831 protected: | 847 protected: |
| 832 Variable64On32(OperandKind K, Type Ty, SizeT Index) : Variable(K, Ty, Index) { | 848 Variable64On32(const Cfg *Func, OperandKind K, Type Ty, SizeT Index) |
| 849 : Variable(Func, K, Ty, Index) { |
| 833 assert(typeWidthInBytes(Ty) == 8); | 850 assert(typeWidthInBytes(Ty) == 8); |
| 834 } | 851 } |
| 835 | 852 |
| 836 Variable *LoVar = nullptr; | 853 Variable *LoVar = nullptr; |
| 837 Variable *HiVar = nullptr; | 854 Variable *HiVar = nullptr; |
| 838 }; | 855 }; |
| 839 | 856 |
| 840 enum MetadataKind { | 857 enum MetadataKind { |
| 841 VMK_Uses, /// Track only uses, not defs | 858 VMK_Uses, /// Track only uses, not defs |
| 842 VMK_SingleDefs, /// Track uses+defs, but only record single def | 859 VMK_SingleDefs, /// Track uses+defs, but only record single def |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 943 private: | 960 private: |
| 944 const Cfg *Func; | 961 const Cfg *Func; |
| 945 MetadataKind Kind; | 962 MetadataKind Kind; |
| 946 CfgVector<VariableTracking> Metadata; | 963 CfgVector<VariableTracking> Metadata; |
| 947 const static InstDefList NoDefinitions; | 964 const static InstDefList NoDefinitions; |
| 948 }; | 965 }; |
| 949 | 966 |
| 950 } // end of namespace Ice | 967 } // end of namespace Ice |
| 951 | 968 |
| 952 #endif // SUBZERO_SRC_ICEOPERAND_H | 969 #endif // SUBZERO_SRC_ICEOPERAND_H |
| OLD | NEW |