first Version of Loop Unrolling

This commit is contained in:
Nils Hölscher 2022-05-03 11:13:37 +02:00
parent be3904a256
commit 5e6e0e6c90
4 changed files with 304 additions and 97 deletions

4
.vscode/launch.json vendored
View File

@ -7,13 +7,13 @@
{ {
"type": "lldb", "type": "lldb",
"request": "launch", "request": "launch",
"name": "LLDB cnt", "name": "LLDB Unrolling",
"program": "/usr/bin/opt", "program": "/usr/bin/opt",
"args": [ "args": [
"-load-pass-plugin", "-load-pass-plugin",
"${workspaceFolder}/build/libCacheAnalysisPass.so", "${workspaceFolder}/build/libCacheAnalysisPass.so",
"-passes=lru-misses", "-passes=lru-misses",
"${workspaceFolder}/test/cnt.ll", "${workspaceFolder}/test/fft1.ll",
"-o", "-o",
"/dev/null" "/dev/null"
], ],

View File

@ -56,6 +56,7 @@ struct CacheAnalysisPass : PassInfoMixin<CacheAnalysisPass> {
bool PrintEdgesPost = false; bool PrintEdgesPost = false;
bool DumpToDot = true; bool DumpToDot = true;
bool DumpNodes = false; bool DumpNodes = false;
bool LoopUnrolling = true;
// Assume a 4kB Cache // Assume a 4kB Cache
// with 16 Sets, associativity of 4 and Cachelines fitting two // with 16 Sets, associativity of 4 and Cachelines fitting two
@ -228,14 +229,15 @@ struct CacheAnalysisPass : PassInfoMixin<CacheAnalysisPass> {
if (PrintAddresses) if (PrintAddresses)
addressPrinter(F); addressPrinter(F);
} }
if(LoopUnrolling)
AC.unrollLoops();
AC.fillAbstractCache(EntryAddress);
if (DumpNodes)
AC.dumpNodes();
if (PrintEdgesPost) if (PrintEdgesPost)
AC.dumpEdges(); AC.dumpEdges();
if (DumpToDot) if (DumpToDot)
AC.dumpDotFile(); AC.dumpDotFile();
AC.unrollLoops();
AC.fillAbstractCache(EntryAddress);
if (DumpNodes)
AC.dumpNodes();
outs() << "MustHits: " << AC.collectHits() << "\n"; outs() << "MustHits: " << AC.collectHits() << "\n";
outs() << "MayMisses: " << AC.collectMisses() << "\n"; outs() << "MayMisses: " << AC.collectMisses() << "\n";
return PreservedAnalyses::all(); return PreservedAnalyses::all();

View File

@ -114,46 +114,36 @@ case $1 in
echo "Currently not available!" echo "Currently not available!"
echo "But please continue to implement the must join," echo "But please continue to implement the must join,"
echo "to the best of your abilities and check for updates!" echo "to the best of your abilities and check for updates!"
# run "fft1" run "fft1"
# echo "==== Correct fft1 ====" echo "==== Correct fft1 ===="
# echo "MustHits: 16" echo "MustHits: 16"
# echo "MayMisses: 280" echo "MayMisses: 280"
# echo echo
# run "bsort100" run "cnt"
# echo "==== Correct bsort100 ====" echo "==== Correct cnt ===="
# echo "MustHits: 1" echo "MustHits: x"
# echo "MayMisses: 41" echo "MayMisses: xx"
# echo echo
# run "lms" run "crc"
# echo "==== Correct lms ====" echo "==== Correct crc ===="
# echo "MustHits: 5" echo "MustHits: x"
# echo "MayMisses: 288" echo "MayMisses: xx"
# echo echo
# run "minver" run "duff"
# echo "==== Correct minver ====" echo "==== Correct duff ===="
# echo "MustHits: 6" echo "MustHits: x"
# echo "MayMisses: 224" echo "MayMisses: xx"
# echo echo
# run "qsort-exam" run "insertsort"
# echo "==== Correct qsort-exam ====" echo "==== Correct insertsort ===="
# echo "MustHits: 2" echo "MustHits: x"
# echo "MayMisses: 152" echo "MayMisses: xx"
# echo echo
# run "recursion" run "matmult"
# echo "==== Correct recursion ====" echo "==== Correct matmult ===="
# echo "MustHits: 8" echo "MustHits: x"
# echo "MayMisses: 8" echo "MayMisses: x"
# echo echo
# run "select"
# echo "==== Correct select ===="
# echo "MustHits: 4"
# echo "MayMisses: 108"
# echo
# run "whet"
# echo "==== Correct whet ===="
# echo "MustHits: 5"
# echo "MayMisses: 265"
# echo
;; ;;
a | all) a | all)
clean clean

View File

@ -30,7 +30,6 @@ public: // everything is public, because IDGAF
// map keys are instruction Addresses. // map keys are instruction Addresses.
std::map<unsigned int, std::list<unsigned int>> Edges; std::map<unsigned int, std::list<unsigned int>> Edges;
std::map<unsigned int, AbstractState> Nodes; std::map<unsigned int, AbstractState> Nodes;
unsigned int NumberOfNodes = 0;
AbstractCache() {} AbstractCache() {}
@ -46,9 +45,120 @@ public: // everything is public, because IDGAF
Nodes[Suc].Predecessors.push_back(Pre); Nodes[Suc].Predecessors.push_back(Pre);
} }
/**
* @brief Add an Edge to the AbstractStateGraph
*
* @param Pre
* @param Suc
*/
void removeEdge(unsigned int Pre, unsigned int Suc) {
Edges[Pre].remove(Suc);
Nodes[Pre].Successors.remove(Suc);
Nodes[Suc].Predecessors.remove(Pre);
}
/**
* @brief Add an Empty node @NodeAddr
*
* @param NodeAddr
* @return unsigned int
*/
unsigned int addEmptyNode(unsigned int NodeAddr) { unsigned int addEmptyNode(unsigned int NodeAddr) {
Nodes[NumberOfNodes++] = AbstractState(NodeAddr); int I = Nodes.size();
return NumberOfNodes; Nodes[I] = AbstractState(NodeAddr);
return I;
}
/**
* @brief Returns True if a path From -> To exists.
*
* @param From
* @param To
* @return true
* @return false
*/
bool findPath(unsigned int From, unsigned int To) {
std::map<unsigned int, bool> Visited;
Visited[From] = false;
bool Ret = false;
for (auto Visitor : Visited) {
if (!Visitor.second) {
for (unsigned int Next : Edges[Visitor.first]) {
if (Next == To) {
return true;
}
Visited[Next] = false;
}
}
Visited[Visitor.first] = true;
}
return false;
}
/**
* @brief Removes all Nested loops from the handed LoopBody
*
* @param LoopBodyIn
* @param OrigNodeToUnrolledNode
*/
void removeNestedLoops(
std::list<unsigned int> LoopBodyIn,
std::map<unsigned int, unsigned int> OrigNodeToUnrolledNode) {
unsigned int LoopHead = LoopBodyIn.front();
unsigned int LoopTail = LoopBodyIn.back();
unsigned int NestLoopTail;
for (unsigned int NodeNr : LoopBodyIn) {
bool IsLoopHead = false;
bool FoundLoopBody = false;
unsigned int LoopBodySize = 0;
int NestLoopHead = 0;
NestLoopHead = NodeNr;
if (Nodes[NodeNr].Predecessors.size() > 1) {
IsLoopHead = true;
FoundLoopBody = false;
LoopBodySize++;
// is loop head?
for (unsigned int Pre : Nodes[NodeNr].Predecessors) {
if (Pre > NodeNr) {
// Might be loop head.
// check if all States between Pre and NodeNr are a coherent set.
for (unsigned int I = NodeNr; I < Pre; I++) {
// Check if all out going edges are in the set
for (unsigned int Succ : Nodes[I].Successors) {
if (Succ > Pre) {
// Set is not coherent
IsLoopHead = false;
break;
}
}
// check if all incoming edges are in the set.
if (IsLoopHead && I != NodeNr)
for (unsigned int Pred : Nodes[I].Predecessors) {
if (Pred < NodeNr) {
// Set is not coherent
IsLoopHead = false;
break;
}
}
FoundLoopBody = true;
LoopBodySize++;
}
NestLoopTail = Pre;
} else if (!FoundLoopBody) {
// If no coherent Loopbody exist we cannot unroll.
NestLoopHead = 0;
IsLoopHead = false;
}
if (FoundLoopBody) {
// Check if a Path between Head and Tail exists,
// if not its not a loop.
if (findPath(NestLoopHead, NestLoopTail))
removeEdge(OrigNodeToUnrolledNode[NestLoopTail],
OrigNodeToUnrolledNode[NestLoopHead]);
}
}
}
}
} }
/** /**
@ -57,15 +167,23 @@ public: // everything is public, because IDGAF
* @param NodeNr * @param NodeNr
*/ */
void unrollLoops() { void unrollLoops() {
for (auto NodePair : Nodes) { unsigned int NestedBorder = 0;
unsigned int NodeNr = NodePair.first; unsigned int LastNode = Nodes.size();
if (NodeNr == 34) { unsigned int IterationCounter = 0;
llvm::outs() << "HI\n"; for (std::pair<const unsigned int, AbstractState> NodePair : Nodes) {
IterationCounter++;
if (NodePair.first == LastNode) {
break;
} }
unsigned int NodeNr = NodePair.first;
// Don't unroll nested loops
if (NodeNr < NestedBorder)
continue;
bool IsLoopHead = false; bool IsLoopHead = false;
bool FoundLoopBody = false; bool FoundLoopBody = false;
bool Verbose = true; bool Verbose = false;
std::list<unsigned int> LoopBody; std::list<unsigned int> LoopBody;
std::list<unsigned int> AdditionalLoopTails;
if (Nodes[NodeNr].Predecessors.size() > 1) { if (Nodes[NodeNr].Predecessors.size() > 1) {
IsLoopHead = true; IsLoopHead = true;
// is loop head? // is loop head?
@ -73,15 +191,42 @@ public: // everything is public, because IDGAF
if (Pre > NodeNr) { if (Pre > NodeNr) {
// Might be loop head. // Might be loop head.
// check if all States between Pre and NodeNr are a coherent set. // check if all States between Pre and NodeNr are a coherent set.
for (uint I = NodeNr; I < Pre; I++) { for (unsigned int I = NodeNr; I < Pre; I++) {
LoopBody.push_back(I); // Check if all out going edges are in the set
for (uint Succ : Nodes[I].Successors) { for (unsigned int Succ : Nodes[I].Successors) {
if (Succ > Pre) { for (unsigned int PreI : Nodes[I].Predecessors) {
// Set is not coherent // Handle if we have multiple Loopheads.
IsLoopHead = false; if (PreI >= Pre && I != NodeNr) {
break; // I and Pre are Looptail.
{
if (std::find(AdditionalLoopTails.begin(),
AdditionalLoopTails.end(),
I) == AdditionalLoopTails.end()) {
AdditionalLoopTails.push_back(I);
break;
}
}
}
if (std::find(LoopBody.begin(), LoopBody.end(), I) ==
LoopBody.end())
LoopBody.push_back(I);
if (Succ > Pre) {
// Set is not coherent
IsLoopHead = false;
break;
}
} }
} }
// check if all incoming edges are in the set.
if (IsLoopHead && I != NodeNr)
for (unsigned int Pred : Nodes[I].Predecessors) {
if (Pred < NodeNr) {
// Set is not coherent
IsLoopHead = false;
break;
}
}
FoundLoopBody = true; FoundLoopBody = true;
} }
LoopBody.push_back(Pre); LoopBody.push_back(Pre);
@ -92,45 +237,91 @@ public: // everything is public, because IDGAF
} }
} }
} }
if (IsLoopHead && Verbose) {
llvm::outs() << "Found LoopHead @: " << NodeNr << "\n";
llvm::outs() << "With Body: {\n";
int I = 1;
for (auto Node : LoopBody) {
llvm::outs() << Node << ", ";
if (!(I++ % 5)) {
llvm::outs() << "\n";
}
}
llvm::outs() << "}\n";
}
// Found Loop Head and Body! // Found Loop Head and Body!
// TODO: Now unroll
// Add empty unrolled Nodes // Add empty unrolled Nodes
// Map points from OrigNode To Unrolled Node. // Map points from OrigNode To Unrolled Node.
std::map<unsigned int, unsigned int> OrigNodeToUnrolledNode; if (FoundLoopBody) {
for (auto Node : LoopBody) { std::map<unsigned int, unsigned int> OrigNodeToUnrolledNode;
// Node to unroll for (unsigned int Node : LoopBody) {
AbstractState UnrolledNode(Nodes[Node]); // Node to unroll
UnrolledNode.setUnrolled(1); AbstractState UnrolledNode(Nodes[Node]);
Nodes[NumberOfNodes++] = UnrolledNode; UnrolledNode.setUnrolled(1);
OrigNodeToUnrolledNode[Node] = NumberOfNodes; unsigned int I = Nodes.size();
} Nodes[I] = UnrolledNode;
OrigNodeToUnrolledNode[Node] = I;
unsigned int LoopHead = LoopBody.front(); assert(Nodes[OrigNodeToUnrolledNode[Node]].Unrolled == 1);
LoopBody.pop_front(); assert(Nodes[Node].Addr == Nodes[OrigNodeToUnrolledNode[Node]].Addr);
unsigned int LoopTail = LoopBody.back();
LoopBody.pop_back();
for (auto Node : LoopBody) {
for (auto Succ : Nodes[Node].Successors) {
// Add All successors to unrolled Node
Nodes[OrigNodeToUnrolledNode[Node]].Successors.push_back(
OrigNodeToUnrolledNode[Succ]);
} }
for (auto Pre : Nodes[Node].Predecessors) {
// Add All predecessors to unrolled Node // LoopTail and Head have to be processed different
Nodes[OrigNodeToUnrolledNode[Node]].Successors.push_back( unsigned int LoopTail = LoopBody.back();
OrigNodeToUnrolledNode[Pre]); LoopBody.pop_back();
NestedBorder = LoopTail;
unsigned int LoopHead = LoopBody.front();
LoopBody.pop_front();
// Find State entering to LoopHead ()
unsigned int LoopHeadEntry = 0;
for (unsigned int Pre : Nodes[LoopHead].Predecessors) {
if (Pre < LoopHead) {
LoopHeadEntry = Pre;
break;
}
}
// Make LoopHeadEntry point to unrolled state instead of the loop.
addEdge(LoopHeadEntry, OrigNodeToUnrolledNode[LoopHead]);
removeEdge(LoopHeadEntry, LoopHead);
// Connect unrolled Loop to the the original Loop.
if (AdditionalLoopTails.size() == 0)
addEdge(OrigNodeToUnrolledNode[LoopTail], LoopHead);
for (auto Tail : AdditionalLoopTails)
addEdge(OrigNodeToUnrolledNode[Tail], LoopHead);
// Fix all other states
addEdge(OrigNodeToUnrolledNode[LoopBody.back()],
OrigNodeToUnrolledNode[LoopTail]);
for (unsigned int Node : LoopBody) {
for (unsigned int Pre : Nodes[Node].Predecessors) {
// if (std::find(LoopBody.begin(), LoopBody.end(), Pre) !=
// LoopBody.end())
// Add All predecessors and successors to unrolled Nodes
addEdge(OrigNodeToUnrolledNode[Pre], OrigNodeToUnrolledNode[Node]);
}
}
// Remove Nested loops in unrolled loop
removeNestedLoops(LoopBody, OrigNodeToUnrolledNode);
if (Verbose && FoundLoopBody) {
llvm::outs() << "Found LoopHead @: " << NodeNr << "\n";
llvm::outs() << "With LoopTail @: " << LoopTail << "\n";
llvm::outs() << "With Body: {\n";
int I = 1;
for (auto Node : LoopBody) {
llvm::outs() << Node << ", ";
if (!(I++ % 5)) {
llvm::outs() << "\n";
}
}
llvm::outs() << "}\n";
llvm::outs() << "Unrolled States: {\n";
I = 1;
for (auto Node : LoopBody) {
llvm::outs() << OrigNodeToUnrolledNode[Node] << ", ";
if (!(I++ % 5)) {
llvm::outs() << "\n";
}
}
llvm::outs() << "}\n";
I = 1;
llvm::outs() << "OrigNodeToUnrolledNode: {\n";
for (auto Nr : OrigNodeToUnrolledNode) {
llvm::outs() << Nr.first << "->" << Nr.second << ", ";
if (!(I++ % 3))
llvm::outs() << "\n";
}
llvm::outs() << "}\n";
} }
} }
} }
@ -144,7 +335,6 @@ public: // everything is public, because IDGAF
*/ */
void fillAbstractCache(unsigned int NodeNr) { void fillAbstractCache(unsigned int NodeNr) {
// if(isLoopHead(NodeNr)) // if(isLoopHead(NodeNr))
// unrollLoop(NodeNr);
Nodes[NodeNr].Computed = true; Nodes[NodeNr].Computed = true;
for (unsigned int SuccNr : Nodes[NodeNr].Successors) { for (unsigned int SuccNr : Nodes[NodeNr].Successors) {
Nodes[SuccNr]; Nodes[SuccNr];
@ -162,6 +352,11 @@ public: // everything is public, because IDGAF
return; return;
} }
/**
* @brief Return number of measured Hits
*
* @return unsigned int
*/
unsigned int collectHits() { unsigned int collectHits() {
unsigned int Hits = 0; unsigned int Hits = 0;
for (auto const &E : Edges) { for (auto const &E : Edges) {
@ -174,6 +369,11 @@ public: // everything is public, because IDGAF
return Hits; return Hits;
} }
/**
* @brief Return number of measured Misses
*
* @return unsigned int
*/
unsigned int collectMisses() { unsigned int collectMisses() {
unsigned int Misses = 0; unsigned int Misses = 0;
for (auto const &E : Edges) { for (auto const &E : Edges) {
@ -186,6 +386,10 @@ public: // everything is public, because IDGAF
return Misses; return Misses;
} }
/**
* @brief Prints all Edges to Console
*
*/
void dumpEdges() { void dumpEdges() {
llvm::outs() << "Dumping Edges:\n"; llvm::outs() << "Dumping Edges:\n";
for (auto const &E : Edges) { for (auto const &E : Edges) {
@ -203,6 +407,10 @@ public: // everything is public, because IDGAF
} }
} }
/**
* @brief Dumps the Graph to a out.dot file
*
*/
void dumpDotFile() { void dumpDotFile() {
bool PrintOld = true; bool PrintOld = true;
std::ofstream DotFile; std::ofstream DotFile;
@ -213,6 +421,9 @@ public: // everything is public, because IDGAF
for (unsigned int To : E.second) { for (unsigned int To : E.second) {
if (PrintOld) { if (PrintOld) {
DotFile << E.first << " -> " << To << "\n"; DotFile << E.first << " -> " << To << "\n";
if (Nodes[E.first].Unrolled) {
DotFile << E.first << " [color = red]\n";
}
} else { } else {
DotFile << Nodes[E.first].Addr << "." << Nodes[E.first].Unrolled DotFile << Nodes[E.first].Addr << "." << Nodes[E.first].Unrolled
<< " -> " << Nodes[To].Addr << "." << Nodes[To].Unrolled << " -> " << Nodes[To].Addr << "." << Nodes[To].Unrolled
@ -224,6 +435,10 @@ public: // everything is public, because IDGAF
DotFile.close(); DotFile.close();
} }
/**
* @brief Prints all nodes to Console
*
*/
void dumpNodes() { void dumpNodes() {
for (auto const &E : Edges) { for (auto const &E : Edges) {
Nodes[E.first].dump(); Nodes[E.first].dump();