diff --git a/.vscode/launch.json b/.vscode/launch.json index e769ab8..bfa1036 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -4,6 +4,21 @@ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ + { + "type": "lldb", + "request": "launch", + "name": "LLDB cnt", + "program": "/usr/bin/opt", + "args": [ + "-load-pass-plugin", + "${workspaceFolder}/build/libCacheAnalysisPass.so", + "-passes=lru-misses", + "${workspaceFolder}/test/cnt.ll", + "-o", + "/dev/null" + ], + "cwd": "${workspaceFolder}" + }, { "type": "lldb", "request": "launch", diff --git a/CacheAnalysisPass/CacheAnalysisPass.cpp b/CacheAnalysisPass/CacheAnalysisPass.cpp index 47a6ed7..4e253d0 100644 --- a/CacheAnalysisPass/CacheAnalysisPass.cpp +++ b/CacheAnalysisPass/CacheAnalysisPass.cpp @@ -46,52 +46,6 @@ using namespace llvm; // everything in an anonymous namespace. namespace { -std::string typeToName(Type::TypeID Id) { - switch (Id) { - case Type::TypeID::ArrayTyID: - return "ArrayTy"; - case Type::TypeID::BFloatTyID: - return "BFloatTy"; - case Type::TypeID::FloatTyID: - return "FloatTy"; - case Type::TypeID::DoubleTyID: - return "DoubleTy"; - case Type::TypeID::FixedVectorTyID: - return "FixedVectorTy"; - case Type::TypeID::FP128TyID: - return "FP128Ty"; - case Type::TypeID::FunctionTyID: - return "FunctionTy"; - case Type::TypeID::HalfTyID: - return "HalfTy"; - case Type::TypeID::IntegerTyID: - return "IntegerTy"; - case Type::TypeID::LabelTyID: - return "LabelTy"; - case Type::TypeID::MetadataTyID: - return "MetadataTy"; - case Type::TypeID::PointerTyID: - return "PointerTy"; - case Type::TypeID::PPC_FP128TyID: - return "PPC_FP128Ty"; - case Type::TypeID::ScalableVectorTyID: - return "ScalableVectorTy"; - case Type::TypeID::StructTyID: - return "StructTy"; - case Type::TypeID::TokenTyID: - return "TokenTy"; - case Type::TypeID::VoidTyID: - return "VoidTy"; - case Type::TypeID::X86_AMXTyID: - return "X86_AMXTy"; - case Type::TypeID::X86_FP80TyID: - return "X86_FP80Ty"; - case Type::TypeID::X86_MMXTyID: - return "X86_MMXTy"; - } - // should not reach here - return nullptr; -} // New PM implementation struct CacheAnalysisPass : PassInfoMixin { @@ -100,7 +54,7 @@ struct CacheAnalysisPass : PassInfoMixin { bool PrintAddresses = false; bool PrintEdges = false; bool PrintEdgesPost = false; - bool DumpToDot = false; + bool DumpToDot = true; bool DumpNodes = false; // Assume a 4kB Cache @@ -278,6 +232,7 @@ struct CacheAnalysisPass : PassInfoMixin { AC.dumpEdges(); if (DumpToDot) AC.dumpDotFile(); + AC.unrollLoops(); AC.fillAbstractCache(EntryAddress); if (DumpNodes) AC.dumpNodes(); diff --git a/include/AbstractCache.h b/include/AbstractCache.h index f4b47e5..48df8e7 100644 --- a/include/AbstractCache.h +++ b/include/AbstractCache.h @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -29,6 +30,7 @@ public: // everything is public, because IDGAF // map keys are instruction Addresses. std::map> Edges; std::map Nodes; + unsigned int NumberOfNodes = 0; AbstractCache() {} @@ -44,17 +46,112 @@ public: // everything is public, because IDGAF Nodes[Suc].Predecessors.push_back(Pre); } - void addEmptyNode(unsigned int NodeAddr) { - Nodes[NodeAddr] = AbstractState(NodeAddr); + unsigned int addEmptyNode(unsigned int NodeAddr) { + Nodes[NumberOfNodes++] = AbstractState(NodeAddr); + return NumberOfNodes; } + /** + * @brief Unroll Loops. + * + * @param NodeNr + */ + void unrollLoops() { + for (auto NodePair : Nodes) { + unsigned int NodeNr = NodePair.first; + if (NodeNr == 34) { + llvm::outs() << "HI\n"; + } + bool IsLoopHead = false; + bool FoundLoopBody = false; + bool Verbose = true; + std::list LoopBody; + if (Nodes[NodeNr].Predecessors.size() > 1) { + IsLoopHead = true; + // 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 (uint I = NodeNr; I < Pre; I++) { + LoopBody.push_back(I); + for (uint Succ : Nodes[I].Successors) { + if (Succ > Pre) { + // Set is not coherent + IsLoopHead = false; + break; + } + } + FoundLoopBody = true; + } + LoopBody.push_back(Pre); + } else if (!FoundLoopBody) { + // If no coherent Loopbody exist we cannot unroll. + LoopBody.clear(); + IsLoopHead = false; + } + } + } + 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! + // TODO: Now unroll + // Add empty unrolled Nodes + // Map points from OrigNode To Unrolled Node. + std::map OrigNodeToUnrolledNode; + for (auto Node : LoopBody) { + // Node to unroll + AbstractState UnrolledNode(Nodes[Node]); + UnrolledNode.setUnrolled(1); + Nodes[NumberOfNodes++] = UnrolledNode; + OrigNodeToUnrolledNode[Node] = NumberOfNodes; + } + + unsigned int LoopHead = LoopBody.front(); + LoopBody.pop_front(); + 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 + Nodes[OrigNodeToUnrolledNode[Node]].Successors.push_back( + OrigNodeToUnrolledNode[Pre]); + } + } + } + return; + } + + /** + * @brief Idea fill the graph with the node and perform loop unrolling. + * + * @param NodeNr + */ void fillAbstractCache(unsigned int NodeNr) { + // if(isLoopHead(NodeNr)) + // unrollLoop(NodeNr); Nodes[NodeNr].Computed = true; for (unsigned int SuccNr : Nodes[NodeNr].Successors) { Nodes[SuccNr]; if (Nodes[SuccNr].Computed) { // Join don't call - Nodes[SuccNr].mustJoin(Nodes[NodeNr]); + // TODO fix Join + Nodes[SuccNr].mustJoin(Nodes[NodeNr]); // maybe fill Nodes[SuccNr].mustJoin(AbstractState(NodeNr)); } else { // Update and fill Succ @@ -107,13 +204,20 @@ public: // everything is public, because IDGAF } void dumpDotFile() { + bool PrintOld = true; std::ofstream DotFile; DotFile.open("out.dot"); DotFile << "digraph g {" << "\n"; for (auto const &E : Edges) { for (unsigned int To : E.second) { - DotFile << E.first << " -> " << To << "\n"; + if (PrintOld) { + DotFile << E.first << " -> " << To << "\n"; + } else { + DotFile << Nodes[E.first].Addr << "." << Nodes[E.first].Unrolled + << " -> " << Nodes[To].Addr << "." << Nodes[To].Unrolled + << "\n"; + } } } DotFile << "}\n"; diff --git a/include/AbstractState.h b/include/AbstractState.h index 3251353..1b4da84 100644 --- a/include/AbstractState.h +++ b/include/AbstractState.h @@ -27,6 +27,7 @@ public: // everything is public, because IDGAF std::list Predecessors; unsigned int Addr; + unsigned int Unrolled; bool Computed = false; @@ -57,6 +58,8 @@ public: // everything is public, because IDGAF std::map Sets; AbstractState(AbstractState const &Copy) { + Addr = Copy.Addr; + Unrolled = Copy.Unrolled; for (auto S : Copy.Sets) { unsigned int SetNr = S.first; for (auto E : S.second.Associativity) { @@ -70,12 +73,22 @@ public: // everything is public, because IDGAF AbstractState() {} - AbstractState(unsigned int AddressIn) { Addr = AddressIn; } - - AbstractState(Address Addr) { - Sets[Addr.Index].Associativity[0] = {{Addr.Tag}}; + AbstractState(unsigned int AddressIn) { + Addr = AddressIn; + Unrolled = 0; } + AbstractState(unsigned int AddressIn, unsigned int UnrolledIn) { + Addr = AddressIn; + Unrolled = UnrolledIn; + } + + // AbstractState(Address Addr) { + // Sets[Addr.Index].Associativity[0] = {{Addr.Tag}}; + // } + + void setUnrolled(unsigned int In) { Unrolled = In; } + /** * @brief Executes an Must LRU Join on the AbstractCacheState * @@ -111,9 +124,11 @@ public: // everything is public, because IDGAF * @param Addr , Address */ void update(Address Addr) { + // This loopages all entries by one. 3 <-2, 2<-1, 1<-0 for (int I = 3; I > 0; I--) { Sets[Addr.Index].Associativity[I] = Sets[Addr.Index].Associativity[I - 1]; } + // entry at age 0 is updated with current address. Sets[Addr.Index].Associativity[0].Blocks = {Addr.Tag}; } @@ -126,7 +141,7 @@ public: // everything is public, because IDGAF for (auto S : UpdateState.Sets) { unsigned int Index = S.first; for (auto E : S.second.Associativity) { - unsigned int Age = E.first + 1; + unsigned int Age = E.first; // If updated age is greater 4 The Tag is no longer in Cache. // Due to associativity of 4 per set. if (Age >= 4) @@ -139,17 +154,18 @@ public: // everything is public, because IDGAF } /** - * @brief Fills the AbstractState PreState and PreAddress. + * @brief Fills the AbstractState PreState and updates with PreAddress. * * @param PreState, State that fills this state. * * @param PreAddr Address of PreState */ void fill(AbstractState PreState, Address PreAddr) { + // copy Pre State into this. for (auto S : PreState.Sets) { unsigned int Index = S.first; for (auto E : S.second.Associativity) { - unsigned int Age = E.first + 1; + unsigned int Age = E.first; // If updated age is greater 4 The Tag is no longer in Cache. // Due to associativity of 4 per set. if (Age >= 4) @@ -159,11 +175,13 @@ public: // everything is public, because IDGAF } } } - Sets[PreAddr.Index].Associativity[0].Blocks.push_back(PreAddr.Tag); + // update this with PreAddr + this->update(PreAddr); } void dump() { llvm::outs() << Addr << " {\n"; + llvm::outs() << "Unrolled: " << Unrolled << "\n"; llvm::outs() << "Predecessors: "; for (auto PreNr : Predecessors) { llvm::outs() << PreNr << " ";