<html><head><meta http-equiv="Content-Type" content="text/html charset=windows-1252"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;">Hi Duncan,<div><br><div><div>On Mar 19, 2013, at 12:52 PM, Duncan Sands <<a href="mailto:baldrick@free.fr">baldrick@free.fr</a>> wrote:</div><br class="Apple-interchange-newline"><blockquote type="cite"><div style="letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;">Hi Quentin,<br><br>On 18/03/13 23:30, Quentin Colombet wrote:<br><blockquote type="cite">Author: qcolombet<br>Date: Mon Mar 18 17:30:07 2013<br>New Revision: 177331<br><br>URL: <a href="http://llvm.org/viewvc/llvm-project?rev=177331&view=rev">http://llvm.org/viewvc/llvm-project?rev=177331&view=rev</a><br>Log:<br>Extend global merge pass to optionally consider global constant variables.<br>Also add some checks to not merge globals used within landing pad instructions or marked as "used".<br><br>Modified:<br>    llvm/trunk/lib/Transforms/Scalar/GlobalMerge.cpp<br>    llvm/trunk/test/CodeGen/ARM/global-merge.ll<br><br>Modified: llvm/trunk/lib/Transforms/Scalar/GlobalMerge.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Scalar/GlobalMerge.cpp?rev=177331&r1=177330&r2=177331&view=diff">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Scalar/GlobalMerge.cpp?rev=177331&r1=177330&r2=177331&view=diff</a><br>==============================================================================<br>--- llvm/trunk/lib/Transforms/Scalar/GlobalMerge.cpp (original)<br>+++ llvm/trunk/lib/Transforms/Scalar/GlobalMerge.cpp Mon Mar 18 17:30:07 2013<br>@@ -53,6 +53,7 @@<br><br> #define DEBUG_TYPE "global-merge"<br> #include "llvm/Transforms/Scalar.h"<br>+#include "llvm/ADT/SmallPtrSet.h"<br> #include "llvm/ADT/Statistic.h"<br> #include "llvm/IR/Attributes.h"<br> #include "llvm/IR/Constants.h"<br>@@ -60,14 +61,22 @@<br> #include "llvm/IR/DerivedTypes.h"<br> #include "llvm/IR/Function.h"<br> #include "llvm/IR/GlobalVariable.h"<br>+#include "llvm/IR/InlineAsm.h"<br></blockquote><br>I guess this include is not needed.<br></div></blockquote><div>Yes, you’re right, it shouldn’t be needed anymore.</div><br><blockquote type="cite"><div style="letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;"><br><blockquote type="cite"> #include "llvm/IR/Instructions.h"<br> #include "llvm/IR/Intrinsics.h"<br>+#include "llvm/IR/IntrinsicInst.h"<br></blockquote><br>Is this include needed?<br></div></blockquote>No, it shouldn’t.</div><div><br></div><div><blockquote type="cite"><div style="letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;"><br><blockquote type="cite"> #include "llvm/IR/Module.h"<br> #include "llvm/Pass.h"<br>+#include "llvm/Support/CommandLine.h"<br> #include "llvm/Target/TargetLowering.h"<br> #include "llvm/Target/TargetLoweringObjectFile.h"<br> using namespace llvm;<br><br>+static cl::opt<bool><br>+EnableGlobalMergeOnConst("global-merge-on-const", cl::Hidden,<br>+                  <span class="Apple-tab-span" style="white-space: pre;">      </span>cl::desc("Enable global merge pass on constants"),<br>+                  <span class="Apple-tab-span" style="white-space: pre;">    </span>cl::init(false));<br></blockquote><br>Why is this optional, why not always do it?<br></div></blockquote><div>As it is if you enable it by default, the heuristic (merge variable by size) produces performance regression already noticeable by during make check.</div><div>I didn’t want to impact any existing target using the global merge pass, thus I’ve kept the original behavior by default.</div><div>The idea is to improve the current heuristic as a second step, then enable it by default.</div><div><br></div><br><blockquote type="cite"><div style="letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;"><br><blockquote type="cite">+<br> STATISTIC(NumMerged      , "Number of globals merged");<br> namespace {<br>   class GlobalMerge : public FunctionPass {<br>@@ -78,6 +87,23 @@ namespace {<br>     bool doMerge(SmallVectorImpl<GlobalVariable*> &Globals,<br>                  Module &M, bool isConst, unsigned AddrSpace) const;<br><br>+    /// \brief Check if the given variable has been identified as must keep<br>+    /// \pre setMustKeepGlobalVariables must have been called on the Module that<br>+    ///      contains GV<br>+    bool isMustKeepGlobalVariable(const GlobalVariable *GV) const {<br>+      return MustKeepGlobalVariables.count(GV);<br>+    }<br>+<br>+    /// Collect every variables marked as "used" or used in a landing pad<br>+    /// instruction for this Module.<br>+    void setMustKeepGlobalVariables(Module &M);<br>+<br>+    /// Collect every variables marked as "used"<br>+    void collectUsedGlobalVariables(Module &M);<br>+<br>+    /// Keep track of the GlobalVariable that are marked as "used"<br></blockquote><br>This comment is misleading since it isn't just for "used" variables.  How<br>about:<br> /// Keep track of global variables that must not be merged away.<br></div></blockquote><div>Ok</div><br><blockquote type="cite"><div style="letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;"><blockquote type="cite">+    SmallPtrSet<const GlobalVariable *, 16> MustKeepGlobalVariables;<br>+<br>   public:<br>     static char ID;             // Pass identification, replacement for typeid.<br>     explicit GlobalMerge(const TargetLowering *tli = 0)<br>@@ -169,6 +195,46 @@ bool GlobalMerge::doMerge(SmallVectorImp<br>   return true;<br> }<br><br>+void GlobalMerge::collectUsedGlobalVariables(Module &M) {<br>+  // Extract global variables from llvm.used array<br>+  const GlobalVariable *GV = M.getGlobalVariable("llvm.used");<br>+  if (!GV || !GV->hasInitializer()) return;<br>+<br>+  // Should be an array of 'i8*'.<br>+  const ConstantArray *InitList = dyn_cast<ConstantArray>(GV->getInitializer());<br>+  if (InitList == 0) return;<br>+<br>+  for (unsigned i = 0, e = InitList->getNumOperands(); i != e; ++i)<br>+    if (const GlobalVariable *G =<br>+        dyn_cast<GlobalVariable>(InitList->getOperand(i)->stripPointerCasts()))<br>+      MustKeepGlobalVariables.insert(G);<br>+}<br></blockquote><br>The initial part of the above logic is probably common to every place that<br>examines llvm.used.  Maybe you could factor it out into a shared helper<br>function?<br></div></blockquote>Yes, it is.</div><div>Where would be the right place for such helper?<br><blockquote type="cite"><div style="letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;"><br><blockquote type="cite">+<br>+void GlobalMerge::setMustKeepGlobalVariables(Module &M) {<br>+  // If we already processed a Module, UsedGlobalVariables may have been<br>+  // populated. Reset the information for this module.<br></blockquote><br>Is the above really possible?  I thought a new instance of the pass was created<br>every time it is run on a module.<br></div></blockquote><div>Although it is not currently happening, it is possible in the future, especially with the new design of the pass manager that allows to reuse passes for different objects (Function, Module, etc.)</div><div>Anyway, to follow the intended design, I'll put this piece of code in doFinalization.</div><br><blockquote type="cite"><div style="letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;"><br><blockquote type="cite">+  MustKeepGlobalVariables.clear();<br>+  collectUsedGlobalVariables(M);<br>+<br>+  for (Module::iterator IFn = M.begin(), IEndFn = M.end(); IFn != IEndFn;<br>+       ++IFn) {<br>+    for (Function::iterator IBB = IFn->begin(), IEndBB = IFn->end();<br>+         IBB != IEndBB; ++IBB) {<br>+      // Follow the inwoke link to find the landing pad instruction<br>+      const InvokeInst *II = dyn_cast<InvokeInst>(IBB->getTerminator());<br>+      if (!II) continue;<br>+<br>+      const LandingPadInst *LPInst = II->getUnwindDest()->getLandingPadInst();<br>+      // Look for globals in the clauses of the landing pad instruction<br>+      for (unsigned Idx = 0, NumClauses = LPInst->getNumClauses();<br>+           Idx != NumClauses; ++Idx)<br>+        if (const GlobalVariable *GV =<br>+            dyn_cast<GlobalVariable>(LPInst->getClause(Idx)<br>+                                     ->stripPointerCasts()))<br>+          MustKeepGlobalVariables.insert(GV);<br>+    }<br>+  }<br>+}<br><br> bool GlobalMerge::doInitialization(Module &M) {<br>   DenseMap<unsigned, SmallVector<GlobalVariable*, 16> > Globals, ConstGlobals,<br>@@ -176,6 +242,7 @@ bool GlobalMerge::doInitialization(Modul<br>   const DataLayout *TD = TLI->getDataLayout();<br>   unsigned MaxOffset = TLI->getMaximalGlobalOffset();<br>   bool Changed = false;<br>+  setMustKeepGlobalVariables(M);<br><br>   // Grab all non-const globals.<br>   for (Module::global_iterator I = M.global_begin(),<br>@@ -200,6 +267,12 @@ bool GlobalMerge::doInitialization(Modul<br>         I->getName().startswith(".llvm."))<br>       continue;<br><br>+    // Ignore all "required" globals:<br>+    // - the ones used for EH<br>+    // - the ones marked with "used" attribute<br></blockquote><br>I think it is a mistake to explain here the logic used to define<br>MustKeepGlobalVariables.  I think it would be better to just say:<br> // Ignore all "required" globals.<br></div></blockquote><div>Ok</div><br><blockquote type="cite"><div style="letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;"><br><blockquote type="cite">+    if (isMustKeepGlobalVariable(I))<br>+      continue;<br>+<br>     if (TD->getTypeAllocSize(Ty) < MaxOffset) {<br>       if (TargetLoweringObjectFile::getKindForGlobal(I, TLI->getTargetMachine())<br>           .isBSSLocal())<br></blockquote></div></blockquote><div>I’ve made a patch with the straight forward changes you’ve suggested: r177445.</div><div>I’m waiting for direction on where to place the helper function to collect the used variables.</div><div><br></div><div>Thanks for your help.</div><div><br></div><div>-Quentin</div></div></div></body></html>