Teach the ConstantMerge pass about alignment. Fixes PR10514!

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@136250 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Nick Lewycky 2011-07-27 19:47:34 +00:00
parent 84e7f7e267
commit e511186183
2 changed files with 56 additions and 10 deletions

View File

@ -23,7 +23,9 @@
#include "llvm/DerivedTypes.h" #include "llvm/DerivedTypes.h"
#include "llvm/Module.h" #include "llvm/Module.h"
#include "llvm/Pass.h" #include "llvm/Pass.h"
#include "llvm/Target/TargetData.h"
#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/PointerIntPair.h"
#include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/Statistic.h" #include "llvm/ADT/Statistic.h"
using namespace llvm; using namespace llvm;
@ -37,10 +39,18 @@ namespace {
initializeConstantMergePass(*PassRegistry::getPassRegistry()); initializeConstantMergePass(*PassRegistry::getPassRegistry());
} }
// run - For this pass, process all of the globals in the module, // For this pass, process all of the globals in the module, eliminating
// eliminating duplicate constants. // duplicate constants.
//
bool runOnModule(Module &M); bool runOnModule(Module &M);
// Return true iff we can determine the alignment of this global variable.
bool hasKnownAlignment(GlobalVariable *GV) const;
// Return the alignment of the global, including converting the default
// alignment to a concrete value.
unsigned getAlignment(GlobalVariable *GV) const;
const TargetData *TD;
}; };
} }
@ -77,15 +87,28 @@ static bool IsBetterCannonical(const GlobalVariable &A,
return A.hasUnnamedAddr(); return A.hasUnnamedAddr();
} }
bool ConstantMerge::hasKnownAlignment(GlobalVariable *GV) const {
return TD || GV->getAlignment() != 0;
}
unsigned ConstantMerge::getAlignment(GlobalVariable *GV) const {
if (TD)
return TD->getPreferredAlignment(GV);
return GV->getAlignment();
}
bool ConstantMerge::runOnModule(Module &M) { bool ConstantMerge::runOnModule(Module &M) {
TD = getAnalysisIfAvailable<TargetData>();
// Find all the globals that are marked "used". These cannot be merged. // Find all the globals that are marked "used". These cannot be merged.
SmallPtrSet<const GlobalValue*, 8> UsedGlobals; SmallPtrSet<const GlobalValue*, 8> UsedGlobals;
FindUsedValues(M.getGlobalVariable("llvm.used"), UsedGlobals); FindUsedValues(M.getGlobalVariable("llvm.used"), UsedGlobals);
FindUsedValues(M.getGlobalVariable("llvm.compiler.used"), UsedGlobals); FindUsedValues(M.getGlobalVariable("llvm.compiler.used"), UsedGlobals);
// Map unique constant/section pairs to globals. We don't want to merge // Map unique <constants, has-unknown-alignment> pairs to globals. We don't
// globals in different sections. // want to merge globals of unknown alignment with those of explicit
DenseMap<Constant*, GlobalVariable*> CMap; // alignment. If we have TargetData, we always know the alignment.
DenseMap<PointerIntPair<Constant*, 1, bool>, GlobalVariable*> CMap;
// Replacements - This vector contains a list of replacements to perform. // Replacements - This vector contains a list of replacements to perform.
SmallVector<std::pair<GlobalVariable*, GlobalVariable*>, 32> Replacements; SmallVector<std::pair<GlobalVariable*, GlobalVariable*>, 32> Replacements;
@ -120,7 +143,8 @@ bool ConstantMerge::runOnModule(Module &M) {
Constant *Init = GV->getInitializer(); Constant *Init = GV->getInitializer();
// Check to see if the initializer is already known. // Check to see if the initializer is already known.
GlobalVariable *&Slot = CMap[Init]; PointerIntPair<Constant*, 1, bool> Pair(Init, hasKnownAlignment(GV));
GlobalVariable *&Slot = CMap[Pair];
// If this is the first constant we find or if the old on is local, // If this is the first constant we find or if the old on is local,
// replace with the current one. It the current is externally visible // replace with the current one. It the current is externally visible
@ -152,7 +176,8 @@ bool ConstantMerge::runOnModule(Module &M) {
Constant *Init = GV->getInitializer(); Constant *Init = GV->getInitializer();
// Check to see if the initializer is already known. // Check to see if the initializer is already known.
GlobalVariable *Slot = CMap[Init]; PointerIntPair<Constant*, 1, bool> Pair(Init, hasKnownAlignment(GV));
GlobalVariable *Slot = CMap[Pair];
if (!Slot || Slot == GV) if (!Slot || Slot == GV)
continue; continue;
@ -175,6 +200,14 @@ bool ConstantMerge::runOnModule(Module &M) {
// now. This avoid invalidating the pointers in CMap, which are unneeded // now. This avoid invalidating the pointers in CMap, which are unneeded
// now. // now.
for (unsigned i = 0, e = Replacements.size(); i != e; ++i) { for (unsigned i = 0, e = Replacements.size(); i != e; ++i) {
// Bump the alignment if necessary.
if (Replacements[i].first->getAlignment() ||
Replacements[i].second->getAlignment()) {
Replacements[i].second->setAlignment(std::max(
Replacements[i].first->getAlignment(),
Replacements[i].second->getAlignment()));
}
// Eliminate any uses of the dead global. // Eliminate any uses of the dead global.
Replacements[i].first->replaceAllUsesWith(Replacements[i].second); Replacements[i].first->replaceAllUsesWith(Replacements[i].second);

View File

@ -1,5 +1,7 @@
; RUN: opt -constmerge %s -S -o - | FileCheck %s ; RUN: opt -constmerge %s -S -o - | FileCheck %s
; Test that in one run var3 is merged into var2 and var1 into var4. ; Test that in one run var3 is merged into var2 and var1 into var4.
; Test that we merge @var5 and @var6 into one with the higher alignment, and
; don't merge var7/var8 into var5/var6.
declare void @zed(%struct.foobar*, %struct.foobar*) declare void @zed(%struct.foobar*, %struct.foobar*)
@ -14,13 +16,24 @@ declare void @zed(%struct.foobar*, %struct.foobar*)
; CHECK-NOT: @ ; CHECK-NOT: @
; CHECK: @var2 = constant %struct.foobar { i32 2 } ; CHECK: @var2 = constant %struct.foobar { i32 2 }
; CHECK-NEXT: @var4 = constant %struct.foobar { i32 2 } ; CHECK-NEXT: @var4 = constant %struct.foobar { i32 2 }
; CHECK-NOT: @
; CHECK: declare void @zed(%struct.foobar*, %struct.foobar*) declare void @helper([16 x i8]*)
@var5 = internal constant [16 x i8] c"foo1bar2foo3bar\00", align 16
@var6 = private unnamed_addr constant [16 x i8] c"foo1bar2foo3bar\00", align 1
@var7 = internal constant [16 x i8] c"foo1bar2foo3bar\00"
@var8 = private unnamed_addr constant [16 x i8] c"foo1bar2foo3bar\00"
; CHECK-NEXT: @var6 = private constant [16 x i8] c"foo1bar2foo3bar\00", align 16
; CHECK-NEXT: @var8 = private constant [16 x i8] c"foo1bar2foo3bar\00"
define i32 @main() { define i32 @main() {
entry: entry:
call void @zed(%struct.foobar* @var1, %struct.foobar* @var2) call void @zed(%struct.foobar* @var1, %struct.foobar* @var2)
call void @zed(%struct.foobar* @var3, %struct.foobar* @var4) call void @zed(%struct.foobar* @var3, %struct.foobar* @var4)
call void @helper([16 x i8]* @var5)
call void @helper([16 x i8]* @var6)
call void @helper([16 x i8]* @var7)
call void @helper([16 x i8]* @var8)
ret i32 0 ret i32 0
} }