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

Duncan P. N. Exon Smith via llvm-commits llvm-commits at lists.llvm.org
Tue Apr 5 23:38:19 PDT 2016


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




More information about the llvm-commits mailing list