Store Arguments in a flat array instead of an iplist

This saves two pointers from Argument and eliminates some extra
allocations.

Arguments cannot be inserted or removed from a Function because that
would require changing its Type, which LLVM does not allow. Instead,
passes that change prototypes, like DeadArgElim, create a new Function
and copy over argument names and attributes. The primary benefit of
iplist is O(1) random insertion and removal. We just don't need that for
arguments, so don't use it.

Reviewed By: chandlerc

Subscribers: dlj, inglorion, llvm-commits

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

llvm-svn: 298105
This commit is contained in:
Reid Kleckner 2017-03-17 17:16:39 +00:00
parent ee2dd785f6
commit 56d028d974
4 changed files with 72 additions and 43 deletions

View File

@ -21,25 +21,24 @@
namespace llvm {
template <typename NodeTy> class SymbolTableListTraits;
/// This class represents an incoming formal argument to a Function. A formal
/// argument, since it is ``formal'', does not contain an actual value but
/// instead represents the type, argument number, and attributes of an argument
/// 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, public ilist_node<Argument> {
class Argument : public Value {
virtual void anchor();
Function *Parent;
unsigned ArgNo;
friend class SymbolTableListTraits<Argument>;
friend class Function;
void setParent(Function *parent);
public:
/// Argument constructor.
explicit Argument(Type *Ty, const Twine &Name = "", unsigned ArgNo = 0);
explicit Argument(Type *Ty, const Twine &Name = "", Function *F = nullptr,
unsigned ArgNo = 0);
inline const Function *getParent() const { return Parent; }
inline Function *getParent() { return Parent; }
@ -47,7 +46,10 @@ public:
/// Return the index of this formal argument in its containing function.
///
/// For example in "void foo(int a, float b)" a is 0 and b is 1.
unsigned getArgNo() const { return ArgNo; }
unsigned getArgNo() const {
assert(Parent && "can't get number of unparented arg");
return ArgNo;
}
/// Return true if this argument has the nonnull attribute. Also returns true
/// if at least one byte is known to be dereferenceable and the pointer is in

View File

@ -48,20 +48,20 @@ class DISubprogram;
class Function : public GlobalObject, public ilist_node<Function> {
public:
typedef SymbolTableList<Argument> ArgumentListType;
typedef SymbolTableList<BasicBlock> BasicBlockListType;
// BasicBlock iterators...
typedef BasicBlockListType::iterator iterator;
typedef BasicBlockListType::const_iterator const_iterator;
typedef ArgumentListType::iterator arg_iterator;
typedef ArgumentListType::const_iterator const_arg_iterator;
typedef Argument *arg_iterator;
typedef const Argument *const_arg_iterator;
private:
// Important things that make up a function!
BasicBlockListType BasicBlocks; ///< The basic blocks
mutable ArgumentListType ArgumentList; ///< The formal arguments
mutable Argument *Arguments; ///< The formal arguments
size_t NumArgs;
std::unique_ptr<ValueSymbolTable>
SymTab; ///< Symbol table of args/instructions
AttributeSet AttributeSets; ///< Parameter attributes
@ -103,6 +103,8 @@ private:
void BuildLazyArguments() const;
void clearArguments();
/// Function ctor - If the (optional) Module argument is specified, the
/// function is automatically inserted into the end of the function list for
/// the module.
@ -509,10 +511,6 @@ public:
/// Requires that this has no function body.
void stealArgumentListFrom(Function &Src);
static ArgumentListType Function::*getSublistAccess(Argument*) {
return &Function::ArgumentList;
}
/// Get the underlying elements of the Function... the basic block list is
/// empty for external functions.
///
@ -556,20 +554,20 @@ public:
arg_iterator arg_begin() {
CheckLazyArguments();
return ArgumentList.begin();
return Arguments;
}
const_arg_iterator arg_begin() const {
CheckLazyArguments();
return ArgumentList.begin();
return Arguments;
}
arg_iterator arg_end() {
CheckLazyArguments();
return ArgumentList.end();
return Arguments + NumArgs;
}
const_arg_iterator arg_end() const {
CheckLazyArguments();
return ArgumentList.end();
return Arguments + NumArgs;
}
iterator_range<arg_iterator> args() {
@ -581,7 +579,7 @@ public:
/// @}
size_t arg_size() const { return getFunctionType()->getNumParams(); }
size_t arg_size() const { return NumArgs; }
bool arg_empty() const { return arg_size() == 0; }
/// \brief Check whether this function has a personality function.

View File

@ -1913,10 +1913,8 @@ void LLVMGetParams(LLVMValueRef FnRef, LLVMValueRef *ParamRefs) {
}
LLVMValueRef LLVMGetParam(LLVMValueRef FnRef, unsigned index) {
Function::arg_iterator AI = unwrap<Function>(FnRef)->arg_begin();
while (index --> 0)
AI++;
return wrap(&*AI);
Function *Fn = unwrap<Function>(FnRef);
return wrap(&Fn->arg_begin()[index]);
}
LLVMValueRef LLVMGetParamParent(LLVMValueRef V) {
@ -1941,18 +1939,17 @@ LLVMValueRef LLVMGetLastParam(LLVMValueRef Fn) {
LLVMValueRef LLVMGetNextParam(LLVMValueRef Arg) {
Argument *A = unwrap<Argument>(Arg);
Function::arg_iterator I(A);
if (++I == A->getParent()->arg_end())
Function *Fn = A->getParent();
if (A->getArgNo() + 1 >= Fn->arg_size())
return nullptr;
return wrap(&*I);
return wrap(&Fn->arg_begin()[A->getArgNo() + 1]);
}
LLVMValueRef LLVMGetPreviousParam(LLVMValueRef Arg) {
Argument *A = unwrap<Argument>(Arg);
Function::arg_iterator I(A);
if (I == A->getParent()->arg_begin())
if (A->getArgNo() == 0)
return nullptr;
return wrap(&*--I);
return wrap(&A->getParent()->arg_begin()[A->getArgNo() - 1]);
}
void LLVMSetParamAlignment(LLVMValueRef Arg, unsigned align) {

View File

@ -30,7 +30,6 @@ using namespace llvm;
// Explicit instantiations of SymbolTableListTraits since some of the methods
// are not in the public header file...
template class llvm::SymbolTableListTraits<Argument>;
template class llvm::SymbolTableListTraits<BasicBlock>;
//===----------------------------------------------------------------------===//
@ -39,8 +38,8 @@ template class llvm::SymbolTableListTraits<BasicBlock>;
void Argument::anchor() { }
Argument::Argument(Type *Ty, const Twine &Name, unsigned ArgNo)
: Value(Ty, Value::ArgumentVal), Parent(nullptr), ArgNo(ArgNo) {
Argument::Argument(Type *Ty, const Twine &Name, Function *Par, unsigned ArgNo)
: Value(Ty, Value::ArgumentVal), Parent(Par), ArgNo(ArgNo) {
setName(Name);
}
@ -188,7 +187,8 @@ void Function::eraseFromParent() {
Function::Function(FunctionType *Ty, LinkageTypes Linkage, const Twine &name,
Module *ParentModule)
: GlobalObject(Ty, Value::FunctionVal,
OperandTraits<Function>::op_begin(this), 0, Linkage, name) {
OperandTraits<Function>::op_begin(this), 0, Linkage, name),
Arguments(nullptr), NumArgs(Ty->getNumParams()) {
assert(FunctionType::isValidReturnType(getReturnType()) &&
"invalid return type");
setGlobalObjectSubClassData(0);
@ -216,7 +216,8 @@ Function::~Function() {
dropAllReferences(); // After this it is safe to delete instructions.
// Delete all of the method arguments and unlink from symbol table...
ArgumentList.clear();
if (Arguments)
clearArguments();
// Remove the function from the on-the-side GC table.
clearGC();
@ -224,17 +225,33 @@ Function::~Function() {
void Function::BuildLazyArguments() const {
// Create the arguments vector, all arguments start out unnamed.
FunctionType *FT = getFunctionType();
for (unsigned i = 0, e = FT->getNumParams(); i != e; ++i) {
assert(!FT->getParamType(i)->isVoidTy() &&
"Cannot have void typed arguments!");
ArgumentList.push_back(
new Argument(FT->getParamType(i), "", i));
auto *FT = getFunctionType();
if (NumArgs > 0) {
Arguments = std::allocator<Argument>().allocate(NumArgs);
for (unsigned i = 0, e = NumArgs; i != e; ++i) {
Type *ArgTy = FT->getParamType(i);
assert(!ArgTy->isVoidTy() && "Cannot have void typed arguments!");
new (Arguments + i) Argument(ArgTy, "", const_cast<Function *>(this), i);
}
}
// Clear the lazy arguments bit.
unsigned SDC = getSubclassDataFromValue();
const_cast<Function*>(this)->setValueSubclassData(SDC &= ~(1<<0));
assert(!hasLazyArguments());
}
static MutableArrayRef<Argument> makeArgArray(Argument *Args, size_t Count) {
return MutableArrayRef<Argument>(Args, Count);
}
void Function::clearArguments() {
for (Argument &A : makeArgArray(Arguments, NumArgs)) {
A.setName("");
A.~Argument();
}
std::allocator<Argument>().deallocate(Arguments, NumArgs);
Arguments = nullptr;
}
void Function::stealArgumentListFrom(Function &Src) {
@ -242,10 +259,10 @@ void Function::stealArgumentListFrom(Function &Src) {
// Drop the current arguments, if any, and set the lazy argument bit.
if (!hasLazyArguments()) {
assert(llvm::all_of(ArgumentList,
assert(llvm::all_of(makeArgArray(Arguments, NumArgs),
[](const Argument &A) { return A.use_empty(); }) &&
"Expected arguments to be unused in declaration");
ArgumentList.clear();
clearArguments();
setValueSubclassData(getSubclassDataFromValue() | (1 << 0));
}
@ -254,8 +271,23 @@ void Function::stealArgumentListFrom(Function &Src) {
return;
// Steal arguments from Src, and fix the lazy argument bits.
ArgumentList.splice(ArgumentList.end(), Src.ArgumentList);
assert(arg_size() == Src.arg_size());
Arguments = Src.Arguments;
Src.Arguments = nullptr;
for (Argument &A : makeArgArray(Arguments, NumArgs)) {
// FIXME: This does the work of transferNodesFromList inefficiently.
SmallString<128> Name;
if (A.hasName())
Name = A.getName();
if (!Name.empty())
A.setName("");
A.setParent(this);
if (!Name.empty())
A.setName(Name);
}
setValueSubclassData(getSubclassDataFromValue() & ~(1 << 0));
assert(!hasLazyArguments());
Src.setValueSubclassData(Src.getSubclassDataFromValue() | (1 << 0));
}