UseListOrder: Order GlobalValue uses after initializers

To avoid unnecessary forward references, the reader doesn't process
initializers of `GlobalValue`s until after the constant pool has been
processed, and then in reverse order.  Model this when predicting
use-list order.  This gets two more Bitcode tests passing with
`llvm-uselistorder`.

Part of PR5680.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@214242 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Duncan P. N. Exon Smith
2014-07-29 23:06:14 +00:00
parent abf3c77acb
commit 9b9c19509f
3 changed files with 57 additions and 14 deletions

View File

@@ -28,6 +28,17 @@ using namespace llvm;
namespace { namespace {
struct OrderMap { struct OrderMap {
DenseMap<const Value *, std::pair<unsigned, bool>> IDs; DenseMap<const Value *, std::pair<unsigned, bool>> IDs;
unsigned LastGlobalConstantID;
unsigned LastGlobalValueID;
OrderMap() : LastGlobalConstantID(0), LastGlobalValueID(0) {}
bool isGlobalConstant(unsigned ID) const {
return ID <= LastGlobalConstantID;
}
bool isGlobalValue(unsigned ID) const {
return ID <= LastGlobalValueID && !isGlobalConstant(ID);
}
unsigned size() const { return IDs.size(); } unsigned size() const { return IDs.size(); }
std::pair<unsigned, bool> &operator[](const Value *V) { return IDs[V]; } std::pair<unsigned, bool> &operator[](const Value *V) { return IDs[V]; }
@@ -44,7 +55,7 @@ static void orderValue(const Value *V, OrderMap &OM) {
if (const Constant *C = dyn_cast<Constant>(V)) if (const Constant *C = dyn_cast<Constant>(V))
if (C->getNumOperands() && !isa<GlobalValue>(C)) if (C->getNumOperands() && !isa<GlobalValue>(C))
for (const Value *Op : C->operands()) for (const Value *Op : C->operands())
if (!isa<BasicBlock>(Op)) if (!isa<BasicBlock>(Op) && !isa<GlobalValue>(Op))
orderValue(Op, OM); orderValue(Op, OM);
// Note: we cannot cache this lookup above, since inserting into the map // Note: we cannot cache this lookup above, since inserting into the map
@@ -57,12 +68,11 @@ static OrderMap orderModule(const Module *M) {
// and ValueEnumerator::incorporateFunction(). // and ValueEnumerator::incorporateFunction().
OrderMap OM; OrderMap OM;
for (const GlobalVariable &G : M->globals()) // In the reader, initializers of GlobalValues are set *after* all the
orderValue(&G, OM); // globals have been read. Rather than awkwardly modeling this behaviour
for (const Function &F : *M) // directly in predictValueUseListOrderImpl(), just assign IDs to
orderValue(&F, OM); // initializers of GlobalValues before GlobalValues themselves to model this
for (const GlobalAlias &A : M->aliases()) // implicitly.
orderValue(&A, OM);
for (const GlobalVariable &G : M->globals()) for (const GlobalVariable &G : M->globals())
if (G.hasInitializer()) if (G.hasInitializer())
orderValue(G.getInitializer(), OM); orderValue(G.getInitializer(), OM);
@@ -71,6 +81,23 @@ static OrderMap orderModule(const Module *M) {
for (const Function &F : *M) for (const Function &F : *M)
if (F.hasPrefixData()) if (F.hasPrefixData())
orderValue(F.getPrefixData(), OM); orderValue(F.getPrefixData(), OM);
OM.LastGlobalConstantID = OM.size();
// Initializers of GlobalValues are processed in
// BitcodeReader::ResolveGlobalAndAliasInits(). Match the order there rather
// than ValueEnumerator, and match the code in predictValueUseListOrderImpl()
// by giving IDs in reverse order.
//
// Since GlobalValues never reference each other directly (just through
// initializers), their relative IDs only matter for determining order of
// uses in their initializers.
for (const Function &F : *M)
orderValue(&F, OM);
for (const GlobalAlias &A : M->aliases())
orderValue(&A, OM);
for (const GlobalVariable &G : M->globals())
orderValue(&G, OM);
OM.LastGlobalValueID = OM.size();
for (const Function &F : *M) { for (const Function &F : *M) {
if (F.isDeclaration()) if (F.isDeclaration())
@@ -110,8 +137,8 @@ static void predictValueUseListOrderImpl(const Value *V, const Function *F,
// We may have lost some users. // We may have lost some users.
return; return;
std::sort(List.begin(), List.end(), bool IsGlobalValue = OM.isGlobalValue(ID);
[&OM, ID](const Entry &L, const Entry &R) { std::sort(List.begin(), List.end(), [&](const Entry &L, const Entry &R) {
const Use *LU = L.first; const Use *LU = L.first;
const Use *RU = R.first; const Use *RU = R.first;
if (LU == RU) if (LU == RU)
@@ -119,22 +146,36 @@ static void predictValueUseListOrderImpl(const Value *V, const Function *F,
auto LID = OM.lookup(LU->getUser()).first; auto LID = OM.lookup(LU->getUser()).first;
auto RID = OM.lookup(RU->getUser()).first; auto RID = OM.lookup(RU->getUser()).first;
// Global values are processed in reverse order.
//
// Moreover, initializers of GlobalValues are set *after* all the globals
// have been read (despite having earlier IDs). Rather than awkwardly
// modeling this behaviour here, orderModule() has assigned IDs to
// initializers of GlobalValues before GlobalValues themselves.
if (OM.isGlobalValue(LID) && OM.isGlobalValue(RID))
return LID < RID;
// If ID is 4, then expect: 7 6 5 1 2 3. // If ID is 4, then expect: 7 6 5 1 2 3.
if (LID < RID) { if (LID < RID) {
if (RID < ID) if (RID < ID)
return true; if (!IsGlobalValue) // GlobalValue uses don't get reversed.
return true;
return false; return false;
} }
if (RID < LID) { if (RID < LID) {
if (LID < ID) if (LID < ID)
return false; if (!IsGlobalValue) // GlobalValue uses don't get reversed.
return false;
return true; return true;
} }
// LID and RID are equal, so we have different operands of the same user. // LID and RID are equal, so we have different operands of the same user.
// Assume operands are added in order for all instructions. // Assume operands are added in order for all instructions.
if (LU->getOperandNo() < RU->getOperandNo()) if (LID < ID)
return LID < ID; if (!IsGlobalValue) // GlobalValue uses don't get reversed.
return ID < LID; return LU->getOperandNo() < RU->getOperandNo();
return LU->getOperandNo() > RU->getOperandNo();
}); });
if (std::is_sorted( if (std::is_sorted(

View File

@@ -1,4 +1,5 @@
; RUN: llvm-dis < %s.bc | FileCheck %s ; RUN: llvm-dis < %s.bc | FileCheck %s
; RUN: llvm-uselistorder < %s.bc -preserve-bc-use-list-order -num-shuffles=5
; local-linkage-default-visibility.3.4.ll.bc was generated by passing this file ; local-linkage-default-visibility.3.4.ll.bc was generated by passing this file
; to llvm-as-3.4. The test checks that LLVM upgrades visibility of symbols ; to llvm-as-3.4. The test checks that LLVM upgrades visibility of symbols

View File

@@ -1,4 +1,5 @@
; RUN: llvm-dis < %s.bc | FileCheck %s ; RUN: llvm-dis < %s.bc | FileCheck %s
; RUN: llvm-uselistorder < %s.bc -preserve-bc-use-list-order -num-shuffles=5
; old-aliases.bc consist of this file assembled with an old llvm-as (3.5 trunk) ; old-aliases.bc consist of this file assembled with an old llvm-as (3.5 trunk)
; from when aliases contained a ConstantExpr. ; from when aliases contained a ConstantExpr.