56#define DEBUG_TYPE "deadargelim"
58STATISTIC(NumArgumentsEliminated,
"Number of unread args removed");
59STATISTIC(NumRetValsEliminated,
"Number of unused return values removed");
61 "Number of unread args replaced with poison");
74 DAE() : ModulePass(ID) {}
76 bool runOnModule(
Module &M)
override {
79 DeadArgumentEliminationPass DAEP;
81 PreservedAnalyses PA = DAEP.
run(M, DummyMAM);
90INITIALIZE_PASS(DAE,
"deadargelim",
"Dead Argument Elimination",
false,
false)
98bool DeadArgumentEliminationPass::deleteDeadVarargs(
Function &
F) {
99 assert(
F.getFunctionType()->isVarArg() &&
"Function isn't varargs!");
100 if (
F.isDeclaration() || !
F.hasLocalLinkage())
104 if (
F.hasAddressTaken())
110 if (
F.hasFnAttribute(Attribute::Naked)) {
116 for (BasicBlock &BB :
F) {
117 for (Instruction &
I : BB) {
124 if (
II->getIntrinsicID() == Intrinsic::vastart)
135 FunctionType *FTy =
F.getFunctionType();
137 std::vector<Type *> Params(FTy->param_begin(), FTy->param_end());
139 unsigned NumArgs = Params.size();
145 F.getParent()->getFunctionList().insert(
F.getIterator(), NF);
151 std::vector<Value *>
Args;
162 if (!PAL.isEmpty()) {
164 for (
unsigned ArgNo = 0; ArgNo < NumArgs; ++ArgNo)
165 ArgAttrs.
push_back(PAL.getParamAttrs(ArgNo));
166 PAL = AttributeList::get(
F.getContext(), PAL.getFnAttrs(),
167 PAL.getRetAttrs(), ArgAttrs);
173 CallBase *NewCB =
nullptr;
184 NewCB->
copyMetadata(*CB, {LLVMContext::MD_prof, LLVMContext::MD_dbg});
210 I->replaceAllUsesWith(&*I2);
216 F.getAllMetadata(MDs);
217 for (
auto [KindID, Node] : MDs)
221 F.replaceAllUsesWith(NF);
232bool DeadArgumentEliminationPass::removeDeadArgumentsFromCallers(
Function &
F) {
244 if (!
F.hasExactDefinition())
252 !
F.getFunctionType()->isVarArg())
258 if (
F.hasFnAttribute(Attribute::Naked))
264 SmallVector<unsigned, 8> UnusedArgs;
267 AttributeMask UBImplyingAttributes =
268 AttributeFuncs::getUBImplyingAttributes();
269 for (Argument &Arg :
F.args()) {
270 if (!Arg.hasSwiftErrorAttr() && Arg.use_empty() &&
271 !Arg.hasPassPointeeByValueCopyAttr()) {
272 if (Arg.isUsedByMetadata()) {
277 F.removeParamAttrs(Arg.getArgNo(), UBImplyingAttributes);
281 if (UnusedArgs.
empty())
284 for (Use &U :
F.uses()) {
291 for (
unsigned ArgNo : UnusedArgs) {
296 ++NumArgumentsReplacedWithPoison;
308 Type *RetTy =
F->getReturnType();
312 return STy->getNumElements();
314 return ATy->getNumElements();
322 Type *RetTy =
F->getReturnType();
326 return STy->getElementType(Idx);
328 return ATy->getElementType();
335DeadArgumentEliminationPass::markIfNotLive(RetOrArg
Use,
336 UseVector &MaybeLiveUses) {
343 MaybeLiveUses.push_back(Use);
355DeadArgumentEliminationPass::surveyUse(
const Use *U, UseVector &MaybeLiveUses,
356 unsigned RetValNum) {
357 const User *
V =
U->getUser();
363 const Function *
F = RI->getParent()->getParent();
364 if (RetValNum != -1U) {
367 return markIfNotLive(Use, MaybeLiveUses);
377 markIfNotLive(Use, MaybeLiveUses);
390 RetValNum = *
IV->idx_begin();
396 for (
const Use &UU :
IV->uses()) {
397 Result = surveyUse(&UU, MaybeLiveUses, RetValNum);
419 if (ArgNo >=
F->getFunctionType()->getNumParams())
424 "Argument is not where we expected it");
429 return markIfNotLive(Use, MaybeLiveUses);
443DeadArgumentEliminationPass::surveyUses(
const Value *V,
444 UseVector &MaybeLiveUses) {
448 for (
const Use &U :
V->uses()) {
449 Result = surveyUse(&U, MaybeLiveUses);
462void DeadArgumentEliminationPass::surveyFunction(
const Function &
F) {
464 if (!
F.hasLocalLinkage()) {
471 if (
F.getAttributes().hasAttrSomewhere(Attribute::InAlloca) ||
472 F.getAttributes().hasAttrSomewhere(Attribute::Preallocated)) {
480 if (
F.hasFnAttribute(Attribute::Naked)) {
486 if (!
F.isDefinitionExact()) {
496 RetVals RetValLiveness(RetCount,
MaybeLive);
503 RetUses MaybeLiveRetUses(RetCount);
505 for (
const BasicBlock &BB :
F) {
506 if (BB.getTerminatingMustTailCall()) {
508 <<
" has musttail calls\n");
509 if (markFnOrRetTyFrozenOnMusttail(
F))
515 dbgs() <<
"DeadArgumentEliminationPass - Inspecting callers for fn: "
516 <<
F.getName() <<
"\n");
519 unsigned NumLiveRetVals = 0;
522 for (
const Use &U :
F.uses()) {
534 <<
" has musttail callers\n");
535 if (markFnOrRetTyFrozenOnMusttail(
F))
543 if (NumLiveRetVals == RetCount)
547 for (
const Use &UU : CB->
uses()) {
551 unsigned Idx = *Ext->idx_begin();
552 if (RetValLiveness[Idx] !=
Live) {
553 RetValLiveness[Idx] = surveyUses(Ext, MaybeLiveRetUses[Idx]);
554 if (RetValLiveness[Idx] ==
Live)
561 if (surveyUse(&UU, MaybeLiveAggregateUses) ==
Live) {
562 NumLiveRetVals = RetCount;
563 RetValLiveness.assign(RetCount,
Live);
567 for (
unsigned Ri = 0; Ri != RetCount; ++Ri) {
568 if (RetValLiveness[Ri] !=
Live)
569 MaybeLiveRetUses[Ri].append(MaybeLiveAggregateUses.begin(),
570 MaybeLiveAggregateUses.end());
577 for (
unsigned Ri = 0; Ri != RetCount; ++Ri)
578 markValue(
createRet(&
F, Ri), RetValLiveness[Ri], MaybeLiveRetUses[Ri]);
580 LLVM_DEBUG(
dbgs() <<
"DeadArgumentEliminationPass - Inspecting args for fn: "
581 <<
F.getName() <<
"\n");
587 AI !=
E; ++AI, ++ArgI) {
589 if (
F.getFunctionType()->isVarArg()) {
599 Result = surveyUses(&*AI, MaybeLiveArgUses);
603 markValue(
createArg(&
F, ArgI), Result, MaybeLiveArgUses);
605 MaybeLiveArgUses.clear();
612void DeadArgumentEliminationPass::markValue(
const RetOrArg &
RA, Liveness L,
613 const UseVector &MaybeLiveUses) {
619 assert(!isLive(
RA) &&
"Use is already live!");
620 for (
const auto &MaybeLiveUse : MaybeLiveUses) {
621 if (isLive(MaybeLiveUse)) {
628 Uses.emplace(MaybeLiveUse,
RA);
638bool DeadArgumentEliminationPass::markFnOrRetTyFrozenOnMusttail(
653void DeadArgumentEliminationPass::markFrozen(
const Function &
F) {
655 <<
F.getName() <<
"\n");
659 for (
unsigned ArgI = 0,
E =
F.arg_size(); ArgI !=
E; ++ArgI)
666void DeadArgumentEliminationPass::markRetTyFrozen(
const Function &
F) {
667 LLVM_DEBUG(
dbgs() <<
"DeadArgumentEliminationPass - frozen return type fn: "
668 <<
F.getName() <<
"\n");
674void DeadArgumentEliminationPass::markLive(
const RetOrArg &
RA) {
681 <<
RA.getDescription() <<
" live\n");
682 propagateLiveness(
RA);
685bool DeadArgumentEliminationPass::isLive(
const RetOrArg &
RA) {
691void DeadArgumentEliminationPass::propagateLiveness(
const RetOrArg &
RA) {
695 UseMap::iterator Begin =
Uses.lower_bound(
RA);
696 UseMap::iterator
E =
Uses.end();
698 for (
I = Begin;
I !=
E &&
I->first ==
RA; ++
I)
703 Uses.erase(Begin,
I);
709bool DeadArgumentEliminationPass::removeDeadStuffFromFunction(
Function *
F) {
716 FunctionType *FTy =
F->getFunctionType();
717 std::vector<Type *> Params;
720 bool HasLiveReturnedArg =
false;
724 const AttributeList &PAL =
F->getAttributes();
725 OptimizationRemarkEmitter ORE(
F);
737 Params.push_back(
I->getType());
738 ArgAlive[ArgI] =
true;
739 ArgAttrVec.
push_back(PAL.getParamAttrs(ArgI));
740 HasLiveReturnedArg |= PAL.hasParamAttr(ArgI, Attribute::Returned);
742 ++NumArgumentsEliminated;
745 return OptimizationRemark(
DEBUG_TYPE,
"ArgumentRemoved",
F)
746 <<
"eliminating argument " <<
ore::NV(
"ArgName",
I->getName())
747 <<
"(" <<
ore::NV(
"ArgIndex", ArgI) <<
")";
749 LLVM_DEBUG(
dbgs() <<
"DeadArgumentEliminationPass - Removing argument "
750 << ArgI <<
" (" <<
I->getName() <<
") from "
751 <<
F->getName() <<
"\n");
756 Type *RetTy = FTy->getReturnType();
757 Type *NRetTy =
nullptr;
762 std::vector<Type *> RetTypes;
783 if (RetTy->
isVoidTy() || HasLiveReturnedArg ||
788 for (
unsigned Ri = 0; Ri != RetCount; ++Ri) {
792 NewRetIdxs[Ri] = RetTypes.size() - 1;
794 ++NumRetValsEliminated;
797 return OptimizationRemark(
DEBUG_TYPE,
"ReturnValueRemoved",
F)
798 <<
"removing return value " << std::to_string(Ri);
801 dbgs() <<
"DeadArgumentEliminationPass - Removing return value "
802 << Ri <<
" from " <<
F->getName() <<
"\n");
805 if (RetTypes.size() > 1) {
810 NRetTy =
StructType::get(STy->getContext(), RetTypes, STy->isPacked());
815 }
else if (RetTypes.size() == 1)
818 NRetTy = RetTypes.front();
819 else if (RetTypes.empty())
824 assert(NRetTy &&
"No new return type found?");
827 AttrBuilder RAttrs(
F->getContext(), PAL.getRetAttrs());
834 RAttrs.remove(AttributeFuncs::typeIncompatible(NRetTy, PAL.getRetAttrs()));
837 AttributeFuncs::typeIncompatible(NRetTy, PAL.getRetAttrs())) &&
838 "Return attributes no longer compatible?");
843 AttributeSet FnAttrs =
844 PAL.getFnAttrs().removeAttribute(
F->getContext(), Attribute::AllocSize);
848 AttributeList NewPAL =
849 AttributeList::get(
F->getContext(), FnAttrs, RetAttrs, ArgAttrVec);
865 F->getParent()->getFunctionList().insert(
F->getIterator(), NF);
870 std::vector<Value *>
Args;
871 while (!
F->use_empty()) {
879 AttrBuilder RAttrs(
F->getContext(), CallPAL.getRetAttrs());
881 AttributeFuncs::typeIncompatible(NRetTy, CallPAL.getRetAttrs()));
890 for (
unsigned E = FTy->getNumParams(); Pi !=
E; ++
I, ++Pi)
894 AttributeSet
Attrs = CallPAL.getParamAttrs(Pi);
895 if (NRetTy != RetTy &&
Attrs.hasAttribute(Attribute::Returned)) {
902 F->getContext(), AttrBuilder(
F->getContext(), Attrs)
903 .removeAttribute(Attribute::Returned)));
913 ArgAttrVec.
push_back(CallPAL.getParamAttrs(Pi));
921 AttributeSet FnAttrs = CallPAL.getFnAttrs().removeAttribute(
922 F->getContext(), Attribute::AllocSize);
924 AttributeList NewCallPAL =
925 AttributeList::get(
F->getContext(), FnAttrs, RetAttrs, ArgAttrVec);
930 CallBase *NewCB =
nullptr;
941 NewCB->
copyMetadata(CB, {LLVMContext::MD_prof, LLVMContext::MD_dbg});
956 "Return type changed, but not into a void. The old return type"
957 " must have been a struct or an array!");
971 for (
unsigned Ri = 0; Ri != RetCount; ++Ri)
972 if (NewRetIdxs[Ri] != -1) {
975 if (RetTypes.size() > 1)
978 V = IRB.CreateExtractValue(NewCB, NewRetIdxs[Ri],
"newret");
983 RetVal = IRB.CreateInsertValue(RetVal, V, Ri,
"oldret");
1007 I !=
E; ++
I, ++ArgI)
1008 if (ArgAlive[ArgI]) {
1011 I->replaceAllUsesWith(&*I2);
1023 for (BasicBlock &BB : *NF)
1026 Value *RetVal =
nullptr;
1028 if (!NFTy->getReturnType()->isVoidTy()) {
1035 Value *OldRet = RI->getOperand(0);
1038 for (
unsigned RetI = 0; RetI != RetCount; ++RetI)
1039 if (NewRetIdxs[RetI] != -1) {
1040 Value *EV = IRB.CreateExtractValue(OldRet, RetI,
"oldret");
1042 if (RetTypes.size() > 1) {
1046 RetVal = IRB.CreateInsertValue(RetVal, EV, NewRetIdxs[RetI],
1059 NewRet->setDebugLoc(RI->getDebugLoc());
1060 RI->eraseFromParent();
1065 F->getAllMetadata(MDs);
1066 for (
auto [KindID, Node] : MDs)
1067 NF->addMetadata(KindID, *Node);
1073 if (NFTy != FTy && NF->getSubprogram()) {
1074 DISubprogram *
SP = NF->getSubprogram();
1075 auto Temp =
SP->getType()->cloneWithCC(llvm::dwarf::DW_CC_nocall);
1080 F->eraseFromParent();
1093 LLVM_DEBUG(
dbgs() <<
"DeadArgumentEliminationPass - Deleting dead varargs\n");
1095 if (
F.getFunctionType()->isVarArg())
1101 LLVM_DEBUG(
dbgs() <<
"DeadArgumentEliminationPass - Determining liveness\n");
1109 Changed |= removeDeadStuffFromFunction(&
F);
1114 Changed |= removeDeadArgumentsFromCallers(
F);
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
This file contains the simple types necessary to represent the attributes associated with functions a...
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
This file contains the declarations for the subclasses of Constant, which represent the different fla...
static Type * getRetComponentType(const Function *F, unsigned Idx)
Returns the sub-type a function will return at a given Idx.
static unsigned numRetVals(const Function *F)
Convenience function that returns the number of return values.
Module.h This file contains the declarations for the Module class.
This header defines various interfaces for pass management in LLVM.
This defines the Use class.
Machine Check Debug Module
uint64_t IntrinsicInst * II
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
SI optimize exec mask operations pre RA
This file defines the SmallVector class.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
static const uint32_t IV[8]
static LLVM_ABI ArrayType * get(Type *ElementType, uint64_t NumElements)
This static method is the primary way to construct an ArrayType.
static LLVM_ABI AttributeSet get(LLVMContext &C, const AttrBuilder &B)
LLVM_ABI const_iterator getFirstInsertionPt() const
Returns an iterator to the first instruction in this block that is suitable for inserting a non-PHI i...
void setCallingConv(CallingConv::ID CC)
void removeParamAttrs(unsigned ArgNo, const AttributeMask &AttrsToRemove)
Removes the attributes from the given argument.
LLVM_ABI void getOperandBundlesAsDefs(SmallVectorImpl< OperandBundleDef > &Defs) const
Return the list of operand bundles attached to this instruction as a vector of OperandBundleDefs.
Function * getCalledFunction() const
Returns the function called, or null if this is an indirect function invocation or the function signa...
CallingConv::ID getCallingConv() const
User::op_iterator arg_begin()
Return the iterator pointing to the beginning of the argument list.
LLVM_ABI bool isMustTailCall() const
Tests if this call site must be tail call optimized.
bool isCallee(Value::const_user_iterator UI) const
Determine whether the passed iterator points to the callee operand's Use.
void setAttributes(AttributeList A)
Set the attributes for this call.
Value * getArgOperand(unsigned i) const
void setArgOperand(unsigned i, Value *v)
User::op_iterator arg_end()
Return the iterator pointing to the end of the argument list.
bool isBundleOperand(unsigned Idx) const
Return true if the operand at index Idx is a bundle operand.
FunctionType * getFunctionType() const
unsigned getArgOperandNo(const Use *U) const
Given a use for a arg operand, get the arg operand number that corresponds to it.
AttributeList getAttributes() const
Return the attributes for this call.
static CallInst * Create(FunctionType *Ty, Value *F, const Twine &NameStr="", InsertPosition InsertBefore=nullptr)
bool isMustTailCall() const
LLVM_ABI void removeDeadConstantUsers() const
If there are any dead constant users dangling off of this constant, remove them.
SmallVector< RetOrArg, 5 > UseVector
LLVM_ABI PreservedAnalyses run(Module &M, ModuleAnalysisManager &)
FuncSet FrozenRetTyFunctions
This set contains all functions that cannot change return type;.
Liveness
During our initial pass over the program, we determine that things are either alive or maybe alive.
LiveSet LiveValues
This set contains all values that have been determined to be live.
RetOrArg createRet(const Function *F, unsigned Idx)
Convenience wrapper.
RetOrArg createArg(const Function *F, unsigned Idx)
Convenience wrapper.
FuncSet FrozenFunctions
This set contains all functions that cannot be changed in any way.
UseMap Uses
This maps a return value or argument to any MaybeLive return values or arguments it uses.
static LLVM_ABI FunctionType * get(Type *Result, ArrayRef< Type * > Params, bool isVarArg)
This static method is the primary way of constructing a FunctionType.
static Function * Create(FunctionType *Ty, LinkageTypes Linkage, unsigned AddrSpace, const Twine &N="", Module *M=nullptr)
void splice(Function::iterator ToIt, Function *FromF)
Transfer all blocks from FromF to this function at ToIt.
void setAttributes(AttributeList Attrs)
Set the attribute list for this Function.
Type * getReturnType() const
Returns the type of the ret val.
const Argument * const_arg_iterator
void copyAttributesFrom(const Function *Src)
copyAttributesFrom - copy all additional attributes (those not needed to create a Function) from the ...
LLVM_ABI void setComdat(Comdat *C)
LLVM_ABI void addMetadata(unsigned KindID, MDNode &MD)
Add a metadata attachment.
static unsigned getAggregateOperandIndex()
LLVM_ABI InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
LLVM_ABI void copyMetadata(const Instruction &SrcInst, ArrayRef< unsigned > WL=ArrayRef< unsigned >())
Copy metadata from SrcInst to this instruction.
static InvokeInst * Create(FunctionType *Ty, Value *Func, BasicBlock *IfNormal, BasicBlock *IfException, ArrayRef< Value * > Args, const Twine &NameStr, InsertPosition InsertBefore=nullptr)
static std::enable_if_t< std::is_base_of< MDNode, T >::value, T * > replaceWithPermanent(std::unique_ptr< T, TempMDNodeDeleter > N)
Replace a temporary node with a permanent one.
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
A Module instance is used to store all the information related to an LLVM module.
static LLVM_ABI PoisonValue * get(Type *T)
Static factory methods - Return an 'poison' object of the specified type.
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
bool areAllPreserved() const
Test whether all analyses are preserved (and none are abandoned).
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
static ReturnInst * Create(LLVMContext &C, Value *retVal=nullptr, InsertPosition InsertBefore=nullptr)
void push_back(const T &Elt)
Class to represent struct types.
static LLVM_ABI StructType * get(LLVMContext &Context, ArrayRef< Type * > Elements, bool isPacked=false)
This static method is the primary way to create a literal StructType.
The instances of the Type class are immutable: once they are created, they are never changed.
bool isArrayTy() const
True if this is an instance of ArrayType.
static LLVM_ABI Type * getVoidTy(LLVMContext &C)
bool isStructTy() const
True if this is an instance of StructType.
bool isVoidTy() const
Return true if this is 'void'.
A Use represents the edge between a Value definition and its users.
Value * getOperand(unsigned i) const
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
bool isUsedByMetadata() const
Return true if there is metadata referencing this value.
iterator_range< use_iterator > uses()
LLVM_ABI void takeName(Value *V)
Transfer the name from V to this value.
const ParentTy * getParent() const
self_iterator getIterator()
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
constexpr char Attrs[]
Key for Kernel::Metadata::mAttrs.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
@ Tail
Attemps to make calls as fast as possible while guaranteeing that tail call optimization can always b...
@ SwiftTail
This follows the Swift calling convention in how arguments are passed but guarantees tail calls will ...
@ BasicBlock
Various leaf nodes.
@ User
could "use" a pointer
DiagnosticInfoOptimizationBase::Argument NV
NodeAddr< UseNode * > Use
friend class Instruction
Iterator for Instructions in a `BasicBlock.
This is an optimization pass for GlobalISel generic memory operations.
LLVM_ABI ModulePass * createDeadArgEliminationPass()
createDeadArgEliminationPass - This pass removes arguments from functions which are not used by the b...
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
IRBuilder(LLVMContext &, FolderTy, InserterTy, MDNode *, ArrayRef< OperandBundleDef >) -> IRBuilder< FolderTy, InserterTy >
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
LLVM_ABI BasicBlock * SplitEdge(BasicBlock *From, BasicBlock *To, DominatorTree *DT=nullptr, LoopInfo *LI=nullptr, MemorySSAUpdater *MSSAU=nullptr, const Twine &BBName="")
Split the edge connecting the specified blocks, and return the newly created basic block between From...
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.
Struct that represents (part of) either a return value or a function argument.