Skip to content

Commit 47fe1b6

Browse files
author
Krzysztof Parzyszek
committed
[RDF] Lower the sorting complexity in RDFLiveness::getAllReachingDefs
The sorting is needed, because reaching defs are (logically) ordered, but are not collected in that order. This change will break up the single call to std::sort into a series of smaller sorts, each of which should use a cheaper comparison function than the original.
1 parent bf82ff6 commit 47fe1b6

File tree

1 file changed

+78
-38
lines changed

1 file changed

+78
-38
lines changed

llvm/lib/CodeGen/RDFLiveness.cpp

+78-38
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,10 @@
2323
// <10.1145/2086696.2086706>. <hal-00647369>
2424
//
2525
#include "llvm/ADT/BitVector.h"
26+
#include "llvm/ADT/DenseMap.h"
2627
#include "llvm/ADT/STLExtras.h"
2728
#include "llvm/ADT/SetVector.h"
29+
#include "llvm/ADT/SmallSet.h"
2830
#include "llvm/CodeGen/MachineBasicBlock.h"
2931
#include "llvm/CodeGen/MachineDominanceFrontier.h"
3032
#include "llvm/CodeGen/MachineDominators.h"
@@ -108,7 +110,7 @@ NodeList Liveness::getAllReachingDefs(RegisterRef RefRR,
108110
const RegisterAggr &DefRRs) {
109111
NodeList RDefs; // Return value.
110112
SetVector<NodeId> DefQ;
111-
SetVector<NodeId> Owners;
113+
DenseMap<MachineInstr*, uint32_t> OrdMap;
112114

113115
// Dead defs will be treated as if they were live, since they are actually
114116
// on the data-flow path. They cannot be ignored because even though they
@@ -151,18 +153,9 @@ NodeList Liveness::getAllReachingDefs(RegisterRef RefRR,
151153
for (auto S : DFG.getRelatedRefs(TA.Addr->getOwner(DFG), TA))
152154
if (NodeId RD = NodeAddr<RefNode*>(S).Addr->getReachingDef())
153155
DefQ.insert(RD);
154-
}
155-
156-
// Remove all non-phi defs that are not aliased to RefRR, and collect
157-
// the owners of the remaining defs.
158-
SetVector<NodeId> Defs;
159-
for (NodeId N : DefQ) {
160-
auto TA = DFG.addr<DefNode*>(N);
161-
bool IsPhi = TA.Addr->getFlags() & NodeAttrs::PhiRef;
162-
if (!IsPhi && !PRI.alias(RefRR, TA.Addr->getRegRef(DFG)))
163-
continue;
164-
Defs.insert(TA.Id);
165-
Owners.insert(TA.Addr->getOwner(DFG).Id);
156+
// Don't visit sibling defs. They share the same reaching def (which
157+
// will be visited anyway), but they define something not aliased to
158+
// this ref.
166159
}
167160

168161
// Return the MachineBasicBlock containing a given instruction.
@@ -174,38 +167,81 @@ NodeList Liveness::getAllReachingDefs(RegisterRef RefRR,
174167
NodeAddr<BlockNode*> BA = PA.Addr->getOwner(DFG);
175168
return BA.Addr->getCode();
176169
};
177-
// Less(A,B) iff instruction A is further down in the dominator tree than B.
178-
auto Less = [&Block,this] (NodeId A, NodeId B) -> bool {
170+
171+
SmallSet<NodeId,32> Defs;
172+
173+
// Remove all non-phi defs that are not aliased to RefRR, and segregate
174+
// the the remaining defs into buckets for containing blocks.
175+
std::map<NodeId, NodeAddr<InstrNode*>> Owners;
176+
std::map<MachineBasicBlock*, SmallVector<NodeId,32>> Blocks;
177+
for (NodeId N : DefQ) {
178+
auto TA = DFG.addr<DefNode*>(N);
179+
bool IsPhi = TA.Addr->getFlags() & NodeAttrs::PhiRef;
180+
if (!IsPhi && !PRI.alias(RefRR, TA.Addr->getRegRef(DFG)))
181+
continue;
182+
Defs.insert(TA.Id);
183+
NodeAddr<InstrNode*> IA = TA.Addr->getOwner(DFG);
184+
Owners[TA.Id] = IA;
185+
Blocks[Block(IA)].push_back(IA.Id);
186+
}
187+
188+
auto Precedes = [this,&OrdMap] (NodeId A, NodeId B) {
179189
if (A == B)
180190
return false;
181-
auto OA = DFG.addr<InstrNode*>(A), OB = DFG.addr<InstrNode*>(B);
182-
MachineBasicBlock *BA = Block(OA), *BB = Block(OB);
183-
if (BA != BB)
184-
return MDT.dominates(BB, BA);
185-
// They are in the same block.
191+
NodeAddr<InstrNode*> OA = DFG.addr<InstrNode*>(A);
192+
NodeAddr<InstrNode*> OB = DFG.addr<InstrNode*>(B);
186193
bool StmtA = OA.Addr->getKind() == NodeAttrs::Stmt;
187194
bool StmtB = OB.Addr->getKind() == NodeAttrs::Stmt;
188-
if (StmtA) {
189-
if (!StmtB) // OB is a phi and phis dominate statements.
190-
return true;
191-
MachineInstr *CA = NodeAddr<StmtNode*>(OA).Addr->getCode();
192-
MachineInstr *CB = NodeAddr<StmtNode*>(OB).Addr->getCode();
193-
// The order must be linear, so tie-break such equalities.
194-
if (CA == CB)
195-
return A < B;
196-
return MDT.dominates(CB, CA);
197-
} else {
198-
// OA is a phi.
199-
if (StmtB)
200-
return false;
201-
// Both are phis. There is no ordering between phis (in terms of
202-
// the data-flow), so tie-break this via node id comparison.
195+
if (StmtA && StmtB) {
196+
const MachineInstr *InA = NodeAddr<StmtNode*>(OA).Addr->getCode();
197+
const MachineInstr *InB = NodeAddr<StmtNode*>(OB).Addr->getCode();
198+
assert(InA->getParent() == InB->getParent());
199+
auto FA = OrdMap.find(InA);
200+
if (FA != OrdMap.end())
201+
return FA->second < OrdMap.find(InB)->second;
202+
const MachineBasicBlock *BB = InA->getParent();
203+
for (auto It = BB->begin(), E = BB->end(); It != E; ++It) {
204+
if (It == InA->getIterator())
205+
return true;
206+
if (It == InB->getIterator())
207+
return false;
208+
}
209+
llvm_unreachable("InA and InB should be in the same block");
210+
}
211+
// One of them is a phi node.
212+
if (!StmtA && !StmtB) {
213+
// Both are phis, which are unordered. Break the tie by id numbers.
203214
return A < B;
204215
}
216+
// Only one of them is a phi. Phis always precede statements.
217+
return !StmtA;
205218
};
206219

207-
std::vector<NodeId> Tmp(Owners.begin(), Owners.end());
208-
llvm::sort(Tmp, Less);
220+
auto GetOrder = [&OrdMap] (MachineBasicBlock &B) {
221+
uint32_t Pos = 0;
222+
for (MachineInstr &In : B)
223+
OrdMap.insert({&In, ++Pos});
224+
};
225+
226+
// For each block, sort the nodes in it.
227+
std::vector<MachineBasicBlock*> TmpBB;
228+
for (auto &Bucket : Blocks) {
229+
TmpBB.push_back(Bucket.first);
230+
if (Bucket.second.size() > 2)
231+
GetOrder(*Bucket.first);
232+
std::sort(Bucket.second.begin(), Bucket.second.end(), Precedes);
233+
}
234+
235+
// Sort the blocks with respect to dominance.
236+
std::sort(TmpBB.begin(), TmpBB.end(), [this](auto A, auto B) {
237+
return MDT.dominates(A, B);
238+
});
239+
240+
std::vector<NodeId> TmpInst;
241+
for (auto I = TmpBB.rbegin(), E = TmpBB.rend(); I != E; ++I) {
242+
auto &Bucket = Blocks[*I];
243+
TmpInst.insert(TmpInst.end(), Bucket.rbegin(), Bucket.rend());
244+
}
209245

210246
// The vector is a list of instructions, so that defs coming from
211247
// the same instruction don't need to be artificially ordered.
@@ -220,14 +256,18 @@ NodeList Liveness::getAllReachingDefs(RegisterRef RefRR,
220256
// *d3<C> If A \incl BuC, and B \incl AuC, then *d2 would be
221257
// covered if we added A first, and A would be covered
222258
// if we added B first.
259+
// In this example we want both A and B, because we don't want to give
260+
// either one priority over the other, since they belong to the same
261+
// statement.
223262

224263
RegisterAggr RRs(DefRRs);
225264

226265
auto DefInSet = [&Defs] (NodeAddr<RefNode*> TA) -> bool {
227266
return TA.Addr->getKind() == NodeAttrs::Def &&
228267
Defs.count(TA.Id);
229268
};
230-
for (NodeId T : Tmp) {
269+
270+
for (NodeId T : TmpInst) {
231271
if (!FullChain && RRs.hasCoverOf(RefRR))
232272
break;
233273
auto TA = DFG.addr<InstrNode*>(T);

0 commit comments

Comments
 (0)