|
|
@@ -1,271 +0,0 @@ |
|
|
|
//===-- AMDILInliner.cpp - TODO: Add brief description -------===// |
|
|
|
// |
|
|
|
// The LLVM Compiler Infrastructure |
|
|
|
// |
|
|
|
// This file is distributed under the University of Illinois Open Source |
|
|
|
// License. See LICENSE.TXT for details. |
|
|
|
// |
|
|
|
//==-----------------------------------------------------------------------===// |
|
|
|
|
|
|
|
#define DEBUG_TYPE "amdilinline" |
|
|
|
#include "AMDIL.h" |
|
|
|
#include "AMDILCompilerErrors.h" |
|
|
|
#include "AMDILMachineFunctionInfo.h" |
|
|
|
#include "AMDILSubtarget.h" |
|
|
|
#include "llvm/ADT/SmallPtrSet.h" |
|
|
|
#include "llvm/ADT/SmallVector.h" |
|
|
|
#include "llvm/CodeGen/MachineFunction.h" |
|
|
|
#include "llvm/CodeGen/MachineFunctionAnalysis.h" |
|
|
|
#include "llvm/CodeGen/Passes.h" |
|
|
|
#include "llvm/Function.h" |
|
|
|
#include "llvm/Instructions.h" |
|
|
|
#include "llvm/IntrinsicInst.h" |
|
|
|
#include "llvm/Support/CallSite.h" |
|
|
|
#include "llvm/Support/Debug.h" |
|
|
|
#include "llvm/Support/raw_ostream.h" |
|
|
|
#include "llvm/Target/TargetData.h" |
|
|
|
#include "llvm/Target/TargetMachine.h" |
|
|
|
#include "llvm/Transforms/Utils/Cloning.h" |
|
|
|
#include "llvm/Transforms/Utils/Local.h" |
|
|
|
|
|
|
|
using namespace llvm; |
|
|
|
|
|
|
|
namespace |
|
|
|
{ |
|
|
|
class LLVM_LIBRARY_VISIBILITY AMDILInlinePass: public FunctionPass |
|
|
|
|
|
|
|
{ |
|
|
|
public: |
|
|
|
TargetMachine &TM; |
|
|
|
static char ID; |
|
|
|
AMDILInlinePass(TargetMachine &tm AMDIL_OPT_LEVEL_DECL); |
|
|
|
~AMDILInlinePass(); |
|
|
|
virtual const char* getPassName() const; |
|
|
|
virtual bool runOnFunction(Function &F); |
|
|
|
bool doInitialization(Module &M); |
|
|
|
bool doFinalization(Module &M); |
|
|
|
virtual void getAnalysisUsage(AnalysisUsage &AU) const; |
|
|
|
private: |
|
|
|
typedef DenseMap<const ArrayType*, SmallVector<AllocaInst*, |
|
|
|
DEFAULT_VEC_SLOTS> > InlinedArrayAllocasTy; |
|
|
|
bool |
|
|
|
AMDILInlineCallIfPossible(CallSite CS, |
|
|
|
const TargetData *TD, |
|
|
|
InlinedArrayAllocasTy &InlinedArrayAllocas); |
|
|
|
|
|
|
|
CodeGenOpt::Level OptLevel; |
|
|
|
}; |
|
|
|
char AMDILInlinePass::ID = 0; |
|
|
|
} // anonymouse namespace |
|
|
|
|
|
|
|
|
|
|
|
namespace llvm |
|
|
|
{ |
|
|
|
FunctionPass* |
|
|
|
createAMDILInlinePass(TargetMachine &tm AMDIL_OPT_LEVEL_DECL) |
|
|
|
{ |
|
|
|
return new AMDILInlinePass(tm AMDIL_OPT_LEVEL_VAR); |
|
|
|
} |
|
|
|
} // llvm namespace |
|
|
|
|
|
|
|
AMDILInlinePass::AMDILInlinePass(TargetMachine &tm AMDIL_OPT_LEVEL_DECL) |
|
|
|
: FunctionPass(ID), TM(tm) |
|
|
|
{ |
|
|
|
OptLevel = tm.getOptLevel(); |
|
|
|
} |
|
|
|
AMDILInlinePass::~AMDILInlinePass() |
|
|
|
{ |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
bool |
|
|
|
AMDILInlinePass::AMDILInlineCallIfPossible(CallSite CS, |
|
|
|
const TargetData *TD, InlinedArrayAllocasTy &InlinedArrayAllocas) { |
|
|
|
Function *Callee = CS.getCalledFunction(); |
|
|
|
Function *Caller = CS.getCaller(); |
|
|
|
|
|
|
|
// Try to inline the function. Get the list of static allocas that were |
|
|
|
// inlined. |
|
|
|
SmallVector<AllocaInst*, 16> StaticAllocas; |
|
|
|
InlineFunctionInfo IFI; |
|
|
|
if (!InlineFunction(CS, IFI)) |
|
|
|
return false; |
|
|
|
DEBUG(errs() << "<amdilinline> function " << Caller->getName() |
|
|
|
<< ": inlined call to "<< Callee->getName() << "\n"); |
|
|
|
|
|
|
|
// If the inlined function had a higher stack protection level than the |
|
|
|
// calling function, then bump up the caller's stack protection level. |
|
|
|
if (Callee->hasFnAttr(Attribute::StackProtectReq)) |
|
|
|
Caller->addFnAttr(Attribute::StackProtectReq); |
|
|
|
else if (Callee->hasFnAttr(Attribute::StackProtect) && |
|
|
|
!Caller->hasFnAttr(Attribute::StackProtectReq)) |
|
|
|
Caller->addFnAttr(Attribute::StackProtect); |
|
|
|
|
|
|
|
|
|
|
|
// Look at all of the allocas that we inlined through this call site. If we |
|
|
|
// have already inlined other allocas through other calls into this function, |
|
|
|
// then we know that they have disjoint lifetimes and that we can merge them. |
|
|
|
// |
|
|
|
// There are many heuristics possible for merging these allocas, and the |
|
|
|
// different options have different tradeoffs. One thing that we *really* |
|
|
|
// don't want to hurt is SRoA: once inlining happens, often allocas are no |
|
|
|
// longer address taken and so they can be promoted. |
|
|
|
// |
|
|
|
// Our "solution" for that is to only merge allocas whose outermost type is an |
|
|
|
// array type. These are usually not promoted because someone is using a |
|
|
|
// variable index into them. These are also often the most important ones to |
|
|
|
// merge. |
|
|
|
// |
|
|
|
// A better solution would be to have real memory lifetime markers in the IR |
|
|
|
// and not have the inliner do any merging of allocas at all. This would |
|
|
|
// allow the backend to do proper stack slot coloring of all allocas that |
|
|
|
// *actually make it to the backend*, which is really what we want. |
|
|
|
// |
|
|
|
// Because we don't have this information, we do this simple and useful hack. |
|
|
|
// |
|
|
|
SmallPtrSet<AllocaInst*, 16> UsedAllocas; |
|
|
|
|
|
|
|
// Loop over all the allocas we have so far and see if they can be merged with |
|
|
|
// a previously inlined alloca. If not, remember that we had it. |
|
|
|
|
|
|
|
for (unsigned AllocaNo = 0, |
|
|
|
e = IFI.StaticAllocas.size(); |
|
|
|
AllocaNo != e; ++AllocaNo) { |
|
|
|
|
|
|
|
AllocaInst *AI = IFI.StaticAllocas[AllocaNo]; |
|
|
|
|
|
|
|
// Don't bother trying to merge array allocations (they will usually be |
|
|
|
// canonicalized to be an allocation *of* an array), or allocations whose |
|
|
|
// type is not itself an array (because we're afraid of pessimizing SRoA). |
|
|
|
const ArrayType *ATy = dyn_cast<ArrayType>(AI->getAllocatedType()); |
|
|
|
if (ATy == 0 || AI->isArrayAllocation()) |
|
|
|
continue; |
|
|
|
|
|
|
|
// Get the list of all available allocas for this array type. |
|
|
|
SmallVector<AllocaInst*, DEFAULT_VEC_SLOTS> &AllocasForType |
|
|
|
= InlinedArrayAllocas[ATy]; |
|
|
|
|
|
|
|
// Loop over the allocas in AllocasForType to see if we can reuse one. Note |
|
|
|
// that we have to be careful not to reuse the same "available" alloca for |
|
|
|
// multiple different allocas that we just inlined, we use the 'UsedAllocas' |
|
|
|
// set to keep track of which "available" allocas are being used by this |
|
|
|
// function. Also, AllocasForType can be empty of course! |
|
|
|
bool MergedAwayAlloca = false; |
|
|
|
for (unsigned i = 0, e = AllocasForType.size(); i != e; ++i) { |
|
|
|
AllocaInst *AvailableAlloca = AllocasForType[i]; |
|
|
|
|
|
|
|
// The available alloca has to be in the right function, not in some other |
|
|
|
// function in this SCC. |
|
|
|
if (AvailableAlloca->getParent() != AI->getParent()) |
|
|
|
continue; |
|
|
|
|
|
|
|
// If the inlined function already uses this alloca then we can't reuse |
|
|
|
// it. |
|
|
|
if (!UsedAllocas.insert(AvailableAlloca)) |
|
|
|
continue; |
|
|
|
|
|
|
|
// Otherwise, we *can* reuse it, RAUW AI into AvailableAlloca and declare |
|
|
|
// success! |
|
|
|
DEBUG(errs() << " ***MERGED ALLOCA: " << *AI); |
|
|
|
|
|
|
|
AI->replaceAllUsesWith(AvailableAlloca); |
|
|
|
AI->eraseFromParent(); |
|
|
|
MergedAwayAlloca = true; |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
// If we already nuked the alloca, we're done with it. |
|
|
|
if (MergedAwayAlloca) |
|
|
|
continue; |
|
|
|
|
|
|
|
// If we were unable to merge away the alloca either because there are no |
|
|
|
// allocas of the right type available or because we reused them all |
|
|
|
// already, remember that this alloca came from an inlined function and mark |
|
|
|
// it used so we don't reuse it for other allocas from this inline |
|
|
|
// operation. |
|
|
|
AllocasForType.push_back(AI); |
|
|
|
UsedAllocas.insert(AI); |
|
|
|
} |
|
|
|
|
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
bool |
|
|
|
AMDILInlinePass::runOnFunction(Function &MF) |
|
|
|
{ |
|
|
|
Function *F = &MF; |
|
|
|
const AMDILSubtarget &STM = TM.getSubtarget<AMDILSubtarget>(); |
|
|
|
if (STM.device()->isSupported(AMDILDeviceInfo::NoInline)) { |
|
|
|
return false; |
|
|
|
} |
|
|
|
const TargetData *TD = getAnalysisIfAvailable<TargetData>(); |
|
|
|
SmallVector<CallSite, 16> CallSites; |
|
|
|
for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) { |
|
|
|
for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I) { |
|
|
|
CallSite CS = CallSite(cast<Value>(I)); |
|
|
|
// If this isn't a call, or it is a call to an intrinsic, it can |
|
|
|
// never be inlined. |
|
|
|
if (CS.getInstruction() == 0 || isa<IntrinsicInst>(I)) |
|
|
|
continue; |
|
|
|
|
|
|
|
// If this is a direct call to an external function, we can never inline |
|
|
|
// it. If it is an indirect call, inlining may resolve it to be a |
|
|
|
// direct call, so we keep it. |
|
|
|
if (CS.getCalledFunction() && CS.getCalledFunction()->isDeclaration()) |
|
|
|
continue; |
|
|
|
|
|
|
|
// We don't want to inline if we are recursive. |
|
|
|
if (CS.getCalledFunction() && CS.getCalledFunction()->getName() == MF.getName()) { |
|
|
|
AMDILMachineFunctionInfo *MFI = |
|
|
|
getAnalysis<MachineFunctionAnalysis>().getMF() |
|
|
|
.getInfo<AMDILMachineFunctionInfo>(); |
|
|
|
MFI->addErrorMsg(amd::CompilerErrorMessage[RECURSIVE_FUNCTION]); |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
CallSites.push_back(CS); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
InlinedArrayAllocasTy InlinedArrayAllocas; |
|
|
|
bool Changed = false; |
|
|
|
for (unsigned CSi = 0; CSi != CallSites.size(); ++CSi) { |
|
|
|
CallSite CS = CallSites[CSi]; |
|
|
|
|
|
|
|
Function *Callee = CS.getCalledFunction(); |
|
|
|
|
|
|
|
// We can only inline direct calls to non-declarations. |
|
|
|
if (Callee == 0 || Callee->isDeclaration()) continue; |
|
|
|
|
|
|
|
// Attempt to inline the function... |
|
|
|
if (!AMDILInlineCallIfPossible(CS, TD, InlinedArrayAllocas)) |
|
|
|
continue; |
|
|
|
Changed = true; |
|
|
|
} |
|
|
|
return Changed; |
|
|
|
} |
|
|
|
|
|
|
|
const char* |
|
|
|
AMDILInlinePass::getPassName() const |
|
|
|
{ |
|
|
|
return "AMDIL Inline Function Pass"; |
|
|
|
} |
|
|
|
bool |
|
|
|
AMDILInlinePass::doInitialization(Module &M) |
|
|
|
{ |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
bool |
|
|
|
AMDILInlinePass::doFinalization(Module &M) |
|
|
|
{ |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
void |
|
|
|
AMDILInlinePass::getAnalysisUsage(AnalysisUsage &AU) const |
|
|
|
{ |
|
|
|
AU.addRequired<MachineFunctionAnalysis>(); |
|
|
|
FunctionPass::getAnalysisUsage(AU); |
|
|
|
AU.setPreservesAll(); |
|
|
|
} |