[IR] De-virtualize ~Value to save a vptr

Summary:
Implements PR889

Removing the virtual table pointer from Value saves 1% of RSS when doing
LTO of llc on Linux. The impact on time was positive, but too noisy to
conclusively say that performance improved. Here is a link to the
spreadsheet with the original data:

https://docs.google.com/spreadsheets/d/1F4FHir0qYnV0MEp2sYYp_BuvnJgWlWPhWOwZ6LbW7W4/edit?usp=sharing

This change makes it invalid to directly delete a Value, User, or
Instruction pointer. Instead, such code can be rewritten to a null check
and a call Value::deleteValue(). Value objects tend to have their
lifetimes managed through iplist, so for the most part, this isn't a big
deal.  However, there are some places where LLVM deletes values, and
those places had to be migrated to deleteValue.  I have also created
llvm::unique_value, which has a custom deleter, so it can be used in
place of std::unique_ptr<Value>.

I had to add the "DerivedUser" Deleter escape hatch for MemorySSA, which
derives from User outside of lib/IR. Code in IR cannot include MemorySSA
headers or call the MemoryAccess object destructors without introducing
a circular dependency, so we need some level of indirection.
Unfortunately, no class derived from User may have any virtual methods,
because adding a virtual method would break User::getHungOffOperands(),
which assumes that it can find the use list immediately prior to the
User object. I've added a static_assert to the appropriate OperandTraits
templates to help people avoid this trap.

Reviewers: chandlerc, mehdi_amini, pete, dberlin, george.burgess.iv

Reviewed By: chandlerc

Subscribers: krytarowski, eraman, george.burgess.iv, mzolotukhin, Prazek, nlewycky, hans, inglorion, pcc, tejohnson, dberlin, llvm-commits

Differential Revision: https://reviews.llvm.org/D31261

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@303362 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Reid Kleckner 2017-05-18 17:24:10 +00:00
parent 7db2df6d96
commit 816047d44c
48 changed files with 282 additions and 237 deletions

View File

@ -84,6 +84,7 @@
#include "llvm/Analysis/MemoryLocation.h"
#include "llvm/Analysis/PHITransAddr.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/DerivedUser.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/OperandTraits.h"
@ -127,7 +128,7 @@ using const_memoryaccess_def_iterator =
// \brief The base for all memory accesses. All memory accesses in a block are
// linked together using an intrusive list.
class MemoryAccess
: public User,
: public DerivedUser,
public ilist_node<MemoryAccess, ilist_tag<MSSAHelpers::AllAccessTag>>,
public ilist_node<MemoryAccess, ilist_tag<MSSAHelpers::DefsOnlyTag>> {
public:
@ -145,15 +146,14 @@ public:
MemoryAccess(const MemoryAccess &) = delete;
MemoryAccess &operator=(const MemoryAccess &) = delete;
~MemoryAccess() override;
void *operator new(size_t, unsigned) = delete;
void *operator new(size_t) = delete;
BasicBlock *getBlock() const { return Block; }
virtual void print(raw_ostream &OS) const = 0;
virtual void dump() const;
void print(raw_ostream &OS) const;
void dump() const;
/// \brief The user iterators for a memory access
typedef user_iterator iterator;
@ -207,11 +207,12 @@ protected:
/// \brief Used for debugging and tracking things about MemoryAccesses.
/// Guaranteed unique among MemoryAccesses, no guarantees otherwise.
virtual unsigned getID() const = 0;
inline unsigned getID() const;
MemoryAccess(LLVMContext &C, unsigned Vty, BasicBlock *BB,
unsigned NumOperands)
: User(Type::getVoidTy(C), Vty, nullptr, NumOperands), Block(BB) {}
MemoryAccess(LLVMContext &C, unsigned Vty, DeleteValueTy DeleteValue,
BasicBlock *BB, unsigned NumOperands)
: DerivedUser(Type::getVoidTy(C), Vty, nullptr, NumOperands, DeleteValue),
Block(BB) {}
private:
BasicBlock *Block;
@ -248,21 +249,21 @@ public:
// Sadly, these have to be public because they are needed in some of the
// iterators.
virtual bool isOptimized() const = 0;
virtual MemoryAccess *getOptimized() const = 0;
virtual void setOptimized(MemoryAccess *) = 0;
inline bool isOptimized() const;
inline MemoryAccess *getOptimized() const;
inline void setOptimized(MemoryAccess *);
/// \brief Reset the ID of what this MemoryUse was optimized to, causing it to
/// be rewalked by the walker if necessary.
/// This really should only be called by tests.
virtual void resetOptimized() = 0;
inline void resetOptimized();
protected:
friend class MemorySSA;
friend class MemorySSAUpdater;
MemoryUseOrDef(LLVMContext &C, MemoryAccess *DMA, unsigned Vty,
Instruction *MI, BasicBlock *BB)
: MemoryAccess(C, Vty, BB, 1), MemoryInst(MI) {
DeleteValueTy DeleteValue, Instruction *MI, BasicBlock *BB)
: MemoryAccess(C, Vty, DeleteValue, BB, 1), MemoryInst(MI) {
setDefiningAccess(DMA);
}
void setDefiningAccess(MemoryAccess *DMA, bool Optimized = false) {
@ -292,7 +293,8 @@ public:
DECLARE_TRANSPARENT_OPERAND_ACCESSORS(MemoryAccess);
MemoryUse(LLVMContext &C, MemoryAccess *DMA, Instruction *MI, BasicBlock *BB)
: MemoryUseOrDef(C, DMA, MemoryUseVal, MI, BB), OptimizedID(0) {}
: MemoryUseOrDef(C, DMA, MemoryUseVal, deleteMe, MI, BB),
OptimizedID(0) {}
// allocate space for exactly one operand
void *operator new(size_t s) { return User::operator new(s, 1); }
@ -302,32 +304,30 @@ public:
return MA->getValueID() == MemoryUseVal;
}
void print(raw_ostream &OS) const override;
void print(raw_ostream &OS) const;
virtual void setOptimized(MemoryAccess *DMA) override {
void setOptimized(MemoryAccess *DMA) {
OptimizedID = DMA->getID();
setOperand(0, DMA);
}
virtual bool isOptimized() const override {
bool isOptimized() const {
return getDefiningAccess() && OptimizedID == getDefiningAccess()->getID();
}
virtual MemoryAccess *getOptimized() const override {
MemoryAccess *getOptimized() const {
return getDefiningAccess();
}
virtual void resetOptimized() override {
void resetOptimized() {
OptimizedID = INVALID_MEMORYACCESS_ID;
}
protected:
friend class MemorySSA;
unsigned getID() const override {
llvm_unreachable("MemoryUses do not have IDs");
}
private:
static void deleteMe(DerivedUser *Self);
unsigned int OptimizedID;
};
@ -350,8 +350,8 @@ public:
MemoryDef(LLVMContext &C, MemoryAccess *DMA, Instruction *MI, BasicBlock *BB,
unsigned Ver)
: MemoryUseOrDef(C, DMA, MemoryDefVal, MI, BB), ID(Ver),
Optimized(nullptr), OptimizedID(INVALID_MEMORYACCESS_ID) {}
: MemoryUseOrDef(C, DMA, MemoryDefVal, deleteMe, MI, BB),
ID(Ver), Optimized(nullptr), OptimizedID(INVALID_MEMORYACCESS_ID) {}
// allocate space for exactly one operand
void *operator new(size_t s) { return User::operator new(s, 1); }
@ -361,27 +361,28 @@ public:
return MA->getValueID() == MemoryDefVal;
}
virtual void setOptimized(MemoryAccess *MA) override {
void setOptimized(MemoryAccess *MA) {
Optimized = MA;
OptimizedID = getDefiningAccess()->getID();
}
virtual MemoryAccess *getOptimized() const override { return Optimized; }
virtual bool isOptimized() const override {
MemoryAccess *getOptimized() const { return Optimized; }
bool isOptimized() const {
return getOptimized() && getDefiningAccess() &&
OptimizedID == getDefiningAccess()->getID();
}
virtual void resetOptimized() override {
void resetOptimized() {
OptimizedID = INVALID_MEMORYACCESS_ID;
}
void print(raw_ostream &OS) const override;
void print(raw_ostream &OS) const;
protected:
friend class MemorySSA;
unsigned getID() const override { return ID; }
unsigned getID() const { return ID; }
private:
static void deleteMe(DerivedUser *Self);
const unsigned ID;
MemoryAccess *Optimized;
unsigned int OptimizedID;
@ -432,7 +433,8 @@ public:
DECLARE_TRANSPARENT_OPERAND_ACCESSORS(MemoryAccess);
MemoryPhi(LLVMContext &C, BasicBlock *BB, unsigned Ver, unsigned NumPreds = 0)
: MemoryAccess(C, MemoryPhiVal, BB, 0), ID(Ver), ReservedSpace(NumPreds) {
: MemoryAccess(C, MemoryPhiVal, deleteMe, BB, 0), ID(Ver),
ReservedSpace(NumPreds) {
allocHungoffUses(ReservedSpace);
}
@ -534,7 +536,9 @@ public:
return V->getValueID() == MemoryPhiVal;
}
void print(raw_ostream &OS) const override;
void print(raw_ostream &OS) const;
unsigned getID() const { return ID; }
protected:
friend class MemorySSA;
@ -546,8 +550,6 @@ protected:
User::allocHungoffUses(N, /* IsPhi */ true);
}
unsigned getID() const final { return ID; }
private:
// For debugging only
const unsigned ID;
@ -561,8 +563,45 @@ private:
ReservedSpace = std::max(E + E / 2, 2u);
growHungoffUses(ReservedSpace, /* IsPhi */ true);
}
static void deleteMe(DerivedUser *Self);
};
inline unsigned MemoryAccess::getID() const {
assert((isa<MemoryDef>(this) || isa<MemoryPhi>(this)) &&
"only memory defs and phis have ids");
if (const auto *MD = dyn_cast<MemoryDef>(this))
return MD->getID();
return cast<MemoryPhi>(this)->getID();
}
inline bool MemoryUseOrDef::isOptimized() const {
if (const auto *MD = dyn_cast<MemoryDef>(this))
return MD->isOptimized();
return cast<MemoryUse>(this)->isOptimized();
}
inline MemoryAccess *MemoryUseOrDef::getOptimized() const {
if (const auto *MD = dyn_cast<MemoryDef>(this))
return MD->getOptimized();
return cast<MemoryUse>(this)->getOptimized();
}
inline void MemoryUseOrDef::setOptimized(MemoryAccess *MA) {
if (auto *MD = dyn_cast<MemoryDef>(this))
MD->setOptimized(MA);
else
cast<MemoryUse>(this)->setOptimized(MA);
}
inline void MemoryUseOrDef::resetOptimized() {
if (auto *MD = dyn_cast<MemoryDef>(this))
MD->resetOptimized();
else
cast<MemoryUse>(this)->resetOptimized();
}
template <> struct OperandTraits<MemoryPhi> : public HungoffOperandTraits<2> {};
DEFINE_TRANSPARENT_OPERAND_ACCESSORS(MemoryPhi, MemoryAccess)

View File

@ -27,8 +27,7 @@ namespace llvm {
/// for a specific function. When used in the body of said function, the
/// argument of course represents the value of the actual argument that the
/// function was called with.
class Argument : public Value {
virtual void anchor();
class Argument final : public Value {
Function *Parent;
unsigned ArgNo;

View File

@ -51,7 +51,7 @@ class ValueSymbolTable;
/// occur because it may be useful in the intermediate stage of constructing or
/// modifying a program. However, the verifier will ensure that basic blocks
/// are "well formed".
class BasicBlock : public Value, // Basic blocks are data objects also
class BasicBlock final : public Value, // Basic blocks are data objects also
public ilist_node_with_parent<BasicBlock, Function> {
public:
using InstListType = SymbolTableList<Instruction>;
@ -77,7 +77,7 @@ private:
public:
BasicBlock(const BasicBlock &) = delete;
BasicBlock &operator=(const BasicBlock &) = delete;
~BasicBlock() override;
~BasicBlock();
/// \brief Get the context in which this basic block lives.
LLVMContext &getContext() const;

View File

@ -40,8 +40,6 @@ class APInt;
/// don't have to worry about the lifetime of the objects.
/// @brief LLVM Constant Representation
class Constant : public User {
void anchor() override;
protected:
Constant(Type *ty, ValueTy vty, Use *Ops, unsigned NumOps)
: User(ty, vty, Ops, NumOps) {}

View File

@ -58,8 +58,6 @@ template <class ConstantClass> struct ConstantAggrKeyType;
class ConstantData : public Constant {
friend class Constant;
void anchor() override;
Value *handleOperandChangeImpl(Value *From, Value *To) {
llvm_unreachable("Constant data does not have operands!");
}
@ -93,7 +91,6 @@ class ConstantInt final : public ConstantData {
ConstantInt(IntegerType *Ty, const APInt& V);
void anchor() override;
void destroyConstantImpl();
public:
@ -274,7 +271,6 @@ class ConstantFP final : public ConstantData {
ConstantFP(Type *Ty, const APFloat& V);
void anchor() override;
void destroyConstantImpl();
public:
@ -588,7 +584,7 @@ class ConstantDataSequential : public ConstantData {
protected:
explicit ConstantDataSequential(Type *ty, ValueTy VT, const char *Data)
: ConstantData(ty, VT), DataElements(Data), Next(nullptr) {}
~ConstantDataSequential() override { delete Next; }
~ConstantDataSequential() { delete Next; }
static Constant *getImpl(StringRef Bytes, Type *Ty);
@ -692,8 +688,6 @@ class ConstantDataArray final : public ConstantDataSequential {
return User::operator new(s, 0);
}
void anchor() override;
public:
ConstantDataArray(const ConstantDataArray &) = delete;
@ -755,8 +749,6 @@ class ConstantDataVector final : public ConstantDataSequential {
return User::operator new(s, 0);
}
void anchor() override;
public:
ConstantDataVector(const ConstantDataVector &) = delete;

View File

@ -0,0 +1,41 @@
//===-- DerivedUser.h - Base for non-IR Users -------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_IR_DERIVEDUSER_H
#define LLVM_IR_DERIVEDUSER_H
#include "llvm/IR/User.h"
namespace llvm {
/// Extension point for the Value hierarchy. All classes outside of lib/IR
/// that wish to inherit from User should instead inherit from DerivedUser
/// instead. Inheriting from this class is discouraged.
///
/// Generally speaking, Value is the base of a closed class hierarchy
/// that can't be extended by code outside of lib/IR. This class creates a
/// loophole that allows classes outside of lib/IR to extend User to leverage
/// its use/def list machinery.
class DerivedUser : public User {
protected:
typedef void (*DeleteValueTy)(DerivedUser *);
private:
friend Value;
DeleteValueTy DeleteValue;
public:
DerivedUser(Type *Ty, unsigned VK, Use *U, unsigned NumOps,
DeleteValueTy DeleteValue)
: User(Ty, VK, U, NumOps), DeleteValue(DeleteValue) {}
};
} // namespace llvm
#endif // LLVM_IR_DERIVEDUSER_H

View File

@ -123,7 +123,7 @@ private:
public:
Function(const Function&) = delete;
void operator=(const Function&) = delete;
~Function() override;
~Function();
static Function *Create(FunctionType *Ty, LinkageTypes Linkage,
const Twine &N = "", Module *M = nullptr) {

View File

@ -161,6 +161,10 @@ protected:
Parent = parent;
}
~GlobalValue() {
removeDeadConstantUsers(); // remove any dead constants using this.
}
public:
enum ThreadLocalMode {
NotThreadLocal = 0,
@ -172,10 +176,6 @@ public:
GlobalValue(const GlobalValue &) = delete;
~GlobalValue() override {
removeDeadConstantUsers(); // remove any dead constants using this.
}
unsigned getAlignment() const;
enum class UnnamedAddr {

View File

@ -66,7 +66,7 @@ public:
GlobalVariable(const GlobalVariable &) = delete;
GlobalVariable &operator=(const GlobalVariable &) = delete;
~GlobalVariable() override {
~GlobalVariable() {
dropAllReferences();
// FIXME: needed by operator delete

View File

@ -28,7 +28,7 @@ class FunctionType;
class PointerType;
template <class ConstantClass> class ConstantUniqueMap;
class InlineAsm : public Value {
class InlineAsm final : public Value {
public:
enum AsmDialect {
AD_ATT,
@ -48,7 +48,6 @@ private:
InlineAsm(FunctionType *Ty, const std::string &AsmString,
const std::string &Constraints, bool hasSideEffects,
bool isAlignStack, AsmDialect asmDialect);
~InlineAsm() override;
/// When the ConstantUniqueMap merges two types and makes two InlineAsms
/// identical, it destroys one of them with this method.

View File

@ -62,9 +62,6 @@ protected:
Use *Ops, unsigned NumOps, BasicBlock *InsertAtEnd)
: Instruction(Ty, iType, Ops, NumOps, InsertAtEnd) {}
// Out of line virtual method, so the vtable, etc has a home.
~TerminatorInst() override;
public:
/// Return the number of successors that this terminator has.
unsigned getNumSuccessors() const;
@ -299,9 +296,6 @@ public:
void *operator new(size_t, unsigned) = delete;
// Out of line virtual method, so the vtable, etc has a home.
~UnaryInstruction() override;
/// Transparently provide more efficient getOperand methods.
DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value);
@ -568,8 +562,6 @@ DEFINE_TRANSPARENT_OPERAND_ACCESSORS(BinaryOperator, Value)
/// if (isa<CastInst>(Instr)) { ... }
/// @brief Base class of casting instructions.
class CastInst : public UnaryInstruction {
void anchor() override;
protected:
/// @brief Constructor with insert-before-instruction semantics for subclasses
CastInst(Type *Ty, unsigned iType, Value *S,
@ -914,8 +906,6 @@ protected:
Value *LHS, Value *RHS, const Twine &Name,
BasicBlock *InsertAtEnd);
void anchor() override; // Out of line virtual method.
public:
CmpInst() = delete;

View File

@ -102,6 +102,10 @@
#define LAST_OTHER_INST(num)
#endif
#ifndef HANDLE_USER_INST
#define HANDLE_USER_INST(num, opc, Class) HANDLE_OTHER_INST(num, opc, Class)
#endif
// Terminator Instructions - These instructions are used to terminate a basic
// block of the program. Every basic block must end with one of these
// instructions for it to be a well formed basic block.
@ -185,8 +189,8 @@ HANDLE_OTHER_INST(52, FCmp , FCmpInst ) // Floating point comparison instr.
HANDLE_OTHER_INST(53, PHI , PHINode ) // PHI node instruction
HANDLE_OTHER_INST(54, Call , CallInst ) // Call a function
HANDLE_OTHER_INST(55, Select , SelectInst ) // select instruction
HANDLE_OTHER_INST(56, UserOp1, Instruction) // May be used internally in a pass
HANDLE_OTHER_INST(57, UserOp2, Instruction) // Internal to passes only
HANDLE_USER_INST (56, UserOp1, Instruction) // May be used internally in a pass
HANDLE_USER_INST (57, UserOp2, Instruction) // Internal to passes only
HANDLE_OTHER_INST(58, VAArg , VAArgInst ) // vaarg instruction
HANDLE_OTHER_INST(59, ExtractElement, ExtractElementInst)// extract from vector
HANDLE_OTHER_INST(60, InsertElement, InsertElementInst) // insert into vector
@ -220,6 +224,8 @@ HANDLE_OTHER_INST(64, LandingPad, LandingPadInst) // Landing pad instruction.
#undef HANDLE_OTHER_INST
#undef LAST_OTHER_INST
#undef HANDLE_USER_INST
#ifdef HANDLE_INST
#undef HANDLE_INST
#endif

View File

@ -36,6 +36,10 @@ class FastMathFlags;
class MDNode;
struct AAMDNodes;
template <> struct ilist_alloc_traits<Instruction> {
static inline void deleteNode(Instruction *V);
};
class Instruction : public User,
public ilist_node_with_parent<Instruction, BasicBlock> {
BasicBlock *Parent;
@ -47,13 +51,13 @@ class Instruction : public User,
HasMetadataBit = 1 << 15
};
protected:
~Instruction(); // Use deleteValue() to delete a generic Instruction.
public:
Instruction(const Instruction &) = delete;
Instruction &operator=(const Instruction &) = delete;
// Out of line virtual method, so the vtable, etc has a home.
~Instruction() override;
/// Specialize the methods defined in Value, as we know that an instruction
/// can only be used by other instructions.
Instruction *user_back() { return cast<Instruction>(*user_begin());}
@ -640,6 +644,10 @@ private:
Instruction *cloneImpl() const;
};
inline void ilist_alloc_traits<Instruction>::deleteNode(Instruction *V) {
V->deleteValue();
}
} // end namespace llvm
#endif // LLVM_IR_INSTRUCTION_H

View File

@ -89,9 +89,6 @@ public:
AllocaInst(Type *Ty, unsigned AddrSpace, Value *ArraySize, unsigned Align,
const Twine &Name, BasicBlock *InsertAtEnd);
// Out of line virtual method, so the vtable, etc. has a home.
~AllocaInst() override;
/// Return true if there is an allocation size parameter to the allocation
/// instruction that is not 1.
bool isArrayAllocation() const;
@ -856,7 +853,6 @@ class GetElementPtrInst : public Instruction {
ArrayRef<Value *> IdxList, unsigned Values,
const Twine &NameStr, BasicBlock *InsertAtEnd);
void anchor() override;
void init(Value *Ptr, ArrayRef<Value *> IdxList, const Twine &NameStr);
protected:
@ -1112,8 +1108,6 @@ DEFINE_TRANSPARENT_OPERAND_ACCESSORS(GetElementPtrInst, Value)
/// must be identical types.
/// Represent an integer comparison operator.
class ICmpInst: public CmpInst {
void anchor() override;
void AssertOK() {
assert(getPredicate() >= CmpInst::FIRST_ICMP_PREDICATE &&
getPredicate() <= CmpInst::LAST_ICMP_PREDICATE &&
@ -1426,8 +1420,6 @@ protected:
CallInst *cloneImpl() const;
public:
~CallInst() override;
static CallInst *Create(Value *Func, ArrayRef<Value *> Args,
ArrayRef<OperandBundleDef> Bundles = None,
const Twine &NameStr = "",
@ -2592,8 +2584,6 @@ class PHINode : public Instruction {
return User::operator new(s);
}
void anchor() override;
protected:
// Note: Instruction needs to be a friend here to call cloneImpl.
friend class Instruction;
@ -2927,8 +2917,6 @@ protected:
ReturnInst *cloneImpl() const;
public:
~ReturnInst() override;
static ReturnInst* Create(LLVMContext &C, Value *retVal = nullptr,
Instruction *InsertBefore = nullptr) {
return new(!!retVal) ReturnInst(C, retVal, InsertBefore);

View File

@ -174,12 +174,13 @@ class MetadataAsValue : public Value {
Metadata *MD;
MetadataAsValue(Type *Ty, Metadata *MD);
~MetadataAsValue() override;
/// \brief Drop use of metadata (during teardown).
void dropUse() { MD = nullptr; }
public:
~MetadataAsValue();
static MetadataAsValue *get(LLVMContext &Context, Metadata *MD);
static MetadataAsValue *getIfExists(LLVMContext &Context, Metadata *MD);
Metadata *getMetadata() const { return MD; }

View File

@ -30,6 +30,9 @@ namespace llvm {
template <typename SubClass, unsigned ARITY>
struct FixedNumOperandTraits {
static Use *op_begin(SubClass* U) {
static_assert(
!std::is_polymorphic<SubClass>::value,
"adding virtual methods to subclasses of User breaks use lists");
return reinterpret_cast<Use*>(U) - ARITY;
}
static Use *op_end(SubClass* U) {
@ -65,6 +68,9 @@ struct OptionalOperandTraits : public FixedNumOperandTraits<SubClass, ARITY> {
template <typename SubClass, unsigned MINARITY = 0>
struct VariadicOperandTraits {
static Use *op_begin(SubClass* U) {
static_assert(
!std::is_polymorphic<SubClass>::value,
"adding virtual methods to subclasses of User breaks use lists");
return reinterpret_cast<Use*>(U) - static_cast<User*>(U)->getNumOperands();
}
static Use *op_end(SubClass* U) {

View File

@ -29,16 +29,11 @@ namespace llvm {
/// This is a utility class that provides an abstraction for the common
/// functionality between Instructions and ConstantExprs.
class Operator : public User {
protected:
// NOTE: Cannot use = delete because it's not legal to delete
// an overridden method that's not deleted in the base class. Cannot leave
// this unimplemented because that leads to an ODR-violation.
~Operator() override;
public:
// The Operator class is intended to be used as a utility, and is never itself
// instantiated.
Operator() = delete;
~Operator() = delete;
void *operator new(size_t, unsigned) = delete;
void *operator new(size_t s) = delete;

View File

@ -46,8 +46,6 @@ class User : public Value {
template <unsigned>
friend struct HungoffOperandTraits;
virtual void anchor();
LLVM_ATTRIBUTE_ALWAYS_INLINE inline static void *
allocateFixedOperandUser(size_t, unsigned, unsigned);
@ -93,9 +91,11 @@ protected:
/// should be called if there are no uses.
void growHungoffUses(unsigned N, bool IsPhi = false);
protected:
~User() = default; // Use deleteValue() to delete a generic Instruction.
public:
User(const User &) = delete;
~User() override = default;
/// \brief Free memory allocated for User and Use objects.
void operator delete(void *Usr);

View File

@ -20,10 +20,14 @@
#if !(defined HANDLE_GLOBAL_VALUE || defined HANDLE_CONSTANT || \
defined HANDLE_INSTRUCTION || defined HANDLE_INLINE_ASM_VALUE || \
defined HANDLE_METADATA_VALUE || defined HANDLE_VALUE || \
defined HANDLE_CONSTANT_MARKER)
defined HANDLE_CONSTANT_MARKER || defined HANDLE_MEMORY_VALUE)
#error "Missing macro definition of HANDLE_VALUE*"
#endif
#ifndef HANDLE_MEMORY_VALUE
#define HANDLE_MEMORY_VALUE(ValueName) HANDLE_VALUE(ValueName)
#endif
#ifndef HANDLE_GLOBAL_VALUE
#define HANDLE_GLOBAL_VALUE(ValueName) HANDLE_CONSTANT(ValueName)
#endif
@ -54,9 +58,13 @@
HANDLE_VALUE(Argument)
HANDLE_VALUE(BasicBlock)
HANDLE_VALUE(MemoryUse)
HANDLE_VALUE(MemoryDef)
HANDLE_VALUE(MemoryPhi)
// FIXME: It's awkward that Value.def knows about classes in Analysis. While
// this doesn't introduce a strict link or include dependency, we should remove
// the circular dependency eventually.
HANDLE_MEMORY_VALUE(MemoryUse)
HANDLE_MEMORY_VALUE(MemoryDef)
HANDLE_MEMORY_VALUE(MemoryPhi)
HANDLE_GLOBAL_VALUE(Function)
HANDLE_GLOBAL_VALUE(GlobalAlias)
@ -94,6 +102,7 @@ HANDLE_CONSTANT_MARKER(ConstantDataLastVal, ConstantTokenNone)
HANDLE_CONSTANT_MARKER(ConstantAggregateFirstVal, ConstantArray)
HANDLE_CONSTANT_MARKER(ConstantAggregateLastVal, ConstantVector)
#undef HANDLE_MEMORY_VALUE
#undef HANDLE_GLOBAL_VALUE
#undef HANDLE_CONSTANT
#undef HANDLE_INSTRUCTION

View File

@ -21,6 +21,7 @@
#include "llvm-c/Types.h"
#include <cassert>
#include <iterator>
#include <memory>
namespace llvm {
@ -69,6 +70,8 @@ using ValueName = StringMapEntry<Value*>;
/// objects that watch it and listen to RAUW and Destroy events. See
/// llvm/IR/ValueHandle.h for details.
class Value {
// The least-significant bit of the first word of Value *must* be zero:
// http://www.llvm.org/docs/ProgrammersManual.html#the-waymarking-algorithm
Type *VTy;
Use *UseList;
@ -200,10 +203,19 @@ private:
protected:
Value(Type *Ty, unsigned scid);
/// Value's destructor should be virtual by design, but that would require
/// that Value and all of its subclasses have a vtable that effectively
/// duplicates the information in the value ID. As a size optimization, the
/// destructor has been protected, and the caller should manually call
/// deleteValue.
~Value(); // Use deleteValue() to delete a generic Value.
public:
Value(const Value &) = delete;
void operator=(const Value &) = delete;
virtual ~Value();
/// Delete a pointer to a generic Value.
void deleteValue();
/// \brief Support for debugging, callable in GDB: V->dump()
void dump() const;
@ -643,6 +655,13 @@ protected:
void setValueSubclassData(unsigned short D) { SubclassData = D; }
};
struct ValueDeleter { void operator()(Value *V) { V->deleteValue(); } };
/// Use this instead of std::unique_ptr<Value> or std::unique_ptr<Instruction>.
/// Those don't work because Value and Instruction's destructors are protected,
/// aren't virtual, and won't destroy the complete object.
typedef std::unique_ptr<Value, ValueDeleter> unique_value;
inline raw_ostream &operator<<(raw_ostream &OS, const Value &V) {
V.print(OS);
return OS;

View File

@ -1799,6 +1799,15 @@ bool MemorySSA::dominates(const MemoryAccess *Dominator,
const static char LiveOnEntryStr[] = "liveOnEntry";
void MemoryAccess::print(raw_ostream &OS) const {
switch (getValueID()) {
case MemoryPhiVal: return static_cast<const MemoryPhi *>(this)->print(OS);
case MemoryDefVal: return static_cast<const MemoryDef *>(this)->print(OS);
case MemoryUseVal: return static_cast<const MemoryUse *>(this)->print(OS);
}
llvm_unreachable("invalid value id");
}
void MemoryDef::print(raw_ostream &OS) const {
MemoryAccess *UO = getDefiningAccess();
@ -1836,8 +1845,6 @@ void MemoryPhi::print(raw_ostream &OS) const {
OS << ')';
}
MemoryAccess::~MemoryAccess() {}
void MemoryUse::print(raw_ostream &OS) const {
MemoryAccess *UO = getDefiningAccess();
OS << "MemoryUse(";
@ -2054,3 +2061,15 @@ MemoryAccess *DoNothingMemorySSAWalker::getClobberingMemoryAccess(
return StartingAccess;
}
} // namespace llvm
void MemoryPhi::deleteMe(DerivedUser *Self) {
delete static_cast<MemoryPhi *>(Self);
}
void MemoryDef::deleteMe(DerivedUser *Self) {
delete static_cast<MemoryDef *>(Self);
}
void MemoryUse::deleteMe(DerivedUser *Self) {
delete static_cast<MemoryUse *>(Self);
}

View File

@ -2502,7 +2502,7 @@ LLParser::PerFunctionState::~PerFunctionState() {
continue;
P.second.first->replaceAllUsesWith(
UndefValue::get(P.second.first->getType()));
delete P.second.first;
P.second.first->deleteValue();
}
for (const auto &P : ForwardRefValIDs) {
@ -2510,7 +2510,7 @@ LLParser::PerFunctionState::~PerFunctionState() {
continue;
P.second.first->replaceAllUsesWith(
UndefValue::get(P.second.first->getType()));
delete P.second.first;
P.second.first->deleteValue();
}
}
@ -2642,7 +2642,7 @@ bool LLParser::PerFunctionState::SetInstName(int NameID,
getTypeString(FI->second.first->getType()) + "'");
Sentinel->replaceAllUsesWith(Inst);
delete Sentinel;
Sentinel->deleteValue();
ForwardRefValIDs.erase(FI);
}
@ -2659,7 +2659,7 @@ bool LLParser::PerFunctionState::SetInstName(int NameID,
getTypeString(FI->second.first->getType()) + "'");
Sentinel->replaceAllUsesWith(Inst);
delete Sentinel;
Sentinel->deleteValue();
ForwardRefVals.erase(FI);
}

View File

@ -4489,11 +4489,11 @@ Error BitcodeReader::parseFunctionBody(Function *F) {
// Add instruction to end of current BB. If there is no current BB, reject
// this file.
if (!CurBB) {
delete I;
I->deleteValue();
return error("Invalid instruction with no BB");
}
if (!OperandBundles.empty()) {
delete I;
I->deleteValue();
return error("Operand bundles found with no consumer");
}
CurBB->getInstList().push_back(I);

View File

@ -73,7 +73,7 @@ void BitcodeReaderValueList::assignValue(Value *V, unsigned Idx) {
// If there was a forward reference to this value, replace it.
Value *PrevVal = OldV;
OldV->replaceAllUsesWith(V);
delete PrevVal;
PrevVal->deleteValue();
}
}
@ -194,6 +194,6 @@ void BitcodeReaderValueList::resolveConstantForwardRefs() {
// Update all ValueHandles, they should be the only users at this point.
Placeholder->replaceAllUsesWith(RealVal);
delete Placeholder;
Placeholder->deleteValue();
}
}

View File

@ -350,7 +350,7 @@ bool CodeGenPrepare::runOnFunction(Function &F) {
// Really free removed instructions during promotion.
for (Instruction *I : RemovedInsts)
delete I;
I->deleteValue();
EverMadeChange |= MadeChange;
}

View File

@ -37,10 +37,6 @@ using namespace llvm;
// Constant Class
//===----------------------------------------------------------------------===//
void Constant::anchor() { }
void ConstantData::anchor() {}
bool Constant::isNegativeZeroValue() const {
// Floating point values have an explicit -0.0 value.
if (const ConstantFP *CFP = dyn_cast<ConstantFP>(this))
@ -496,8 +492,6 @@ void Constant::removeDeadConstantUsers() const {
// ConstantInt
//===----------------------------------------------------------------------===//
void ConstantInt::anchor() { }
ConstantInt::ConstantInt(IntegerType *Ty, const APInt &V)
: ConstantData(Ty, ConstantIntVal), Val(V) {
assert(V.getBitWidth() == Ty->getBitWidth() && "Invalid constant for type");
@ -610,8 +604,6 @@ static const fltSemantics *TypeToFloatSemantics(Type *Ty) {
return &APFloat::PPCDoubleDouble();
}
void ConstantFP::anchor() { }
Constant *ConstantFP::get(Type *Ty, double V) {
LLVMContext &Context = Ty->getContext();
@ -2266,9 +2258,6 @@ Type *GetElementPtrConstantExpr::getResultElementType() const {
//===----------------------------------------------------------------------===//
// ConstantData* implementations
void ConstantDataArray::anchor() {}
void ConstantDataVector::anchor() {}
Type *ConstantDataSequential::getElementType() const {
return getType()->getElementType();
}

View File

@ -44,8 +44,6 @@ namespace llvm {
/// UnaryConstantExpr - This class is private to Constants.cpp, and is used
/// behind the scenes to implement unary constant exprs.
class UnaryConstantExpr : public ConstantExpr {
void anchor() override;
public:
UnaryConstantExpr(unsigned Opcode, Constant *C, Type *Ty)
: ConstantExpr(Ty, Opcode, &Op<0>(), 1) {
@ -65,8 +63,6 @@ public:
/// BinaryConstantExpr - This class is private to Constants.cpp, and is used
/// behind the scenes to implement binary constant exprs.
class BinaryConstantExpr : public ConstantExpr {
void anchor() override;
public:
BinaryConstantExpr(unsigned Opcode, Constant *C1, Constant *C2,
unsigned Flags)
@ -90,8 +86,6 @@ public:
/// SelectConstantExpr - This class is private to Constants.cpp, and is used
/// behind the scenes to implement select constant exprs.
class SelectConstantExpr : public ConstantExpr {
void anchor() override;
public:
SelectConstantExpr(Constant *C1, Constant *C2, Constant *C3)
: ConstantExpr(C2->getType(), Instruction::Select, &Op<0>(), 3) {
@ -115,8 +109,6 @@ public:
/// Constants.cpp, and is used behind the scenes to implement
/// extractelement constant exprs.
class ExtractElementConstantExpr : public ConstantExpr {
void anchor() override;
public:
ExtractElementConstantExpr(Constant *C1, Constant *C2)
: ConstantExpr(cast<VectorType>(C1->getType())->getElementType(),
@ -140,8 +132,6 @@ public:
/// Constants.cpp, and is used behind the scenes to implement
/// insertelement constant exprs.
class InsertElementConstantExpr : public ConstantExpr {
void anchor() override;
public:
InsertElementConstantExpr(Constant *C1, Constant *C2, Constant *C3)
: ConstantExpr(C1->getType(), Instruction::InsertElement,
@ -166,8 +156,6 @@ public:
/// Constants.cpp, and is used behind the scenes to implement
/// shufflevector constant exprs.
class ShuffleVectorConstantExpr : public ConstantExpr {
void anchor() override;
public:
ShuffleVectorConstantExpr(Constant *C1, Constant *C2, Constant *C3)
: ConstantExpr(VectorType::get(
@ -195,8 +183,6 @@ public:
/// Constants.cpp, and is used behind the scenes to implement
/// extractvalue constant exprs.
class ExtractValueConstantExpr : public ConstantExpr {
void anchor() override;
public:
ExtractValueConstantExpr(Constant *Agg, ArrayRef<unsigned> IdxList,
Type *DestTy)
@ -230,8 +216,6 @@ public:
/// Constants.cpp, and is used behind the scenes to implement
/// insertvalue constant exprs.
class InsertValueConstantExpr : public ConstantExpr {
void anchor() override;
public:
InsertValueConstantExpr(Constant *Agg, Constant *Val,
ArrayRef<unsigned> IdxList, Type *DestTy)
@ -271,8 +255,6 @@ class GetElementPtrConstantExpr : public ConstantExpr {
GetElementPtrConstantExpr(Type *SrcElementTy, Constant *C,
ArrayRef<Constant *> IdxList, Type *DestTy);
void anchor() override;
public:
static GetElementPtrConstantExpr *Create(Type *SrcElementTy, Constant *C,
ArrayRef<Constant *> IdxList,
@ -301,8 +283,6 @@ public:
// behind the scenes to implement ICmp and FCmp constant expressions. This is
// needed in order to store the predicate value for these instructions.
class CompareConstantExpr : public ConstantExpr {
void anchor() override;
public:
unsigned short predicate;
CompareConstantExpr(Type *ty, Instruction::OtherOps opc,

View File

@ -66,8 +66,6 @@ template class llvm::SymbolTableListTraits<BasicBlock>;
// Argument Implementation
//===----------------------------------------------------------------------===//
void Argument::anchor() {}
Argument::Argument(Type *Ty, const Twine &Name, Function *Par, unsigned ArgNo)
: Value(Ty, Value::ArgumentVal), Parent(Par), ArgNo(ArgNo) {
setName(Name);

View File

@ -40,10 +40,6 @@ InlineAsm::InlineAsm(FunctionType *FTy, const std::string &asmString,
"Function type not legal for constraints!");
}
// Implement the first virtual method in this class in this file so the
// InlineAsm vtable is emitted here.
InlineAsm::~InlineAsm() = default;
InlineAsm *InlineAsm::get(FunctionType *FTy, StringRef AsmString,
StringRef Constraints, bool hasSideEffects,
bool isAlignStack, AsmDialect asmDialect) {

View File

@ -43,8 +43,6 @@ Instruction::Instruction(Type *ty, unsigned it, Use *Ops, unsigned NumOps,
InsertAtEnd->getInstList().push_back(this);
}
// Out of line virtual method, so the vtable, etc has a home.
Instruction::~Instruction() {
assert(!Parent && "Instruction still linked in the program!");
if (hasMetadataHashEntry())

View File

@ -59,9 +59,6 @@ User::op_iterator CallSite::getCallee() const {
// TerminatorInst Class
//===----------------------------------------------------------------------===//
// Out of line virtual method, so the vtable, etc has a home.
TerminatorInst::~TerminatorInst() = default;
unsigned TerminatorInst::getNumSuccessors() const {
switch (getOpcode()) {
#define HANDLE_TERM_INST(N, OPC, CLASS) \
@ -98,13 +95,6 @@ void TerminatorInst::setSuccessor(unsigned idx, BasicBlock *B) {
llvm_unreachable("not a terminator");
}
//===----------------------------------------------------------------------===//
// UnaryInstruction Class
//===----------------------------------------------------------------------===//
// Out of line virtual method, so the vtable, etc has a home.
UnaryInstruction::~UnaryInstruction() = default;
//===----------------------------------------------------------------------===//
// SelectInst Class
//===----------------------------------------------------------------------===//
@ -138,8 +128,6 @@ const char *SelectInst::areInvalidOperands(Value *Op0, Value *Op1, Value *Op2) {
// PHINode Class
//===----------------------------------------------------------------------===//
void PHINode::anchor() {}
PHINode::PHINode(const PHINode &PN)
: Instruction(PN.getType(), Instruction::PHI, nullptr, PN.getNumOperands()),
ReservedSpace(PN.getNumOperands()) {
@ -293,8 +281,6 @@ void LandingPadInst::addClause(Constant *Val) {
// CallInst Implementation
//===----------------------------------------------------------------------===//
CallInst::~CallInst() = default;
void CallInst::init(FunctionType *FTy, Value *Func, ArrayRef<Value *> Args,
ArrayRef<OperandBundleDef> Bundles, const Twine &NameStr) {
this->FTy = FTy;
@ -900,8 +886,6 @@ BasicBlock *ReturnInst::getSuccessorV(unsigned idx) const {
llvm_unreachable("ReturnInst has no successors!");
}
ReturnInst::~ReturnInst() = default;
//===----------------------------------------------------------------------===//
// ResumeInst Implementation
//===----------------------------------------------------------------------===//
@ -1337,9 +1321,6 @@ AllocaInst::AllocaInst(Type *Ty, unsigned AddrSpace, Value *ArraySize,
setName(Name);
}
// Out of line virtual method, so the vtable, etc has a home.
AllocaInst::~AllocaInst() = default;
void AllocaInst::setAlignment(unsigned Align) {
assert((Align & (Align-1)) == 0 && "Alignment is not a power of 2!");
assert(Align <= MaximumAlignment &&
@ -1689,8 +1670,6 @@ FenceInst::FenceInst(LLVMContext &C, AtomicOrdering Ordering,
// GetElementPtrInst Implementation
//===----------------------------------------------------------------------===//
void GetElementPtrInst::anchor() {}
void GetElementPtrInst::init(Value *Ptr, ArrayRef<Value *> IdxList,
const Twine &Name) {
assert(getNumOperands() == 1 + IdxList.size() &&
@ -2357,8 +2336,6 @@ float FPMathOperator::getFPAccuracy() const {
// CastInst Class
//===----------------------------------------------------------------------===//
void CastInst::anchor() {}
// Just determine if this cast only deals with integral->integral conversion.
bool CastInst::isIntegerCast() const {
switch (getOpcode()) {
@ -3387,8 +3364,6 @@ AddrSpaceCastInst::AddrSpaceCastInst(
// CmpInst Classes
//===----------------------------------------------------------------------===//
void CmpInst::anchor() {}
CmpInst::CmpInst(Type *ty, OtherOps op, Predicate predicate, Value *LHS,
Value *RHS, const Twine &Name, Instruction *InsertBefore)
: Instruction(ty, op,
@ -3528,8 +3503,6 @@ StringRef CmpInst::getPredicateName(Predicate Pred) {
}
}
void ICmpInst::anchor() {}
ICmpInst::Predicate ICmpInst::getSignedPredicate(Predicate pred) {
switch (pred) {
default: llvm_unreachable("Unknown icmp predicate!");

View File

@ -215,27 +215,6 @@ uint32_t LLVMContextImpl::getOperandBundleTagID(StringRef Tag) const {
return I->second;
}
// ConstantsContext anchors
void UnaryConstantExpr::anchor() { }
void BinaryConstantExpr::anchor() { }
void SelectConstantExpr::anchor() { }
void ExtractElementConstantExpr::anchor() { }
void InsertElementConstantExpr::anchor() { }
void ShuffleVectorConstantExpr::anchor() { }
void ExtractValueConstantExpr::anchor() { }
void InsertValueConstantExpr::anchor() { }
void GetElementPtrConstantExpr::anchor() { }
void CompareConstantExpr::anchor() { }
/// Singleton instance of the OptBisect class.
///
/// This singleton is accessed via the LLVMContext::getOptBisect() function. It

View File

@ -19,8 +19,6 @@ class BasicBlock;
// User Class
//===----------------------------------------------------------------------===//
void User::anchor() {}
void User::replaceUsesOfWith(Value *From, Value *To) {
if (From == To) return; // Duh what?
@ -193,12 +191,4 @@ void User::operator delete(void *Usr) {
}
}
//===----------------------------------------------------------------------===//
// Operator Class
//===----------------------------------------------------------------------===//
Operator::~Operator() {
llvm_unreachable("should never destroy an Operator");
}
} // End llvm namespace

View File

@ -20,6 +20,7 @@
#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/DerivedUser.h"
#include "llvm/IR/GetElementPtrTypeIterator.h"
#include "llvm/IR/InstrTypes.h"
#include "llvm/IR/Instructions.h"
@ -59,7 +60,7 @@ Value::Value(Type *ty, unsigned scid)
(SubclassID < ConstantFirstVal || SubclassID > ConstantLastVal))
assert((VTy->isFirstClassType() || VTy->isVoidTy()) &&
"Cannot create non-first-class values except for constants!");
static_assert(sizeof(Value) == 3 * sizeof(void *) + 2 * sizeof(unsigned),
static_assert(sizeof(Value) == 2 * sizeof(void *) + 2 * sizeof(unsigned),
"Value too big");
}
@ -89,6 +90,32 @@ Value::~Value() {
destroyValueName();
}
void Value::deleteValue() {
switch (getValueID()) {
#define HANDLE_VALUE(Name) \
case Value::Name##Val: \
delete static_cast<Name *>(this); \
break;
#define HANDLE_MEMORY_VALUE(Name) \
case Value::Name##Val: \
static_cast<DerivedUser *>(this)->DeleteValue( \
static_cast<DerivedUser *>(this)); \
break;
#define HANDLE_INSTRUCTION(Name) /* nothing */
#include "llvm/IR/Value.def"
#define HANDLE_INST(N, OPC, CLASS) \
case Value::InstructionVal + Instruction::OPC: \
delete static_cast<CLASS *>(this); \
break;
#define HANDLE_USER_INST(N, OPC, CLASS)
#include "llvm/IR/Instruction.def"
default:
llvm_unreachable("attempting to delete unknown value kind");
}
}
void Value::destroyValueName() {
ValueName *Name = getValueName();
if (Name)

View File

@ -399,7 +399,7 @@ void Simplifier::Context::cleanup() {
for (Value *V : Clones) {
Instruction *U = cast<Instruction>(V);
if (!U->getParent())
delete U;
U->deleteValue();
}
}

View File

@ -2057,7 +2057,7 @@ bool GVN::performScalarPRE(Instruction *CurInst) {
if (!performScalarPREInsertion(PREInstr, PREPred, ValNo)) {
// If we failed insertion, make sure we remove the instruction.
DEBUG(verifyRemoved(PREInstr));
delete PREInstr;
PREInstr->deleteValue();
return false;
}
}

View File

@ -1906,7 +1906,7 @@ bool JumpThreadingPass::DuplicateCondBranchOnPHIIntoPred(
{BB->getModule()->getDataLayout(), TLI, nullptr, nullptr, New})) {
ValueMapping[&*BI] = IV;
if (!New->mayHaveSideEffects()) {
delete New;
New->deleteValue();
New = nullptr;
}
} else {

View File

@ -347,7 +347,7 @@ bool LoopRotate::rotateLoop(Loop *L, bool SimplifiedLatch) {
// in the map.
ValueMap[Inst] = V;
if (!C->mayHaveSideEffects()) {
delete C;
C->deleteValue();
C = nullptr;
}
} else {

View File

@ -1582,7 +1582,7 @@ Value *ReassociatePass::OptimizeAdd(Instruction *I,
}
// No need for extra uses anymore.
delete DummyInst;
DummyInst->deleteValue();
unsigned NumAddedValues = NewMulOps.size();
Value *V = EmitAddTreeOfValues(I, NewMulOps);

View File

@ -2443,7 +2443,7 @@ private:
"insert");
LI.replaceAllUsesWith(V);
Placeholder->replaceAllUsesWith(&LI);
delete Placeholder;
Placeholder->deleteValue();
} else {
LI.replaceAllUsesWith(V);
}

View File

@ -693,7 +693,7 @@ bool StraightLineStrengthReduce::runOnFunction(Function &F) {
UnlinkedInst->setOperand(I, nullptr);
RecursivelyDeleteTriviallyDeadInstructions(Op);
}
delete UnlinkedInst;
UnlinkedInst->deleteValue();
}
bool Ret = !UnlinkedInstructions.empty();
UnlinkedInstructions.clear();

View File

@ -317,7 +317,7 @@ void PruningFunctionCloner::CloneBlock(const BasicBlock *BB,
if (!NewInst->mayHaveSideEffects()) {
VMap[&*II] = V;
delete NewInst;
NewInst->deleteValue();
continue;
}
}

View File

@ -2235,7 +2235,7 @@ static bool FoldCondBranchOnPHI(BranchInst *BI, const DataLayout &DL,
if (!BBI->use_empty())
TranslateMap[&*BBI] = V;
if (!N->mayHaveSideEffects()) {
delete N; // Instruction folded away, don't need actual inst
N->deleteValue(); // Instruction folded away, don't need actual inst
N = nullptr;
}
} else {

View File

@ -578,12 +578,12 @@ private:
void eraseInstruction(Instruction *I) {
I->removeFromParent();
I->dropAllReferences();
DeletedInstructions.push_back(std::unique_ptr<Instruction>(I));
DeletedInstructions.emplace_back(I);
}
/// Temporary store for deleted instructions. Instructions will be deleted
/// eventually when the BoUpSLP is destructed.
SmallVector<std::unique_ptr<Instruction>, 8> DeletedInstructions;
SmallVector<unique_value, 8> DeletedInstructions;
/// A list of values that need to extracted out of the tree.
/// This list holds pairs of (Internal Scalar : External User). External User

View File

@ -178,12 +178,13 @@ TEST(ConstantsTest, PointerCast) {
ConstantExpr::getAddrSpaceCast(NullInt32Ptr1, Int32PtrTy));
}
#define CHECK(x, y) { \
#define CHECK(x, y) \
{ \
std::string __s; \
raw_string_ostream __o(__s); \
Instruction *__I = cast<ConstantExpr>(x)->getAsInstruction(); \
__I->print(__o); \
delete __I; \
__I->deleteValue(); \
__o.flush(); \
EXPECT_EQ(std::string(" <badref> = " y), __s); \
}

View File

@ -406,8 +406,8 @@ TEST(InstructionsTest, FPMathOperator) {
EXPECT_TRUE(isa<FPMathOperator>(V1));
FPMathOperator *O1 = cast<FPMathOperator>(V1);
EXPECT_EQ(O1->getFPAccuracy(), 1.0);
delete V1;
delete I;
V1->deleteValue();
I->deleteValue();
}

View File

@ -218,7 +218,7 @@ TEST_F(MDNodeTest, Delete) {
EXPECT_EQ(n, wvh);
delete I;
I->deleteValue();
}
TEST_F(MDNodeTest, SelfReference) {

View File

@ -41,13 +41,18 @@ protected:
}
void eraseClones() {
DeleteContainerPointers(Clones);
for (Value *V : Clones)
V->deleteValue();
Clones.clear();
}
void TearDown() override {
eraseClones();
DeleteContainerPointers(Orig);
delete V;
for (Value *V : Orig)
V->deleteValue();
Orig.clear();
if (V)
V->deleteValue();
}
SmallPtrSet<Value *, 4> Orig; // Erase on exit