//===- GlobalOpt.cpp - Optimize Global Variables --------------------------===//
//
// 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 transforms simple global variables that never have their address
// taken. If obviously true, it marks read/write globals as constant, deletes
// variables only stored to, etc.
//
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "globalopt"
#include "llvm/Transforms/IPO.h"
#include "llvm/CallingConv.h"
#include "llvm/Constants.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Instructions.h"
#include "llvm/IntrinsicInst.h"
#include "llvm/Module.h"
#include "llvm/Pass.h"
#include "llvm/Support/Debug.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Transforms/Utils/Local.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/StringExtras.h"
#include <set>
#include <algorithm>
using namespace llvm;
namespace {
Statistic<> NumMarked ("globalopt", "Number of globals marked constant");
Statistic<> NumSRA ("globalopt", "Number of aggregate globals broken "
"into scalars");
Statistic<> NumSubstitute("globalopt",
"Number of globals with initializers stored into them");
Statistic<> NumDeleted ("globalopt", "Number of globals deleted");
Statistic<> NumFnDeleted("globalopt", "Number of functions deleted");
Statistic<> NumGlobUses ("globalopt", "Number of global uses devirtualized");
Statistic<> NumLocalized("globalopt", "Number of globals localized");
Statistic<> NumShrunkToBool("globalopt",
"Number of global vars shrunk to booleans");
Statistic<> NumFastCallFns("globalopt",
"Number of functions converted to fastcc");
struct GlobalOpt : public ModulePass {
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
AU.addRequired<TargetData>();
}
bool runOnModule(Module &M);
private:
bool ProcessInternalGlobal(GlobalVariable *GV, Module::global_iterator &GVI);
};
RegisterOpt<GlobalOpt> X("globalopt", "Global Variable Optimizer");
}
ModulePass *llvm::createGlobalOptimizerPass() { return new GlobalOpt(); }
/// GlobalStatus - As we analyze each global, keep track of some information
/// about it. If we find out that the address of the global is taken, none of
/// this info will be accurate.
struct GlobalStatus {
/// isLoaded - True if the global is ever loaded. If the global isn't ever
/// loaded it can be deleted.
bool isLoaded;
/// StoredType - Keep track of what stores to the global look like.
///
enum StoredType {
/// NotStored - There is no store to this global. It can thus be marked
/// constant.
NotStored,
/// isInitializerStored - This global is stored to, but the only thing
/// stored is the constant it was initialized with. This is only tracked
/// for scalar globals.
isInitializerStored,
/// isStoredOnce - This global is stored to, but only its initializer and
/// one other value is ever stored to it. If this global isStoredOnce, we
/// track the value stored to it in StoredOnceValue below. This is only
/// tracked for scalar globals.
isStoredOnce,
/// isStored - This global is stored to by multiple values or something else
/// that we cannot track.
isStored
} StoredType;
/// StoredOnceValue - If only one value (besides the initializer constant) is
/// ever stored to this global, keep track of what value it is.
Value *StoredOnceValue;
// AccessingFunction/HasMultipleAccessingFunctions - These start out
// null/false. When the first accessing function is noticed, it is recorded.
// When a second different accessing function is noticed,
// HasMultipleAccessingFunctions is set to true.
Function *AccessingFunction;
bool HasMultipleAccessingFunctions;
// HasNonInstructionUser - Set to true if this global has a user that is not
// an instruction (e.g. a constant expr or GV initializer).
bool HasNonInstructionUser;
/// isNotSuitableForSRA - Keep track of whether any SRA preventing users of
/// the global exist. Such users include GEP instruction with variable
/// indexes, and non-gep/load/store users like constant expr casts.
bool isNotSuitableForSRA;
GlobalStatus() : isLoaded(false), StoredType(NotStored), StoredOnceValue(0),
AccessingFunction(0), HasMultipleAccessingFunctions(false),
HasNonInstructionUser(false), isNotSuitableForSRA(false) {}
};
/// ConstantIsDead - Return true if the specified constant is (transitively)
/// dead. The constant may be used by other constants (e.g. constant arrays and
/// constant exprs) as long as they are dead, but it cannot be used by anything
/// else.
static bool ConstantIsDead(Constant *C) {
if (isa<GlobalValue>(C)) return false;
for (Value::use_iterator UI = C->use_begin(), E = C->use_end();