My faith in programmers has been found to be totally misplaced. One would

assume that if they don't intend to write to a global variable, that they
would mark it as constant.  However, there are people that don't understand
that the compiler can do nice things for them if they give it the information
it needs.

This pass looks for blatently obvious globals that are only ever read from.
Though it uses a trivially simple "alias analysis" of sorts, it is still able
to do amazing things to important benchmarks.  253.perlbmk, for example,
contains several ***GIANT*** function pointer tables that are not marked
constant and should be.  Marking them constant allows the optimizer to turn
a whole bunch of indirect calls into direct calls.  Note that only a link-time
optimizer can do this transformation, but perlbmk does have several strings
and other minor globals that can be marked constant by this pass when run
from GCCAS.

176.gcc has a ton of strings and large tables that are marked constant, both
at compile time (38 of them) and at link time (48 more).  Other benchmarks
give similar results, though it seems like big ones have disproportionally
more than small ones.

This pass is extremely quick and does good things.  I'm going to enable it
in gccas & gccld.  Not bad for 50 SLOC.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@11836 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Chris Lattner 2004-02-25 21:34:36 +00:00
parent 757df02826
commit 079236d1c9

View File

@ -0,0 +1,82 @@
//===- GlobalConstifier.cpp - Mark read-only globals constant -------------===//
//
// The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass loops over the non-constant internal global variables in the
// program. If it can prove that they are never written to, it marks them
// constant.
//
// NOTE: this should eventually use the alias analysis interfaces to do the
// transformation, but for now we just stick with a simple solution. DSA in
// particular could give a much more accurate answer to the mod/ref query, but
// it's not quite ready for this.
//
//===----------------------------------------------------------------------===//
#include "llvm/Transforms/IPO.h"
#include "llvm/Constants.h"
#include "llvm/iMemory.h"
#include "llvm/Module.h"
#include "llvm/Pass.h"
#include "Support/Debug.h"
#include "Support/Statistic.h"
using namespace llvm;
namespace {
Statistic<> NumMarked("constify", "Number of globals marked constant");
struct Constifier : public Pass {
bool run(Module &M);
};
RegisterOpt<Constifier> X("constify", "Global Constifier");
}
Pass *llvm::createGlobalConstifierPass() { return new Constifier(); }
/// isStoredThrough - Return false if the specified pointer is provably never
/// stored through. If we can't tell, we must conservatively assume it might.
///
static bool isStoredThrough(Value *V) {
for (Value::use_iterator UI = V->use_begin(), E = V->use_end(); UI != E; ++UI)
if (Constant *C = dyn_cast<Constant>(*UI)) {
if (ConstantExpr *CE = dyn_cast<ConstantExpr>(C)) {
if (isStoredThrough(CE))
return true;
} else if (ConstantPointerRef *CPR = dyn_cast<ConstantPointerRef>(C)) {
if (isStoredThrough(CPR)) return true;
} else {
// Must be an element of a constant array or something.
return true;
}
} else if (Instruction *I = dyn_cast<Instruction>(*UI)) {
if (I->getOpcode() == Instruction::GetElementPtr) {
if (isStoredThrough(I)) return true;
} else if (!isa<LoadInst>(*UI))
return true; // Any other non-load instruction might store!
} else {
// Otherwise must be a global or some other user.
return true;
}
return false;
}
bool Constifier::run(Module &M) {
bool Changed = false;
for (Module::giterator GV = M.gbegin(), E = M.gend(); GV != E; ++GV)
if (!GV->isConstant() && GV->hasInternalLinkage() && GV->hasInitializer()) {
if (!isStoredThrough(GV)) {
DEBUG(std::cerr << "MARKING CONSTANT: " << *GV << "\n");
GV->setConstant(true);
++NumMarked;
Changed = true;
}
}
return Changed;
}