mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-08-20 11:29:24 +00:00
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
83 lines
2.8 KiB
C++
83 lines
2.8 KiB
C++
//===- 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;
|
|
}
|