[attrs] Split off the forced attributes utility into its own pass that
authorChandler Carruth <chandlerc@gmail.com>
Sun, 27 Dec 2015 08:13:45 +0000 (08:13 +0000)
committerChandler Carruth <chandlerc@gmail.com>
Sun, 27 Dec 2015 08:13:45 +0000 (08:13 +0000)
is (by default) run much earlier than FuncitonAttrs proper.

This allows forcing optnone or other widely impactful attributes. It is
also a bit simpler as the force attribute behavior needs no specific
iteration order.

I've added the pass into the default module pass pipeline and LTO pass
pipeline which mirrors where function attrs itself was being run.

Differential Revision: http://reviews.llvm.org/D15668

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@256465 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/InitializePasses.h
include/llvm/Transforms/IPO/ForceFunctionAttrs.h [new file with mode: 0644]
lib/Passes/PassBuilder.cpp
lib/Passes/PassRegistry.def
lib/Transforms/IPO/CMakeLists.txt
lib/Transforms/IPO/ForceFunctionAttrs.cpp [new file with mode: 0644]
lib/Transforms/IPO/FunctionAttrs.cpp
lib/Transforms/IPO/IPO.cpp
lib/Transforms/IPO/PassManagerBuilder.cpp
test/Transforms/ForcedFunctionAttrs/forced.ll [new file with mode: 0644]
test/Transforms/FunctionAttrs/forced.ll [deleted file]

index 2bec347e0e9d81b99463370d96a67b6a53fa8bb3..21002a9e1a6c4e1097114757f78191edc4634d23 100644 (file)
@@ -131,6 +131,7 @@ void initializeScalarizerPass(PassRegistry&);
 void initializeEarlyCSELegacyPassPass(PassRegistry &);
 void initializeEliminateAvailableExternallyPass(PassRegistry&);
 void initializeExpandISelPseudosPass(PassRegistry&);
+void initializeForceFunctionAttrsLegacyPassPass(PassRegistry&);
 void initializeFunctionAttrsPass(PassRegistry&);
 void initializeGCMachineCodeAnalysisPass(PassRegistry&);
 void initializeGCModuleInfoPass(PassRegistry&);
diff --git a/include/llvm/Transforms/IPO/ForceFunctionAttrs.h b/include/llvm/Transforms/IPO/ForceFunctionAttrs.h
new file mode 100644 (file)
index 0000000..0ff4afe
--- /dev/null
@@ -0,0 +1,35 @@
+//===-- ForceFunctionAttrs.h - Force function attrs for debugging ---------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+/// \file
+/// Super simple passes to force specific function attrs from the commandline
+/// into the IR for debugging purposes.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TRANSFORMS_IPO_FORCEFUNCTIONATTRS_H
+#define LLVM_TRANSFORMS_IPO_FORCEFUNCTIONATTRS_H
+
+#include "llvm/IR/Module.h"
+#include "llvm/IR/PassManager.h"
+
+namespace llvm {
+
+/// Pass which forces specific function attributes into the IR, primarily as
+/// a debugging tool.
+class ForceFunctionAttrsPass {
+public:
+  static StringRef name() { return "ForceFunctionAttrsPass"; }
+  PreservedAnalyses run(Module &M);
+};
+
+/// Create a legacy pass manager instance of a pass to force function attrs.
+Pass *createForceFunctionAttrsLegacyPass();
+
+}
+
+#endif // LLVM_TRANSFORMS_IPO_FORCEFUNCTIONATTRS_H
index b24c615f85ff54f2257058f2db648c250f2c8b55..e8d5459f011d445d622969c81a7b3a2da7a5117a 100644 (file)
 #include "llvm/IR/Verifier.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Target/TargetMachine.h"
-#include "llvm/Transforms/InstCombine/InstCombine.h"
+#include "llvm/Transforms/IPO/ForceFunctionAttrs.h"
 #include "llvm/Transforms/IPO/StripDeadPrototypes.h"
+#include "llvm/Transforms/InstCombine/InstCombine.h"
 #include "llvm/Transforms/Scalar/ADCE.h"
 #include "llvm/Transforms/Scalar/EarlyCSE.h"
 #include "llvm/Transforms/Scalar/LowerExpectIntrinsic.h"
-#include "llvm/Transforms/Scalar/SimplifyCFG.h"
 #include "llvm/Transforms/Scalar/SROA.h"
+#include "llvm/Transforms/Scalar/SimplifyCFG.h"
 
 using namespace llvm;
 
index 638f606c402db9db9815db9292ff19099ad75b88..b7683f12393095ab82e283db9951e0682c7dad77 100644 (file)
@@ -27,6 +27,7 @@ MODULE_ANALYSIS("targetlibinfo", TargetLibraryAnalysis())
 #ifndef MODULE_PASS
 #define MODULE_PASS(NAME, CREATE_PASS)
 #endif
+MODULE_PASS("forceattrs", ForceFunctionAttrsPass())
 MODULE_PASS("invalidate<all>", InvalidateAllAnalysesPass())
 MODULE_PASS("no-op-module", NoOpModulePass())
 MODULE_PASS("print", PrintModulePass(dbgs()))
index d79ce50a1a6fc9d78244898e0804b97d15495fdf..f03f2dc4a72ce3a69a598c96cc623675f660a1b8 100644 (file)
@@ -6,6 +6,7 @@ add_llvm_library(LLVMipo
   DeadArgumentElimination.cpp
   ElimAvailExtern.cpp
   ExtractGV.cpp
+  ForceFunctionAttrs.cpp
   FunctionAttrs.cpp
   FunctionImport.cpp
   GlobalDCE.cpp
diff --git a/lib/Transforms/IPO/ForceFunctionAttrs.cpp b/lib/Transforms/IPO/ForceFunctionAttrs.cpp
new file mode 100644 (file)
index 0000000..816291d
--- /dev/null
@@ -0,0 +1,121 @@
+//===- ForceFunctionAttrs.cpp - Force function attrs for debugging --------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Transforms/IPO/ForceFunctionAttrs.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
+using namespace llvm;
+
+#define DEBUG_TYPE "forceattrs"
+
+static cl::list<std::string>
+    ForceAttributes("force-attribute", cl::Hidden,
+                    cl::desc("Add an attribute to a function. This should be a "
+                             "pair of 'function-name:attribute-name', for "
+                             "example -force-add-attribute=foo:noinline. This "
+                             "option can be specified multiple times."));
+
+static Attribute::AttrKind parseAttrKind(StringRef Kind) {
+  return StringSwitch<Attribute::AttrKind>(Kind)
+      .Case("alwaysinline", Attribute::AlwaysInline)
+      .Case("builtin", Attribute::Builtin)
+      .Case("cold", Attribute::Cold)
+      .Case("convergent", Attribute::Convergent)
+      .Case("inlinehint", Attribute::InlineHint)
+      .Case("jumptable", Attribute::JumpTable)
+      .Case("minsize", Attribute::MinSize)
+      .Case("naked", Attribute::Naked)
+      .Case("nobuiltin", Attribute::NoBuiltin)
+      .Case("noduplicate", Attribute::NoDuplicate)
+      .Case("noimplicitfloat", Attribute::NoImplicitFloat)
+      .Case("noinline", Attribute::NoInline)
+      .Case("nonlazybind", Attribute::NonLazyBind)
+      .Case("noredzone", Attribute::NoRedZone)
+      .Case("noreturn", Attribute::NoReturn)
+      .Case("norecurse", Attribute::NoRecurse)
+      .Case("nounwind", Attribute::NoUnwind)
+      .Case("optnone", Attribute::OptimizeNone)
+      .Case("optsize", Attribute::OptimizeForSize)
+      .Case("readnone", Attribute::ReadNone)
+      .Case("readonly", Attribute::ReadOnly)
+      .Case("argmemonly", Attribute::ArgMemOnly)
+      .Case("returns_twice", Attribute::ReturnsTwice)
+      .Case("safestack", Attribute::SafeStack)
+      .Case("sanitize_address", Attribute::SanitizeAddress)
+      .Case("sanitize_memory", Attribute::SanitizeMemory)
+      .Case("sanitize_thread", Attribute::SanitizeThread)
+      .Case("ssp", Attribute::StackProtect)
+      .Case("sspreq", Attribute::StackProtectReq)
+      .Case("sspstrong", Attribute::StackProtectStrong)
+      .Case("uwtable", Attribute::UWTable)
+      .Default(Attribute::None);
+}
+
+/// If F has any forced attributes given on the command line, add them.
+static void addForcedAttributes(Function &F) {
+  for (auto &S : ForceAttributes) {
+    auto KV = StringRef(S).split(':');
+    if (KV.first != F.getName())
+      continue;
+
+    auto Kind = parseAttrKind(KV.second);
+    if (Kind == Attribute::None) {
+      DEBUG(dbgs() << "ForcedAttribute: " << KV.second
+                   << " unknown or not handled!\n");
+      continue;
+    }
+    if (F.hasFnAttribute(Kind))
+      continue;
+    F.addFnAttr(Kind);
+  }
+}
+
+PreservedAnalyses ForceFunctionAttrsPass::run(Module &M) {
+  if (ForceAttributes.empty())
+    return PreservedAnalyses::all();
+
+  for (Function &F : M.functions())
+    addForcedAttributes(F);
+
+  // Just conservatively invalidate analyses, this isn't likely to be important.
+  return PreservedAnalyses::none();
+}
+
+namespace {
+struct ForceFunctionAttrsLegacyPass : public ModulePass {
+  static char ID; // Pass identification, replacement for typeid
+  ForceFunctionAttrsLegacyPass() : ModulePass(ID) {
+    initializeForceFunctionAttrsLegacyPassPass(
+        *PassRegistry::getPassRegistry());
+  }
+
+  bool runOnModule(Module &M) override {
+    if (ForceAttributes.empty())
+      return false;
+
+    for (Function &F : M.functions())
+      addForcedAttributes(F);
+
+    // Conservatively assume we changed something.
+    return true;
+  }
+};
+}
+
+char ForceFunctionAttrsLegacyPass::ID = 0;
+INITIALIZE_PASS(ForceFunctionAttrsLegacyPass, "forceattrs",
+                "Force set function attributes", false, false)
+
+Pass *llvm::createForceFunctionAttrsLegacyPass() {
+  return new ForceFunctionAttrsLegacyPass();
+}
index e699c5e0df5cf100581e5dba163b486b2b0c8e10..b268eff25928098d909f6cb2759cf09a947d0f83 100644 (file)
@@ -53,13 +53,6 @@ STATISTIC(NumNonNullReturn, "Number of function returns marked nonnull");
 STATISTIC(NumAnnotated, "Number of attributes added to library functions");
 STATISTIC(NumNoRecurse, "Number of functions marked as norecurse");
 
-static cl::list<std::string>
-ForceAttributes("force-attribute", cl::Hidden,
-                cl::desc("Add an attribute to a function. This should be a "
-                         "pair of 'function-name:attribute-name', for "
-                         "example -force-add-attribute=foo:noinline. This "
-                         "option can be specified multiple times."));
-
 namespace {
 typedef SmallSetVector<Function *, 8> SCCNodeSet;
 }
@@ -1851,64 +1844,6 @@ static bool addNoRecurseAttrsTopDownOnly(Function *F) {
   return false;
 }
 
-static Attribute::AttrKind parseAttrKind(StringRef Kind) {
-  return StringSwitch<Attribute::AttrKind>(Kind)
-    .Case("alwaysinline", Attribute::AlwaysInline)
-    .Case("builtin", Attribute::Builtin)
-    .Case("cold", Attribute::Cold)
-    .Case("convergent", Attribute::Convergent)
-    .Case("inlinehint", Attribute::InlineHint)
-    .Case("jumptable", Attribute::JumpTable)
-    .Case("minsize", Attribute::MinSize)
-    .Case("naked", Attribute::Naked)
-    .Case("nobuiltin", Attribute::NoBuiltin)
-    .Case("noduplicate", Attribute::NoDuplicate)
-    .Case("noimplicitfloat", Attribute::NoImplicitFloat)
-    .Case("noinline", Attribute::NoInline)
-    .Case("nonlazybind", Attribute::NonLazyBind)
-    .Case("noredzone", Attribute::NoRedZone)
-    .Case("noreturn", Attribute::NoReturn)
-    .Case("norecurse", Attribute::NoRecurse)
-    .Case("nounwind", Attribute::NoUnwind)
-    .Case("optnone", Attribute::OptimizeNone)
-    .Case("optsize", Attribute::OptimizeForSize)
-    .Case("readnone", Attribute::ReadNone)
-    .Case("readonly", Attribute::ReadOnly)
-    .Case("argmemonly", Attribute::ArgMemOnly)
-    .Case("returns_twice", Attribute::ReturnsTwice)
-    .Case("safestack", Attribute::SafeStack)
-    .Case("sanitize_address", Attribute::SanitizeAddress)
-    .Case("sanitize_memory", Attribute::SanitizeMemory)
-    .Case("sanitize_thread", Attribute::SanitizeThread)
-    .Case("ssp", Attribute::StackProtect)
-    .Case("sspreq", Attribute::StackProtectReq)
-    .Case("sspstrong", Attribute::StackProtectStrong)
-    .Case("uwtable", Attribute::UWTable)
-    .Default(Attribute::None);
-}
-
-/// If F has any forced attributes given on the command line, add them.
-static bool addForcedAttributes(Function *F) {
-  bool Changed = false;
-  for (auto &S : ForceAttributes) {
-    auto KV = StringRef(S).split(':');
-    if (KV.first != F->getName())
-      continue;
-
-    auto Kind = parseAttrKind(KV.second);
-    if (Kind == Attribute::None) {
-      DEBUG(dbgs() << "ForcedAttribute: " << KV.second
-                   << " unknown or not handled!\n");
-      continue;
-    }
-    if (F->hasFnAttribute(Kind))
-      continue;
-    Changed = true;
-    F->addFnAttr(Kind);
-  }
-  return Changed;
-}
-
 bool FunctionAttrs::runOnSCC(CallGraphSCC &SCC) {
   TLI = &getAnalysis<TargetLibraryInfoWrapperPass>().getTLI();
   bool Changed = false;
@@ -1944,7 +1879,6 @@ bool FunctionAttrs::runOnSCC(CallGraphSCC &SCC) {
     if (F->isDeclaration())
       Changed |= inferPrototypeAttributes(*F, *TLI);
 
-    Changed |= addForcedAttributes(F);
     SCCNodes.insert(F);
   }
 
index 2984785a4ded7aca66eb701faa1cdc38b860ce34..54f8de30e28abd9ecb3d076b25030f19fd729fdf 100644 (file)
@@ -27,6 +27,7 @@ void llvm::initializeIPO(PassRegistry &Registry) {
   initializeCrossDSOCFIPass(Registry);
   initializeDAEPass(Registry);
   initializeDAHPass(Registry);
+  initializeForceFunctionAttrsLegacyPassPass(Registry);
   initializeFunctionAttrsPass(Registry);
   initializeGlobalDCEPass(Registry);
   initializeGlobalOptPass(Registry);
index 0d8982774d9bac111c910bc5cc35468b996e74e0..5978b8f59caf88fdaf580a364439cd7e7f2641be 100644 (file)
@@ -31,6 +31,7 @@
 #include "llvm/Analysis/TypeBasedAliasAnalysis.h"
 #include "llvm/Target/TargetMachine.h"
 #include "llvm/Transforms/IPO.h"
+#include "llvm/Transforms/IPO/ForceFunctionAttrs.h"
 #include "llvm/Transforms/Scalar.h"
 #include "llvm/Transforms/Vectorize.h"
 
@@ -187,6 +188,9 @@ void PassManagerBuilder::populateFunctionPassManager(
 
 void PassManagerBuilder::populateModulePassManager(
     legacy::PassManagerBase &MPM) {
+  // Allow forcing function attributes as a debugging and tuning aid.
+  MPM.add(createForceFunctionAttrsLegacyPass());
+
   // If all optimizations are disabled, just run the always-inline pass and,
   // if enabled, the function merging pass.
   if (OptLevel == 0) {
@@ -483,6 +487,9 @@ void PassManagerBuilder::addLTOOptimizationPasses(legacy::PassManagerBase &PM) {
   if (FunctionIndex)
     PM.add(createFunctionImportPass(FunctionIndex));
 
+  // Allow forcing function attributes as a debugging and tuning aid.
+  PM.add(createForceFunctionAttrsLegacyPass());
+
   // Propagate constants at call sites into the functions they call.  This
   // opens opportunities for globalopt (and inlining) by substituting function
   // pointers passed as arguments to direct uses of functions.
diff --git a/test/Transforms/ForcedFunctionAttrs/forced.ll b/test/Transforms/ForcedFunctionAttrs/forced.ll
new file mode 100644 (file)
index 0000000..a41e9c0
--- /dev/null
@@ -0,0 +1,12 @@
+; RUN: opt < %s -S -forceattrs | FileCheck %s --check-prefix=CHECK-CONTROL
+; RUN: opt < %s -S -forceattrs -force-attribute foo:noinline | FileCheck %s --check-prefix=CHECK-FOO
+; RUN: opt < %s -S -passes=forceattrs -force-attribute foo:noinline | FileCheck %s --check-prefix=CHECK-FOO
+
+; CHECK-CONTROL: define void @foo() {
+; CHECK-FOO: define void @foo() #0 {
+define void @foo() {
+  ret void
+}
+
+
+; CHECK-FOO: attributes #0 = { noinline }
diff --git a/test/Transforms/FunctionAttrs/forced.ll b/test/Transforms/FunctionAttrs/forced.ll
deleted file mode 100644 (file)
index d0bdb15..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-; RUN: opt < %s -S -functionattrs | FileCheck %s --check-prefix=CHECK-CONTROL
-; RUN: opt < %s -S -functionattrs -force-attribute foo:noinline | FileCheck %s --check-prefix=CHECK-FOO
-
-; CHECK-CONTROL: define void @foo() #0 {
-; CHECK-FOO: define void @foo() #0 {
-define void @foo() {
-  ret void
-}
-
-
-; CHECK-CONTROL: attributes #0 = { norecurse readnone }
-; CHECK-FOO: attributes #0 = { noinline norecurse readnone }