[llvm] r265519 - IRMover: Steal arguments when moving functions, NFC

Rafael EspĂ­ndola via llvm-commits llvm-commits at lists.llvm.org
Wed Apr 6 07:51:12 PDT 2016


Thanks!

On 6 April 2016 at 02:38, Duncan P. N. Exon Smith via llvm-commits
<llvm-commits at lists.llvm.org> wrote:
> Author: dexonsmith
> Date: Wed Apr  6 01:38:15 2016
> New Revision: 265519
>
> URL: http://llvm.org/viewvc/llvm-project?rev=265519&view=rev
> Log:
> IRMover: Steal arguments when moving functions, NFC
>
> Instead of copying arguments from the source function to the
> destination, steal them.  This has a few advantages.
>
>   - The ValueMap doesn't need to be seeded with (or cleared of)
>     Arguments.
>
>   - Often the destination function won't have created any arguments yet,
>     so this avoids malloc traffic.
>
>   - Argument names don't need to be copied.
>
> Because argument lists are lazy, this required a new
> Function::stealArgumentListFrom helper.
>
> Added:
>     llvm/trunk/unittests/IR/FunctionTest.cpp
> Modified:
>     llvm/trunk/include/llvm/IR/Function.h
>     llvm/trunk/lib/IR/Function.cpp
>     llvm/trunk/lib/Linker/IRMover.cpp
>     llvm/trunk/unittests/IR/CMakeLists.txt
>
> Modified: llvm/trunk/include/llvm/IR/Function.h
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/Function.h?rev=265519&r1=265518&r2=265519&view=diff
> ==============================================================================
> --- llvm/trunk/include/llvm/IR/Function.h (original)
> +++ llvm/trunk/include/llvm/IR/Function.h Wed Apr  6 01:38:15 2016
> @@ -88,9 +88,12 @@ private:
>    /// built on demand, so that the list isn't allocated until the first client
>    /// needs it.  The hasLazyArguments predicate returns true if the arg list
>    /// hasn't been set up yet.
> +public:
>    bool hasLazyArguments() const {
>      return getSubclassDataFromValue() & (1<<0);
>    }
> +
> +private:
>    void CheckLazyArguments() const {
>      if (hasLazyArguments())
>        BuildLazyArguments();
> @@ -442,6 +445,12 @@ public:
>    ///
>    void eraseFromParent() override;
>
> +  /// Steal arguments from another function.
> +  ///
> +  /// Drop this function's arguments and splice in the ones from \c Src.
> +  /// Requires that this has no function body.
> +  void stealArgumentListFrom(Function &Src);
> +
>    /// Get the underlying elements of the Function... the basic block list is
>    /// empty for external functions.
>    ///
>
> Modified: llvm/trunk/lib/IR/Function.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/Function.cpp?rev=265519&r1=265518&r2=265519&view=diff
> ==============================================================================
> --- llvm/trunk/lib/IR/Function.cpp (original)
> +++ llvm/trunk/lib/IR/Function.cpp Wed Apr  6 01:38:15 2016
> @@ -302,6 +302,28 @@ void Function::BuildLazyArguments() cons
>    const_cast<Function*>(this)->setValueSubclassData(SDC &= ~(1<<0));
>  }
>
> +void Function::stealArgumentListFrom(Function &Src) {
> +  assert(isDeclaration() && "Expected no references to current arguments");
> +
> +  // Drop the current arguments, if any, and set the lazy argument bit.
> +  if (!hasLazyArguments()) {
> +    assert(llvm::all_of(ArgumentList,
> +                        [](const Argument &A) { return A.use_empty(); }) &&
> +           "Expected arguments to be unused in declaration");
> +    ArgumentList.clear();
> +    setValueSubclassData(getSubclassDataFromValue() | (1 << 0));
> +  }
> +
> +  // Nothing to steal if Src has lazy arguments.
> +  if (Src.hasLazyArguments())
> +    return;
> +
> +  // Steal arguments from Src, and fix the lazy argument bits.
> +  ArgumentList.splice(ArgumentList.end(), Src.ArgumentList);
> +  setValueSubclassData(getSubclassDataFromValue() & ~(1 << 0));
> +  Src.setValueSubclassData(Src.getSubclassDataFromValue() | (1 << 0));
> +}
> +
>  size_t Function::arg_size() const {
>    return getFunctionType()->getNumParams();
>  }
>
> Modified: llvm/trunk/lib/Linker/IRMover.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Linker/IRMover.cpp?rev=265519&r1=265518&r2=265519&view=diff
> ==============================================================================
> --- llvm/trunk/lib/Linker/IRMover.cpp (original)
> +++ llvm/trunk/lib/Linker/IRMover.cpp Wed Apr  6 01:38:15 2016
> @@ -980,16 +980,6 @@ bool IRLinker::linkFunctionBody(Function
>                                    ValueMapperFlags, &TypeMap,
>                                    &GValMaterializer));
>
> -  // Go through and convert function arguments over, remembering the mapping.
> -  Function::arg_iterator DI = Dst.arg_begin();
> -  for (Argument &Arg : Src.args()) {
> -    DI->setName(Arg.getName()); // Copy the name over.
> -
> -    // Add a mapping to our mapping.
> -    ValueMap[&Arg] = &*DI;
> -    ++DI;
> -  }
> -
>    // Copy over the metadata attachments.
>    SmallVector<std::pair<unsigned, MDNode *>, 8> MDs;
>    Src.getAllMetadata(MDs);
> @@ -997,22 +987,19 @@ bool IRLinker::linkFunctionBody(Function
>      Dst.setMetadata(I.first, MapMetadata(I.second, ValueMap, ValueMapperFlags,
>                                           &TypeMap, &GValMaterializer));
>
> -  // Splice the body of the source function into the dest function.
> +  // Steal arguments and splice the body of Src into Dst.
> +  Dst.stealArgumentListFrom(Src);
>    Dst.getBasicBlockList().splice(Dst.end(), Src.getBasicBlockList());
>
> -  // At this point, all of the instructions and values of the function are now
> -  // copied over.  The only problem is that they are still referencing values in
> -  // the Source function as operands.  Loop through all of the operands of the
> -  // functions and patch them up to point to the local versions.
> +  // At this point, everything has been moved over, but the types and non-local
> +  // operands will be wrong.  Loop through everything and patch it up.
> +  for (Argument &A : Dst.args())
> +    A.mutateType(TypeMap.get(A.getType()));
>    for (BasicBlock &BB : Dst)
>      for (Instruction &I : BB)
>        RemapInstruction(&I, ValueMap, RF_IgnoreMissingEntries | ValueMapperFlags,
>                         &TypeMap, &GValMaterializer);
>
> -  // There is no need to map the arguments anymore.
> -  for (Argument &Arg : Src.args())
> -    ValueMap.erase(&Arg);
> -
>    return false;
>  }
>
>
> Modified: llvm/trunk/unittests/IR/CMakeLists.txt
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/IR/CMakeLists.txt?rev=265519&r1=265518&r2=265519&view=diff
> ==============================================================================
> --- llvm/trunk/unittests/IR/CMakeLists.txt (original)
> +++ llvm/trunk/unittests/IR/CMakeLists.txt Wed Apr  6 01:38:15 2016
> @@ -12,6 +12,7 @@ set(IRSources
>    ConstantsTest.cpp
>    DebugInfoTest.cpp
>    DominatorTreeTest.cpp
> +  FunctionTest.cpp
>    IRBuilderTest.cpp
>    InstructionsTest.cpp
>    IntrinsicsTest.cpp
>
> Added: llvm/trunk/unittests/IR/FunctionTest.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/IR/FunctionTest.cpp?rev=265519&view=auto
> ==============================================================================
> --- llvm/trunk/unittests/IR/FunctionTest.cpp (added)
> +++ llvm/trunk/unittests/IR/FunctionTest.cpp Wed Apr  6 01:38:15 2016
> @@ -0,0 +1,106 @@
> +//===- FunctionTest.cpp - Function unit tests -----------------------------===//
> +//
> +//                     The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
> +
> +#include "llvm/IR/Function.h"
> +#include "gtest/gtest.h"
> +using namespace llvm;
> +
> +namespace {
> +
> +TEST(FunctionTest, hasLazyArguments) {
> +  LLVMContext C;
> +
> +  Type *ArgTypes[] = {Type::getInt8Ty(C), Type::getInt32Ty(C)};
> +  FunctionType *FTy = FunctionType::get(Type::getVoidTy(C), ArgTypes, false);
> +
> +  // Functions start out with lazy arguments.
> +  std::unique_ptr<Function> F(
> +      Function::Create(FTy, GlobalValue::ExternalLinkage, "F"));
> +  EXPECT_TRUE(F->hasLazyArguments());
> +
> +  // Checking for empty or size shouldn't force arguments to be instantiated.
> +  EXPECT_FALSE(F->arg_empty());
> +  EXPECT_TRUE(F->hasLazyArguments());
> +  EXPECT_EQ(2u, F->arg_size());
> +  EXPECT_TRUE(F->hasLazyArguments());
> +
> +  // The argument list should be populated at first access.
> +  (void)F->arg_begin();
> +  EXPECT_FALSE(F->hasLazyArguments());
> +}
> +
> +TEST(FunctionTest, stealArgumentListFrom) {
> +  LLVMContext C;
> +
> +  Type *ArgTypes[] = {Type::getInt8Ty(C), Type::getInt32Ty(C)};
> +  FunctionType *FTy = FunctionType::get(Type::getVoidTy(C), ArgTypes, false);
> +  std::unique_ptr<Function> F1(
> +      Function::Create(FTy, GlobalValue::ExternalLinkage, "F1"));
> +  std::unique_ptr<Function> F2(
> +      Function::Create(FTy, GlobalValue::ExternalLinkage, "F1"));
> +  EXPECT_TRUE(F1->hasLazyArguments());
> +  EXPECT_TRUE(F2->hasLazyArguments());
> +
> +  // Steal arguments before they've been accessed.  Nothing should change; both
> +  // functions should still have lazy arguments.
> +  //
> +  //   steal(empty); drop (empty)
> +  F1->stealArgumentListFrom(*F2);
> +  EXPECT_TRUE(F1->hasLazyArguments());
> +  EXPECT_TRUE(F2->hasLazyArguments());
> +
> +  // Save arguments from F1 for later assertions.  F1 won't have lazy arguments
> +  // anymore.
> +  SmallVector<Argument *, 4> Args;
> +  for (Argument &A : F1->args())
> +    Args.push_back(&A);
> +  EXPECT_EQ(2u, Args.size());
> +  EXPECT_FALSE(F1->hasLazyArguments());
> +
> +  // Steal arguments from F1 to F2.  F1's arguments should be lazy again.
> +  //
> +  //   steal(real); drop (empty)
> +  F2->stealArgumentListFrom(*F1);
> +  EXPECT_TRUE(F1->hasLazyArguments());
> +  EXPECT_FALSE(F2->hasLazyArguments());
> +  unsigned I = 0;
> +  for (Argument &A : F2->args())
> +    EXPECT_EQ(Args[I++], &A);
> +  EXPECT_EQ(2u, I);
> +
> +  // Check that arguments in F1 don't have pointer equality with the saved ones.
> +  // This also instantiates F1's arguments.
> +  I = 0;
> +  for (Argument &A : F1->args())
> +    EXPECT_NE(Args[I++], &A);
> +  EXPECT_EQ(2u, I);
> +  EXPECT_FALSE(F1->hasLazyArguments());
> +  EXPECT_FALSE(F2->hasLazyArguments());
> +
> +  // Steal back from F2.  F2's arguments should be lazy again.
> +  //
> +  //   steal(real); drop (real)
> +  F1->stealArgumentListFrom(*F2);
> +  EXPECT_FALSE(F1->hasLazyArguments());
> +  EXPECT_TRUE(F2->hasLazyArguments());
> +  I = 0;
> +  for (Argument &A : F1->args())
> +    EXPECT_EQ(Args[I++], &A);
> +  EXPECT_EQ(2u, I);
> +
> +  // Steal from F2 a second time.  Now both functions should have lazy
> +  // arguments.
> +  //
> +  //   steal(empty); drop (real)
> +  F1->stealArgumentListFrom(*F2);
> +  EXPECT_TRUE(F1->hasLazyArguments());
> +  EXPECT_TRUE(F2->hasLazyArguments());
> +}
> +
> +} // end namespace
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits


More information about the llvm-commits mailing list