From e511186183d49fb9c4ebefe746ca65e5d9275ff4 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Wed, 27 Jul 2011 19:47:34 +0000 Subject: [PATCH] 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 --- lib/Transforms/IPO/ConstantMerge.cpp | 49 +++++++++++++++++---- test/Transforms/ConstantMerge/merge-both.ll | 17 ++++++- 2 files changed, 56 insertions(+), 10 deletions(-) diff --git a/lib/Transforms/IPO/ConstantMerge.cpp b/lib/Transforms/IPO/ConstantMerge.cpp index a21efced73b..c3ecb7afff7 100644 --- a/lib/Transforms/IPO/ConstantMerge.cpp +++ b/lib/Transforms/IPO/ConstantMerge.cpp @@ -23,7 +23,9 @@ #include "llvm/DerivedTypes.h" #include "llvm/Module.h" #include "llvm/Pass.h" +#include "llvm/Target/TargetData.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/Statistic.h" using namespace llvm; @@ -37,10 +39,18 @@ namespace { initializeConstantMergePass(*PassRegistry::getPassRegistry()); } - // run - For this pass, process all of the globals in the module, - // eliminating duplicate constants. - // + // For this pass, process all of the globals in the module, eliminating + // duplicate constants. 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(); } +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) { + TD = getAnalysisIfAvailable(); + // Find all the globals that are marked "used". These cannot be merged. SmallPtrSet UsedGlobals; FindUsedValues(M.getGlobalVariable("llvm.used"), UsedGlobals); FindUsedValues(M.getGlobalVariable("llvm.compiler.used"), UsedGlobals); - // Map unique constant/section pairs to globals. We don't want to merge - // globals in different sections. - DenseMap CMap; + // Map unique pairs to globals. We don't + // want to merge globals of unknown alignment with those of explicit + // alignment. If we have TargetData, we always know the alignment. + DenseMap, GlobalVariable*> CMap; // Replacements - This vector contains a list of replacements to perform. SmallVector, 32> Replacements; @@ -120,7 +143,8 @@ bool ConstantMerge::runOnModule(Module &M) { Constant *Init = GV->getInitializer(); // Check to see if the initializer is already known. - GlobalVariable *&Slot = CMap[Init]; + PointerIntPair Pair(Init, hasKnownAlignment(GV)); + GlobalVariable *&Slot = CMap[Pair]; // 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 @@ -152,7 +176,8 @@ bool ConstantMerge::runOnModule(Module &M) { Constant *Init = GV->getInitializer(); // Check to see if the initializer is already known. - GlobalVariable *Slot = CMap[Init]; + PointerIntPair Pair(Init, hasKnownAlignment(GV)); + GlobalVariable *Slot = CMap[Pair]; if (!Slot || Slot == GV) continue; @@ -175,6 +200,14 @@ bool ConstantMerge::runOnModule(Module &M) { // now. This avoid invalidating the pointers in CMap, which are unneeded // now. 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. Replacements[i].first->replaceAllUsesWith(Replacements[i].second); diff --git a/test/Transforms/ConstantMerge/merge-both.ll b/test/Transforms/ConstantMerge/merge-both.ll index 0282f464aee..b71eb437dbc 100644 --- a/test/Transforms/ConstantMerge/merge-both.ll +++ b/test/Transforms/ConstantMerge/merge-both.ll @@ -1,5 +1,7 @@ ; RUN: opt -constmerge %s -S -o - | FileCheck %s ; 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*) @@ -14,13 +16,24 @@ declare void @zed(%struct.foobar*, %struct.foobar*) ; CHECK-NOT: @ ; CHECK: @var2 = 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() { entry: call void @zed(%struct.foobar* @var1, %struct.foobar* @var2) 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 } -- 2.34.1