summaryrefslogtreecommitdiff
path: root/lib/Transforms/IPO/GlobalOpt.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Transforms/IPO/GlobalOpt.cpp')
-rw-r--r--lib/Transforms/IPO/GlobalOpt.cpp187
1 files changed, 148 insertions, 39 deletions
diff --git a/lib/Transforms/IPO/GlobalOpt.cpp b/lib/Transforms/IPO/GlobalOpt.cpp
index 93eab680ca6b..4bb2984e3b47 100644
--- a/lib/Transforms/IPO/GlobalOpt.cpp
+++ b/lib/Transforms/IPO/GlobalOpt.cpp
@@ -20,22 +20,41 @@
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/ADT/iterator_range.h"
#include "llvm/Analysis/ConstantFolding.h"
#include "llvm/Analysis/MemoryBuiltins.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/IR/Attributes.h"
+#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/CallSite.h"
#include "llvm/IR/CallingConv.h"
+#include "llvm/IR/Constant.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/DebugInfoMetadata.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Dominators.h"
+#include "llvm/IR/Function.h"
#include "llvm/IR/GetElementPtrTypeIterator.h"
+#include "llvm/IR/GlobalAlias.h"
+#include "llvm/IR/GlobalValue.h"
+#include "llvm/IR/GlobalVariable.h"
+#include "llvm/IR/InstrTypes.h"
+#include "llvm/IR/Instruction.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Operator.h"
+#include "llvm/IR/Type.h"
+#include "llvm/IR/Use.h"
+#include "llvm/IR/User.h"
+#include "llvm/IR/Value.h"
#include "llvm/IR/ValueHandle.h"
#include "llvm/Pass.h"
+#include "llvm/Support/AtomicOrdering.h"
+#include "llvm/Support/Casting.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MathExtras.h"
@@ -45,7 +64,11 @@
#include "llvm/Transforms/Utils/Evaluator.h"
#include "llvm/Transforms/Utils/GlobalStatus.h"
#include "llvm/Transforms/Utils/Local.h"
-#include <algorithm>
+#include <cassert>
+#include <cstdint>
+#include <utility>
+#include <vector>
+
using namespace llvm;
#define DEBUG_TYPE "globalopt"
@@ -139,7 +162,7 @@ static bool IsSafeComputationToRemove(Value *V, const TargetLibraryInfo *TLI) {
}
V = I->getOperand(0);
- } while (1);
+ } while (true);
}
/// This GV is a pointer root. Loop over all users of the global and clean up
@@ -220,7 +243,7 @@ static bool CleanupPointerRootUsers(GlobalVariable *GV,
break;
I->eraseFromParent();
I = J;
- } while (1);
+ } while (true);
I->eraseFromParent();
}
}
@@ -348,7 +371,6 @@ static bool isSafeSROAElementUse(Value *V) {
return true;
}
-
/// U is a direct user of the specified global value. Look at it and its uses
/// and decide whether it is safe to SROA this global.
static bool IsUserOfGlobalSafeForSRA(User *U, GlobalValue *GV) {
@@ -402,11 +424,8 @@ static bool IsUserOfGlobalSafeForSRA(User *U, GlobalValue *GV) {
}
}
- for (User *UU : U->users())
- if (!isSafeSROAElementUse(UU))
- return false;
-
- return true;
+ return llvm::all_of(U->users(),
+ [](User *UU) { return isSafeSROAElementUse(UU); });
}
/// Look at all uses of the global and decide whether it is safe for us to
@@ -419,6 +438,27 @@ static bool GlobalUsersSafeToSRA(GlobalValue *GV) {
return true;
}
+/// Copy over the debug info for a variable to its SRA replacements.
+static void transferSRADebugInfo(GlobalVariable *GV, GlobalVariable *NGV,
+ uint64_t FragmentOffsetInBits,
+ uint64_t FragmentSizeInBits,
+ unsigned NumElements) {
+ SmallVector<DIGlobalVariableExpression *, 1> GVs;
+ GV->getDebugInfo(GVs);
+ for (auto *GVE : GVs) {
+ DIVariable *Var = GVE->getVariable();
+ DIExpression *Expr = GVE->getExpression();
+ if (NumElements > 1) {
+ if (auto E = DIExpression::createFragmentExpression(
+ Expr, FragmentOffsetInBits, FragmentSizeInBits))
+ Expr = *E;
+ else
+ return;
+ }
+ auto *NGVE = DIGlobalVariableExpression::get(GVE->getContext(), Var, Expr);
+ NGV->addDebugInfo(NGVE);
+ }
+}
/// Perform scalar replacement of aggregates on the specified global variable.
/// This opens the door for other optimizations by exposing the behavior of the
@@ -434,7 +474,7 @@ static GlobalVariable *SRAGlobal(GlobalVariable *GV, const DataLayout &DL) {
Constant *Init = GV->getInitializer();
Type *Ty = Init->getType();
- std::vector<GlobalVariable*> NewGlobals;
+ std::vector<GlobalVariable *> NewGlobals;
Module::GlobalListType &Globals = GV->getParent()->getGlobalList();
// Get the alignment of the global, either explicit or target-specific.
@@ -443,9 +483,11 @@ static GlobalVariable *SRAGlobal(GlobalVariable *GV, const DataLayout &DL) {
StartAlignment = DL.getABITypeAlignment(GV->getType());
if (StructType *STy = dyn_cast<StructType>(Ty)) {
- NewGlobals.reserve(STy->getNumElements());
+ uint64_t FragmentOffset = 0;
+ unsigned NumElements = STy->getNumElements();
+ NewGlobals.reserve(NumElements);
const StructLayout &Layout = *DL.getStructLayout(STy);
- for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) {
+ for (unsigned i = 0, e = NumElements; i != e; ++i) {
Constant *In = Init->getAggregateElement(i);
assert(In && "Couldn't get element of initializer?");
GlobalVariable *NGV = new GlobalVariable(STy->getElementType(i), false,
@@ -465,15 +507,22 @@ static GlobalVariable *SRAGlobal(GlobalVariable *GV, const DataLayout &DL) {
unsigned NewAlign = (unsigned)MinAlign(StartAlignment, FieldOffset);
if (NewAlign > DL.getABITypeAlignment(STy->getElementType(i)))
NGV->setAlignment(NewAlign);
+
+ // Copy over the debug info for the variable.
+ FragmentOffset = alignTo(FragmentOffset, NewAlign);
+ uint64_t Size = DL.getTypeSizeInBits(NGV->getValueType());
+ transferSRADebugInfo(GV, NGV, FragmentOffset, Size, NumElements);
+ FragmentOffset += Size;
}
} else if (SequentialType *STy = dyn_cast<SequentialType>(Ty)) {
unsigned NumElements = STy->getNumElements();
if (NumElements > 16 && GV->hasNUsesOrMore(16))
return nullptr; // It's not worth it.
NewGlobals.reserve(NumElements);
-
- uint64_t EltSize = DL.getTypeAllocSize(STy->getElementType());
- unsigned EltAlign = DL.getABITypeAlignment(STy->getElementType());
+ auto ElTy = STy->getElementType();
+ uint64_t EltSize = DL.getTypeAllocSize(ElTy);
+ unsigned EltAlign = DL.getABITypeAlignment(ElTy);
+ uint64_t FragmentSizeInBits = DL.getTypeSizeInBits(ElTy);
for (unsigned i = 0, e = NumElements; i != e; ++i) {
Constant *In = Init->getAggregateElement(i);
assert(In && "Couldn't get element of initializer?");
@@ -494,6 +543,8 @@ static GlobalVariable *SRAGlobal(GlobalVariable *GV, const DataLayout &DL) {
unsigned NewAlign = (unsigned)MinAlign(StartAlignment, EltSize*i);
if (NewAlign > EltAlign)
NGV->setAlignment(NewAlign);
+ transferSRADebugInfo(GV, NGV, FragmentSizeInBits * i, FragmentSizeInBits,
+ NumElements);
}
}
@@ -689,7 +740,6 @@ static bool OptimizeAwayTrappingUsesOfValue(Value *V, Constant *NewV) {
return Changed;
}
-
/// The specified global has only one non-null value stored into it. If there
/// are uses of the loaded value that would trap if the loaded value is
/// dynamically null, then we know that they cannot be reachable with a null
@@ -1045,7 +1095,6 @@ static bool LoadUsesSimpleEnoughForHeapSRA(const Value *V,
return true;
}
-
/// If all users of values loaded from GV are simple enough to perform HeapSRA,
/// return true.
static bool AllGlobalLoadUsesSimpleEnoughForHeapSRA(const GlobalVariable *GV,
@@ -1095,9 +1144,9 @@ static bool AllGlobalLoadUsesSimpleEnoughForHeapSRA(const GlobalVariable *GV,
}
static Value *GetHeapSROAValue(Value *V, unsigned FieldNo,
- DenseMap<Value*, std::vector<Value*> > &InsertedScalarizedValues,
- std::vector<std::pair<PHINode*, unsigned> > &PHIsToRewrite) {
- std::vector<Value*> &FieldVals = InsertedScalarizedValues[V];
+ DenseMap<Value *, std::vector<Value *>> &InsertedScalarizedValues,
+ std::vector<std::pair<PHINode *, unsigned>> &PHIsToRewrite) {
+ std::vector<Value *> &FieldVals = InsertedScalarizedValues[V];
if (FieldNo >= FieldVals.size())
FieldVals.resize(FieldNo+1);
@@ -1139,8 +1188,8 @@ static Value *GetHeapSROAValue(Value *V, unsigned FieldNo,
/// Given a load instruction and a value derived from the load, rewrite the
/// derived value to use the HeapSRoA'd load.
static void RewriteHeapSROALoadUser(Instruction *LoadUser,
- DenseMap<Value*, std::vector<Value*> > &InsertedScalarizedValues,
- std::vector<std::pair<PHINode*, unsigned> > &PHIsToRewrite) {
+ DenseMap<Value *, std::vector<Value *>> &InsertedScalarizedValues,
+ std::vector<std::pair<PHINode *, unsigned>> &PHIsToRewrite) {
// If this is a comparison against null, handle it.
if (ICmpInst *SCI = dyn_cast<ICmpInst>(LoadUser)) {
assert(isa<ConstantPointerNull>(SCI->getOperand(1)));
@@ -1187,7 +1236,7 @@ static void RewriteHeapSROALoadUser(Instruction *LoadUser,
// processed.
PHINode *PN = cast<PHINode>(LoadUser);
if (!InsertedScalarizedValues.insert(std::make_pair(PN,
- std::vector<Value*>())).second)
+ std::vector<Value *>())).second)
return;
// If this is the first time we've seen this PHI, recursively process all
@@ -1202,8 +1251,8 @@ static void RewriteHeapSROALoadUser(Instruction *LoadUser,
/// global. Eliminate all uses of Ptr, making them use FieldGlobals instead.
/// All uses of loaded values satisfy AllGlobalLoadUsesSimpleEnoughForHeapSRA.
static void RewriteUsesOfLoadForHeapSRoA(LoadInst *Load,
- DenseMap<Value*, std::vector<Value*> > &InsertedScalarizedValues,
- std::vector<std::pair<PHINode*, unsigned> > &PHIsToRewrite) {
+ DenseMap<Value *, std::vector<Value *>> &InsertedScalarizedValues,
+ std::vector<std::pair<PHINode *, unsigned> > &PHIsToRewrite) {
for (auto UI = Load->user_begin(), E = Load->user_end(); UI != E;) {
Instruction *User = cast<Instruction>(*UI++);
RewriteHeapSROALoadUser(User, InsertedScalarizedValues, PHIsToRewrite);
@@ -1232,8 +1281,8 @@ static GlobalVariable *PerformHeapAllocSRoA(GlobalVariable *GV, CallInst *CI,
// Okay, at this point, there are no users of the malloc. Insert N
// new mallocs at the same place as CI, and N globals.
- std::vector<Value*> FieldGlobals;
- std::vector<Value*> FieldMallocs;
+ std::vector<Value *> FieldGlobals;
+ std::vector<Value *> FieldMallocs;
SmallVector<OperandBundleDef, 1> OpBundles;
CI->getOperandBundlesAsDefs(OpBundles);
@@ -1330,10 +1379,10 @@ static GlobalVariable *PerformHeapAllocSRoA(GlobalVariable *GV, CallInst *CI,
/// As we process loads, if we can't immediately update all uses of the load,
/// keep track of what scalarized loads are inserted for a given load.
- DenseMap<Value*, std::vector<Value*> > InsertedScalarizedValues;
+ DenseMap<Value *, std::vector<Value *>> InsertedScalarizedValues;
InsertedScalarizedValues[GV] = FieldGlobals;
- std::vector<std::pair<PHINode*, unsigned> > PHIsToRewrite;
+ std::vector<std::pair<PHINode *, unsigned>> PHIsToRewrite;
// Okay, the malloc site is completely handled. All of the uses of GV are now
// loads, and all uses of those loads are simple. Rewrite them to use loads
@@ -1379,7 +1428,7 @@ static GlobalVariable *PerformHeapAllocSRoA(GlobalVariable *GV, CallInst *CI,
}
// Drop all inter-phi links and any loads that made it this far.
- for (DenseMap<Value*, std::vector<Value*> >::iterator
+ for (DenseMap<Value *, std::vector<Value *>>::iterator
I = InsertedScalarizedValues.begin(), E = InsertedScalarizedValues.end();
I != E; ++I) {
if (PHINode *PN = dyn_cast<PHINode>(I->first))
@@ -1389,7 +1438,7 @@ static GlobalVariable *PerformHeapAllocSRoA(GlobalVariable *GV, CallInst *CI,
}
// Delete all the phis and loads now that inter-references are dead.
- for (DenseMap<Value*, std::vector<Value*> >::iterator
+ for (DenseMap<Value *, std::vector<Value *>>::iterator
I = InsertedScalarizedValues.begin(), E = InsertedScalarizedValues.end();
I != E; ++I) {
if (PHINode *PN = dyn_cast<PHINode>(I->first))
@@ -1576,12 +1625,57 @@ static bool TryToShrinkGlobalToBoolean(GlobalVariable *GV, Constant *OtherVal) {
assert(InitVal->getType() != Type::getInt1Ty(GV->getContext()) &&
"No reason to shrink to bool!");
+ SmallVector<DIGlobalVariableExpression *, 1> GVs;
+ GV->getDebugInfo(GVs);
+
// If initialized to zero and storing one into the global, we can use a cast
// instead of a select to synthesize the desired value.
bool IsOneZero = false;
- if (ConstantInt *CI = dyn_cast<ConstantInt>(OtherVal))
+ bool EmitOneOrZero = true;
+ if (ConstantInt *CI = dyn_cast<ConstantInt>(OtherVal)){
IsOneZero = InitVal->isNullValue() && CI->isOne();
+ if (ConstantInt *CIInit = dyn_cast<ConstantInt>(GV->getInitializer())){
+ uint64_t ValInit = CIInit->getZExtValue();
+ uint64_t ValOther = CI->getZExtValue();
+ uint64_t ValMinus = ValOther - ValInit;
+
+ for(auto *GVe : GVs){
+ DIGlobalVariable *DGV = GVe->getVariable();
+ DIExpression *E = GVe->getExpression();
+
+ // It is expected that the address of global optimized variable is on
+ // top of the stack. After optimization, value of that variable will
+ // be ether 0 for initial value or 1 for other value. The following
+ // expression should return constant integer value depending on the
+ // value at global object address:
+ // val * (ValOther - ValInit) + ValInit:
+ // DW_OP_deref DW_OP_constu <ValMinus>
+ // DW_OP_mul DW_OP_constu <ValInit> DW_OP_plus DW_OP_stack_value
+ E = DIExpression::get(NewGV->getContext(),
+ {dwarf::DW_OP_deref,
+ dwarf::DW_OP_constu,
+ ValMinus,
+ dwarf::DW_OP_mul,
+ dwarf::DW_OP_constu,
+ ValInit,
+ dwarf::DW_OP_plus,
+ dwarf::DW_OP_stack_value});
+ DIGlobalVariableExpression *DGVE =
+ DIGlobalVariableExpression::get(NewGV->getContext(), DGV, E);
+ NewGV->addDebugInfo(DGVE);
+ }
+ EmitOneOrZero = false;
+ }
+ }
+
+ if (EmitOneOrZero) {
+ // FIXME: This will only emit address for debugger on which will
+ // be written only 0 or 1.
+ for(auto *GV : GVs)
+ NewGV->addDebugInfo(GV);
+ }
+
while (!GV->use_empty()) {
Instruction *UI = cast<Instruction>(GV->user_back());
if (StoreInst *SI = dyn_cast<StoreInst>(UI)) {
@@ -2202,7 +2296,7 @@ static void setUsedInitializer(GlobalVariable &V,
// Type of pointer to the array of pointers.
PointerType *Int8PtrTy = Type::getInt8PtrTy(V.getContext(), 0);
- SmallVector<llvm::Constant *, 8> UsedArray;
+ SmallVector<Constant *, 8> UsedArray;
for (GlobalValue *GV : Init) {
Constant *Cast
= ConstantExpr::getPointerBitCastOrAddrSpaceCast(GV, Int8PtrTy);
@@ -2215,14 +2309,15 @@ static void setUsedInitializer(GlobalVariable &V,
Module *M = V.getParent();
V.removeFromParent();
GlobalVariable *NV =
- new GlobalVariable(*M, ATy, false, llvm::GlobalValue::AppendingLinkage,
- llvm::ConstantArray::get(ATy, UsedArray), "");
+ new GlobalVariable(*M, ATy, false, GlobalValue::AppendingLinkage,
+ ConstantArray::get(ATy, UsedArray), "");
NV->takeName(&V);
NV->setSection("llvm.metadata");
delete &V;
}
namespace {
+
/// An easy to access representation of llvm.used and llvm.compiler.used.
class LLVMUsed {
SmallPtrSet<GlobalValue *, 8> Used;
@@ -2235,25 +2330,34 @@ public:
UsedV = collectUsedGlobalVariables(M, Used, false);
CompilerUsedV = collectUsedGlobalVariables(M, CompilerUsed, true);
}
- typedef SmallPtrSet<GlobalValue *, 8>::iterator iterator;
- typedef iterator_range<iterator> used_iterator_range;
+
+ using iterator = SmallPtrSet<GlobalValue *, 8>::iterator;
+ using used_iterator_range = iterator_range<iterator>;
+
iterator usedBegin() { return Used.begin(); }
iterator usedEnd() { return Used.end(); }
+
used_iterator_range used() {
return used_iterator_range(usedBegin(), usedEnd());
}
+
iterator compilerUsedBegin() { return CompilerUsed.begin(); }
iterator compilerUsedEnd() { return CompilerUsed.end(); }
+
used_iterator_range compilerUsed() {
return used_iterator_range(compilerUsedBegin(), compilerUsedEnd());
}
+
bool usedCount(GlobalValue *GV) const { return Used.count(GV); }
+
bool compilerUsedCount(GlobalValue *GV) const {
return CompilerUsed.count(GV);
}
+
bool usedErase(GlobalValue *GV) { return Used.erase(GV); }
bool compilerUsedErase(GlobalValue *GV) { return CompilerUsed.erase(GV); }
bool usedInsert(GlobalValue *GV) { return Used.insert(GV).second; }
+
bool compilerUsedInsert(GlobalValue *GV) {
return CompilerUsed.insert(GV).second;
}
@@ -2265,7 +2369,8 @@ public:
setUsedInitializer(*CompilerUsedV, CompilerUsed);
}
};
-}
+
+} // end anonymous namespace
static bool hasUseOtherThanLLVMUsed(GlobalAlias &GA, const LLVMUsed &U) {
if (GA.use_empty()) // No use at all.
@@ -2580,8 +2685,10 @@ PreservedAnalyses GlobalOptPass::run(Module &M, ModuleAnalysisManager &AM) {
}
namespace {
+
struct GlobalOptLegacyPass : public ModulePass {
static char ID; // Pass identification, replacement for typeid
+
GlobalOptLegacyPass() : ModulePass(ID) {
initializeGlobalOptLegacyPassPass(*PassRegistry::getPassRegistry());
}
@@ -2603,9 +2710,11 @@ struct GlobalOptLegacyPass : public ModulePass {
AU.addRequired<DominatorTreeWrapperPass>();
}
};
-}
+
+} // end anonymous namespace
char GlobalOptLegacyPass::ID = 0;
+
INITIALIZE_PASS_BEGIN(GlobalOptLegacyPass, "globalopt",
"Global Variable Optimizer", false, false)
INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)