diff options
Diffstat (limited to 'llvm')
| -rw-r--r-- | llvm/lib/Transforms/IPO/ArgumentPromotion.cpp | 220 | ||||
| -rw-r--r-- | llvm/test/Transforms/ArgumentPromotion/byval.ll | 24 | 
2 files changed, 174 insertions, 70 deletions
diff --git a/llvm/lib/Transforms/IPO/ArgumentPromotion.cpp b/llvm/lib/Transforms/IPO/ArgumentPromotion.cpp index dc61a883542..9acd516123d 100644 --- a/llvm/lib/Transforms/IPO/ArgumentPromotion.cpp +++ b/llvm/lib/Transforms/IPO/ArgumentPromotion.cpp @@ -51,6 +51,7 @@ using namespace llvm;  STATISTIC(NumArgumentsPromoted , "Number of pointer arguments promoted");  STATISTIC(NumAggregatesPromoted, "Number of aggregate arguments promoted"); +STATISTIC(NumByValArgsPromoted , "Number of byval arguments promoted");  STATISTIC(NumArgumentsDead     , "Number of dead pointer args eliminated");  namespace { @@ -71,7 +72,8 @@ namespace {      bool PromoteArguments(CallGraphNode *CGN);      bool isSafeToPromoteArgument(Argument *Arg, bool isByVal) const;      Function *DoPromotion(Function *F,  -                          SmallPtrSet<Argument*, 8> &ArgsToPromote); +                          SmallPtrSet<Argument*, 8> &ArgsToPromote, +                          SmallPtrSet<Argument*, 8> &ByValArgsToTransform);    };    char ArgPromotion::ID = 0; @@ -134,16 +136,44 @@ bool ArgPromotion::PromoteArguments(CallGraphNode *CGN) {    // Check to see which arguments are promotable.  If an argument is promotable,    // add it to ArgsToPromote.    SmallPtrSet<Argument*, 8> ArgsToPromote; +  SmallPtrSet<Argument*, 8> ByValArgsToTransform;    for (unsigned i = 0; i != PointerArgs.size(); ++i) { -    bool isByVal = F->paramHasAttr(PointerArgs[i].second, ParamAttr::ByVal); -    if (isSafeToPromoteArgument(PointerArgs[i].first, isByVal)) -      ArgsToPromote.insert(PointerArgs[i].first); +    bool isByVal = F->paramHasAttr(PointerArgs[i].second+1, ParamAttr::ByVal); +     +    // If this is a byval argument, and if the aggregate type is small, just +    // pass the elements, which is always safe. +    Argument *PtrArg = PointerArgs[i].first; +    if (isByVal) { +      const Type *AgTy = cast<PointerType>(PtrArg->getType())->getElementType(); +      if (const StructType *STy = dyn_cast<StructType>(AgTy)) +        if (STy->getNumElements() <= 3) { +          // If all the elements are first class types, we can promote it. +          bool AllSimple = true; +          for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) +            if (!STy->getElementType(i)->isFirstClassType()) { +              AllSimple = false; +              break; +            } +           +          // Safe to transform, don't even bother trying to "promote" it. +          // Passing the elements as a scalar will allow scalarrepl to hack on +          // the new alloca we introduce. +          if (AllSimple) { +            ByValArgsToTransform.insert(PtrArg); +            continue; +          } +        } +    } +     +    // Otherwise, see if we can promote the pointer to its value. +    if (isSafeToPromoteArgument(PtrArg, isByVal)) +      ArgsToPromote.insert(PtrArg);    }    // No promotable pointer arguments. -  if (ArgsToPromote.empty()) return false; +  if (ArgsToPromote.empty() && ByValArgsToTransform.empty()) return false; -  Function *NewF = DoPromotion(F, ArgsToPromote); +  Function *NewF = DoPromotion(F, ArgsToPromote, ByValArgsToTransform);    // Update the call graph to know that the function has been transformed.    getAnalysis<CallGraph>().changeFunction(F, NewF); @@ -344,7 +374,8 @@ namespace {  /// arguments, and returns the new function.  At this point, we know that it's  /// safe to do so.  Function *ArgPromotion::DoPromotion(Function *F, -                                    SmallPtrSet<Argument*, 8> &ArgsToPromote) { +                                    SmallPtrSet<Argument*, 8> &ArgsToPromote, +                              SmallPtrSet<Argument*, 8> &ByValArgsToTransform) {    // Start by computing a new prototype for the function, which is the same as    // the old function, but has modified arguments. @@ -375,15 +406,18 @@ Function *ArgPromotion::DoPromotion(Function *F,    unsigned index = 1;    for (Function::arg_iterator I = F->arg_begin(), E = F->arg_end(); I != E; -       ++I, ++index) -    if (!ArgsToPromote.count(I)) { +       ++I, ++index) { +    if (ByValArgsToTransform.count(I)) { +      // Just add all the struct element types. +      const Type *AgTy = cast<PointerType>(I->getType())->getElementType(); +      const StructType *STy = cast<StructType>(AgTy); +      for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) +        Params.push_back(STy->getElementType(i)); +      ++NumByValArgsPromoted; +    } else if (!ArgsToPromote.count(I)) {        Params.push_back(I->getType()); -      if (PAL) { -        unsigned attrs = PAL->getParamAttrs(index); -        if (attrs) -          ParamAttrsVec.push_back(ParamAttrsWithIndex::get(Params.size(), -                                  attrs)); -      } +      if (unsigned attrs = PAL ? PAL->getParamAttrs(index) : 0) +        ParamAttrsVec.push_back(ParamAttrsWithIndex::get(Params.size(), attrs));      } else if (I->use_empty()) {        ++NumArgumentsDead;      } else { @@ -416,6 +450,7 @@ Function *ArgPromotion::DoPromotion(Function *F,        else          ++NumAggregatesPromoted;      } +  }    const Type *RetTy = FTy->getReturnType(); @@ -462,9 +497,22 @@ Function *ArgPromotion::DoPromotion(Function *F,      CallSite::arg_iterator AI = CS.arg_begin();      for (Function::arg_iterator I = F->arg_begin(), E = F->arg_end();           I != E; ++I, ++AI) -      if (!ArgsToPromote.count(I)) +      if (!ArgsToPromote.count(I) && !ByValArgsToTransform.count(I)) {          Args.push_back(*AI);          // Unmodified argument -      else if (!I->use_empty()) { +      } else if (ByValArgsToTransform.count(I)) { +        // Emit a GEP and load for each element of the struct. +        const Type *AgTy = cast<PointerType>(I->getType())->getElementType(); +        const StructType *STy = cast<StructType>(AgTy); +        Value *Idxs[2] = { ConstantInt::get(Type::Int32Ty, 0), 0 }; +        for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) { +          Idxs[1] = ConstantInt::get(Type::Int32Ty, i); +          Value *Idx = new GetElementPtrInst(*AI, Idxs, Idxs+2, +                                             (*AI)->getName()+"."+utostr(i), +                                             Call); +          // TODO: Tell AA about the new values? +          Args.push_back(new LoadInst(Idx, Idx->getName()+".val", Call)); +        }         +      } else if (!I->use_empty()) {          // Non-dead argument: insert GEPs and loads as appropriate.          ScalarizeTable &ArgIndices = ScalarizedElements[I];          for (ScalarizeTable::iterator SI = ArgIndices.begin(), @@ -526,71 +574,103 @@ Function *ArgPromotion::DoPromotion(Function *F,    // the new arguments, also transfering over the names as well.    //    for (Function::arg_iterator I = F->arg_begin(), E = F->arg_end(), -       I2 = NF->arg_begin(); I != E; ++I) -    if (!ArgsToPromote.count(I)) { +       I2 = NF->arg_begin(); I != E; ++I) { +    if (!ArgsToPromote.count(I) && !ByValArgsToTransform.count(I)) {        // If this is an unmodified argument, move the name and users over to the        // new version.        I->replaceAllUsesWith(I2);        I2->takeName(I);        AA.replaceWithNewValue(I, I2);        ++I2; -    } else if (I->use_empty()) { +      continue; +    } +     +    if (ByValArgsToTransform.count(I)) { +      // In the callee, we create an alloca, and store each of the new incoming +      // arguments into the alloca. +      Instruction *InsertPt = NF->begin()->begin(); +       +      // Just add all the struct element types. +      const Type *AgTy = cast<PointerType>(I->getType())->getElementType(); +      Value *TheAlloca = new AllocaInst(AgTy, 0, "", InsertPt); +      const StructType *STy = cast<StructType>(AgTy); +      Value *Idxs[2] = { ConstantInt::get(Type::Int32Ty, 0), 0 }; +       +      for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) { +        Idxs[1] = ConstantInt::get(Type::Int32Ty, i); +        Value *Idx = new GetElementPtrInst(TheAlloca, Idxs, Idxs+2, +                                           TheAlloca->getName()+"."+utostr(i), +                                           InsertPt); +        I2->setName(I->getName()+"."+utostr(i)); +        new StoreInst(I2++, Idx, InsertPt); +      } +       +      // Anything that used the arg should now use the alloca. +      I->replaceAllUsesWith(TheAlloca); +      TheAlloca->takeName(I); +      AA.replaceWithNewValue(I, TheAlloca); +      continue; +    }  +     +    if (I->use_empty()) {        AA.deleteValue(I); -    } else { -      // Otherwise, if we promoted this argument, then all users are load -      // instructions, and all loads should be using the new argument that we -      // added. -      ScalarizeTable &ArgIndices = ScalarizedElements[I]; - -      while (!I->use_empty()) { -        if (LoadInst *LI = dyn_cast<LoadInst>(I->use_back())) { -          assert(ArgIndices.begin()->empty() && -                 "Load element should sort to front!"); -          I2->setName(I->getName()+".val"); -          LI->replaceAllUsesWith(I2); -          AA.replaceWithNewValue(LI, I2); -          LI->eraseFromParent(); -          DOUT << "*** Promoted load of argument '" << I->getName() -               << "' in function '" << F->getName() << "'\n"; -        } else { -          GetElementPtrInst *GEP = cast<GetElementPtrInst>(I->use_back()); -          std::vector<Value*> Operands(GEP->op_begin()+1, GEP->op_end()); - -          Function::arg_iterator TheArg = I2; -          for (ScalarizeTable::iterator It = ArgIndices.begin(); -               *It != Operands; ++It, ++TheArg) { -            assert(It != ArgIndices.end() && "GEP not handled??"); -          } +      continue; +    } +     +    // Otherwise, if we promoted this argument, then all users are load +    // instructions, and all loads should be using the new argument that we +    // added. +    ScalarizeTable &ArgIndices = ScalarizedElements[I]; + +    while (!I->use_empty()) { +      if (LoadInst *LI = dyn_cast<LoadInst>(I->use_back())) { +        assert(ArgIndices.begin()->empty() && +               "Load element should sort to front!"); +        I2->setName(I->getName()+".val"); +        LI->replaceAllUsesWith(I2); +        AA.replaceWithNewValue(LI, I2); +        LI->eraseFromParent(); +        DOUT << "*** Promoted load of argument '" << I->getName() +             << "' in function '" << F->getName() << "'\n"; +      } else { +        GetElementPtrInst *GEP = cast<GetElementPtrInst>(I->use_back()); +        std::vector<Value*> Operands(GEP->op_begin()+1, GEP->op_end()); + +        Function::arg_iterator TheArg = I2; +        for (ScalarizeTable::iterator It = ArgIndices.begin(); +             *It != Operands; ++It, ++TheArg) { +          assert(It != ArgIndices.end() && "GEP not handled??"); +        } -          std::string NewName = I->getName(); -          for (unsigned i = 0, e = Operands.size(); i != e; ++i) -            if (ConstantInt *CI = dyn_cast<ConstantInt>(Operands[i])) -              NewName += "." + CI->getValue().toStringUnsigned(10); -            else -              NewName += ".x"; -          TheArg->setName(NewName+".val"); - -          DOUT << "*** Promoted agg argument '" << TheArg->getName() -               << "' of function '" << F->getName() << "'\n"; - -          // All of the uses must be load instructions.  Replace them all with -          // the argument specified by ArgNo. -          while (!GEP->use_empty()) { -            LoadInst *L = cast<LoadInst>(GEP->use_back()); -            L->replaceAllUsesWith(TheArg); -            AA.replaceWithNewValue(L, TheArg); -            L->eraseFromParent(); -          } -          AA.deleteValue(GEP); -          GEP->eraseFromParent(); +        std::string NewName = I->getName(); +        for (unsigned i = 0, e = Operands.size(); i != e; ++i) +          if (ConstantInt *CI = dyn_cast<ConstantInt>(Operands[i])) +            NewName += "." + CI->getValue().toStringUnsigned(10); +          else +            NewName += ".x"; +        TheArg->setName(NewName+".val"); + +        DOUT << "*** Promoted agg argument '" << TheArg->getName() +             << "' of function '" << F->getName() << "'\n"; + +        // All of the uses must be load instructions.  Replace them all with +        // the argument specified by ArgNo. +        while (!GEP->use_empty()) { +          LoadInst *L = cast<LoadInst>(GEP->use_back()); +          L->replaceAllUsesWith(TheArg); +          AA.replaceWithNewValue(L, TheArg); +          L->eraseFromParent();          } +        AA.deleteValue(GEP); +        GEP->eraseFromParent();        } - -      // Increment I2 past all of the arguments added for this promoted pointer. -      for (unsigned i = 0, e = ArgIndices.size(); i != e; ++i) -        ++I2;      } +    // Increment I2 past all of the arguments added for this promoted pointer. +    for (unsigned i = 0, e = ArgIndices.size(); i != e; ++i) +      ++I2; +  } +    // Notify the alias analysis implementation that we inserted a new argument.    if (ExtraArgHack)      AA.copyValue(Constant::getNullValue(Type::Int32Ty), NF->arg_begin()); diff --git a/llvm/test/Transforms/ArgumentPromotion/byval.ll b/llvm/test/Transforms/ArgumentPromotion/byval.ll new file mode 100644 index 00000000000..3a3458f3d94 --- /dev/null +++ b/llvm/test/Transforms/ArgumentPromotion/byval.ll @@ -0,0 +1,24 @@ +; RUN: llvm-as < %s | opt -argpromotion -scalarrepl | llvm-dis | not grep load +; Argpromote + scalarrepl should change this to passing the two integers by value. + +	%struct.ss = type { i32, i64 } + +define internal void @f(%struct.ss* byval  %b) nounwind  { +entry: +	%tmp = getelementptr %struct.ss* %b, i32 0, i32 0		; <i32*> [#uses=2] +	%tmp1 = load i32* %tmp, align 4		; <i32> [#uses=1] +	%tmp2 = add i32 %tmp1, 1		; <i32> [#uses=1] +	store i32 %tmp2, i32* %tmp, align 4 +	ret void +} + +define i32 @main() nounwind  { +entry: +	%S = alloca %struct.ss		; <%struct.ss*> [#uses=4] +	%tmp1 = getelementptr %struct.ss* %S, i32 0, i32 0		; <i32*> [#uses=1] +	store i32 1, i32* %tmp1, align 8 +	%tmp4 = getelementptr %struct.ss* %S, i32 0, i32 1		; <i64*> [#uses=1] +	store i64 2, i64* %tmp4, align 4 +	call void @f( %struct.ss* byval  %S ) nounwind  +	ret i32 0 +}  | 

