diff --git a/lib/ValueManipulationAnalysis/ContractedGraph.cpp b/lib/ValueManipulationAnalysis/ContractedGraph.cpp index 206ef2040..1e9cc98fc 100644 --- a/lib/ValueManipulationAnalysis/ContractedGraph.cpp +++ b/lib/ValueManipulationAnalysis/ContractedGraph.cpp @@ -125,7 +125,7 @@ void ContractedGraph::check() { } const auto IsCentralNode = [Col(this->Color)](const TypeFlowNode *TFGNode) { - return TFGNode->isUndecided() and TFGNode->Candidates.contains(Col); + return TFGNode->isUndecided() and TFGNode->getCandidates().contains(Col); }; // Check map @@ -158,7 +158,7 @@ void ContractedGraph::check() { } // Check that the right nodes belong to the special nodes if (not IsCentralNode(CurNode)) { - if (CurNode->Candidates.contains(Color)) + if (CurNode->getCandidates().contains(Color)) revng_assert(Contracted == NodesToColor); else revng_assert(Contracted == NodesToUncolor); @@ -180,7 +180,7 @@ void ContractedGraph::check() { // Check that the right nodes belong to the special nodes if (not IsCentralNode(TFGNode)) { - if (TFGNode->Candidates.contains(Color)) + if (TFGNode->getCandidates().contains(Color)) revng_assert(CN.get() == NodesToColor); else revng_assert(CN.get() == NodesToUncolor); @@ -205,7 +205,7 @@ static void addInitialNode(ContractedGraph &G, TypeFlowNode *TFGNode) { if (G.ReverseMap.find(TFGNode) != G.ReverseMap.end()) return; - bool HasWrongColor = not TFGNode->Candidates.contains(G.Color); + bool HasWrongColor = not TFGNode->getCandidates().contains(G.Color); if (HasWrongColor) { // Wrong color => uncolor @@ -231,7 +231,8 @@ void vma::makeContractedGraph(ContractedGraph &G, TypeFlowNode *Entry, const ColorSet CurColor) { // Check entrypoint properties - revng_assert(Entry->isDecided() and Entry->Candidates.contains(CurColor)); + revng_assert(Entry->isDecided() + and Entry->getCandidates().contains(CurColor)); // Create special nodes G.NodesToColor = G.addNode(Entry); @@ -240,7 +241,7 @@ void vma::makeContractedGraph(ContractedGraph &G, const auto IsBorderNode = [CurColor](const TypeFlowNode *TFNode) { return TFNode->isDecided() or TFNode->isUncolored() - or (not TFNode->Candidates.contains(CurColor)); + or (not TFNode->getCandidates().contains(CurColor)); }; // Visit the TypeFlowGraph depth-first. Stop when you find a decided node of diff --git a/lib/ValueManipulationAnalysis/Mincut.cpp b/lib/ValueManipulationAnalysis/Mincut.cpp index 4186ca25a..0842ec599 100644 --- a/lib/ValueManipulationAnalysis/Mincut.cpp +++ b/lib/ValueManipulationAnalysis/Mincut.cpp @@ -78,7 +78,7 @@ static unsigned calcCost(ContractedGraph &G) { unsigned AdditionalCost = 0; // If the node belongs to NodesToUncolor, remove G.Color from the candidates - ColorSet NodeColor = TFGNode->Candidates; + ColorSet NodeColor = TFGNode->getCandidates(); NodeColor.Bits.reset(G.Color.firstSetBit()); for (auto *Succ : TFGNode->successors()) { @@ -86,7 +86,7 @@ static unsigned calcCost(ContractedGraph &G) { continue; ColorSet CommonColors; - CommonColors.Bits = Succ->Candidates.Bits & NodeColor.Bits; + CommonColors.Bits = Succ->getCandidates().Bits & NodeColor.Bits; // If the node and its successor have no common candidates, pay a cost if (CommonColors.countValid() == 0) AdditionalCost++; @@ -165,7 +165,7 @@ static void generateColorAllSolution(ContractedGraph &G) { for (TypeFlowNode *TFGNode : CN->InitialNodes) { revng_assert(not TFGNode->isDecided() - or not TFGNode->Candidates.contains(G.Color)); + or not TFGNode->getCandidates().contains(G.Color)); G.NodesToColor->AdditionalNodes.insert(TFGNode); G.getMapEntry(TFGNode) = G.NodesToColor; } @@ -177,7 +177,7 @@ static void moveAllColoredToUncolored(ContractedGraph &G) { std::swap(G.NodesToUncolor->AdditionalNodes, G.NodesToColor->AdditionalNodes); for (TypeFlowNode *TFGNode : G.NodesToUncolor->AdditionalNodes) { revng_assert(not TFGNode->isDecided() - or not TFGNode->Candidates.contains(G.Color)); + or not TFGNode->getCandidates().contains(G.Color)); G.getMapEntry(TFGNode) = G.NodesToUncolor; } } @@ -227,11 +227,12 @@ void vma::minCut(TypeFlowGraph &TG) { auto HasUndecidedNeighbors = [CurColor](TypeFlowNode *TFGNodeode) { return llvm::any_of(TFGNodeode->successors(), [CurColor](TypeFlowNode *Succ) { + auto SuccCandidates = Succ->getCandidates(); return Succ->isUndecided() - and Succ->Candidates.contains(CurColor); + and SuccCandidates.contains(CurColor); }); }; - if (not(N->isDecided() and N->Candidates.contains(CurColor) + if (not(N->isDecided() and N->getCandidates().contains(CurColor) and HasUndecidedNeighbors(N))) continue; @@ -269,23 +270,30 @@ void vma::minCut(TypeFlowGraph &TG) { // Color all nodes that belong to NodesToColor for (TypeFlowNode *TFGNode : BestNodesToColor.InitialNodes) { - revng_assert(TFGNode->Candidates.contains(G.Color)); - TFGNode->Candidates = G.Color; + revng_assert(TFGNode->getCandidates().contains(G.Color)); + TFGNode->setCandidates(G.Color); } for (TypeFlowNode *TFGNode : BestNodesToColor.AdditionalNodes) { - revng_assert(TFGNode->Candidates.contains(G.Color)); - TFGNode->Candidates = G.Color; + revng_assert(TFGNode->getCandidates().contains(G.Color)); + TFGNode->setCandidates(G.Color); } // Uncolor all nodes that belong to NodesToColor for (TypeFlowNode *TFGNode : BestNodesToUncolor.InitialNodes) { + auto InitialColor = TFGNode->getCandidates(); + revng_assert(not TFGNode->isDecided() - or not TFGNode->Candidates.contains(G.Color)); - TFGNode->Candidates.Bits.reset(I); + or not InitialColor.contains(G.Color)); + + InitialColor.Bits.reset(I); + TFGNode->setCandidates(InitialColor); } for (TypeFlowNode *TFGNode : BestNodesToUncolor.AdditionalNodes) { + auto InitialColor = TFGNode->getCandidates(); + revng_assert(not TFGNode->isDecided() - or not TFGNode->Candidates.contains(G.Color)); - TFGNode->Candidates.Bits.reset(I); + or not InitialColor.contains(G.Color)); + InitialColor.Bits.reset(I); + TFGNode->setCandidates(InitialColor); } revng_log(MincutLog, "CurCost after applying mincut " << countCasts(TG)); @@ -293,9 +301,14 @@ void vma::minCut(TypeFlowGraph &TG) { // Remove CurColor from the candidates of any remaining grey node before // going to another color - for (TypeFlowNode *N : TG.nodes()) - if (N->isUndecided() and N->Candidates.contains(CurColor)) - N->Candidates.Bits.reset(I); + for (TypeFlowNode *N : TG.nodes()) { + auto InitialColor = N->getCandidates(); + + if (N->isUndecided() and InitialColor.contains(CurColor)) { + InitialColor.Bits.reset(I); + N->setCandidates(InitialColor); + } + } revng_log(MincutLog, "CurCost after resetting color " << countCasts(TG)); diff --git a/lib/ValueManipulationAnalysis/TypeFlowGraph.cpp b/lib/ValueManipulationAnalysis/TypeFlowGraph.cpp index 0bdd953a5..5d931944c 100644 --- a/lib/ValueManipulationAnalysis/TypeFlowGraph.cpp +++ b/lib/ValueManipulationAnalysis/TypeFlowGraph.cpp @@ -127,8 +127,8 @@ static bool connect(TypeFlowNode *N1, TypeFlowNode *N2) { if (UseNode->getUse()->get() == ValNode->getValue()) { bool Connected = false; - Connected |= addSuccessorIfAbsent(ValNode, UseNode, UseNode->Accepted); - Connected |= addSuccessorIfAbsent(UseNode, ValNode, ValNode->Accepted); + Connected |= addSuccessorIfAbsent(ValNode, UseNode, UseNode->getAccepted()); + Connected |= addSuccessorIfAbsent(UseNode, ValNode, ValNode->getAccepted()); return Connected; } @@ -316,7 +316,7 @@ void vma::propagateColor(TypeFlowGraph &TG) { for (auto *Node : TG.nodes()) { bool AlreadyVisited = (Visited.find(Node) != Visited.end()); // Start from nodes that have only the desired color - if (AlreadyVisited or not Node->Candidates.contains(ColorSet(Filter))) + if (AlreadyVisited or not Node->getCandidates().contains(ColorSet(Filter))) continue; // Explore only the edges that have the desired color @@ -325,8 +325,11 @@ void vma::propagateColor(TypeFlowGraph &TG) { // If a node is reachable from a source with a certain color through edges // that all have that color, by construction it should also accept that // color - revng_assert(Reachable->Accepted.contains(Filter)); - Reachable->Candidates.addColor(Filter); + revng_assert(Reachable->getAccepted().contains(Filter)); + + auto InitialColor = Reachable->getCandidates(); + InitialColor.addColor(Filter); + Reachable->setCandidates(InitialColor); } } } @@ -337,8 +340,11 @@ bool vma::propagateNumberness(TypeFlowGraph &TG) { // TODO: forward propagate numberness for known patterns (e.g. n+n = n ) // For now, just reset all numberness flags - for (auto *N : TG.nodes()) - N->Candidates.Bits.reset(NUMBERNESS_INDEX); + for (auto *N : TG.nodes()) { + auto InitialColor = N->getCandidates(); + InitialColor.Bits.reset(NUMBERNESS_INDEX); + N->setCandidates(InitialColor); + } return false; } @@ -375,7 +381,7 @@ unsigned vma::countCasts(const TypeFlowGraph &TG) { unsigned Cost = 0; for (const TypeFlowNode *TGNode : TG.nodes()) { - const auto &NodeBits = TGNode->Candidates.Bits; + auto NodeBits = TGNode->getCandidates().Bits; // Ignore nodes with no candidates if (NodeBits.count() == 0 or NodeBits == NUMBERNESS) continue; @@ -385,7 +391,7 @@ unsigned vma::countCasts(const TypeFlowGraph &TG) { if (Visited.count(Succ)) continue; - const auto &SuccBits = Succ->Candidates.Bits; + auto SuccBits = Succ->getCandidates().Bits; // If they have no common candidates it means there's a cast if ((SuccBits & NodeBits) == 0) @@ -431,9 +437,9 @@ static llvm::Optional majorityVote(const TypeFlowNode *Node) { // For each color, count the number of decided neighbors with that color int NUndecided = 0; for (const TypeFlowNode *Succ : Node->successors()) { - const ColorSet SuccColor = Succ->Candidates; + const ColorSet SuccColor = Succ->getCandidates(); - if (Succ->isDecided() and Node->Candidates.contains(SuccColor)) { + if (Succ->isDecided() and Node->getCandidates().contains(SuccColor)) { // Since the node is decided, its color has exactly one set bit ColorIndex I = SuccColor.firstSetBit(); // The index of the set bit corresponds to the color @@ -456,7 +462,7 @@ static llvm::Optional majorityVote(const TypeFlowNode *Node) { // common even if all the undecided nodes are colored with the second most // common color, then we have a winner. if (Max.Frequency > (SecondMax.Frequency + NUndecided)) { - revng_assert(Node->Candidates.contains(Max.Color)); + revng_assert(Node->getCandidates().contains(Max.Color)); return Max.Color; } @@ -473,7 +479,7 @@ bool vma::applyMajorityVoting(TypeFlowGraph &TG) { if (N->isUndecided()) { // Check if the neighbors of a node agree on a certain color if (auto VotedColor = majorityVote(N)) { - N->Candidates = *VotedColor; + N->setCandidates(*VotedColor); Modified = true; } } diff --git a/lib/ValueManipulationAnalysis/TypeFlowGraphWriter.h b/lib/ValueManipulationAnalysis/TypeFlowGraphWriter.h index 26473eb2d..a5d7e489f 100644 --- a/lib/ValueManipulationAnalysis/TypeFlowGraphWriter.h +++ b/lib/ValueManipulationAnalysis/TypeFlowGraphWriter.h @@ -83,8 +83,10 @@ struct DOTGraphTraits : public DefaultDOTGraphTraits { } // Node colors - Out << "color : " << dumpToString(Node->Candidates) - << "}\n{accepted: " << dumpToString(Node->Accepted); + Out << "color : "; + Node->getCandidates().print(Out); + Out << "}\n{accepted: "; + Node->getAccepted().print(Out); return Out.str(); } @@ -111,7 +113,7 @@ struct DOTGraphTraits : public DefaultDOTGraphTraits { if (Node->isUndecided()) { Out << " style=filled, fillcolor=lightgrey, color=lightgrey"; } else if (Node->isDecided()) { - auto First = Node->Candidates.firstSetBit(); + auto First = Node->getCandidates().firstSetBit(); revng_assert(First != vma::NUMBERNESS_INDEX); Out << " style=filled, fillcolor=" << ColorCode[First].str() diff --git a/lib/ValueManipulationAnalysis/TypeFlowNode.h b/lib/ValueManipulationAnalysis/TypeFlowNode.h index 6f5d094da..8120af8d3 100644 --- a/lib/ValueManipulationAnalysis/TypeFlowNode.h +++ b/lib/ValueManipulationAnalysis/TypeFlowNode.h @@ -82,7 +82,7 @@ struct EdgeLabel { /// Node data containing colors for an `llvm::Use` or `llvm::Value` class TypeFlowNodeData { -public: +private: /// LLVM Use or Value to which the type information is attached const UseOrValue Content; /// Candidate types for this node @@ -103,6 +103,7 @@ public: TypeFlowNodeData &operator=(TypeFlowNodeData &&N) = delete; public: + UseOrValue getContent() const { return Content; } bool isUse() const { return vma::isUse(Content); } bool isValue() const { return vma::isValue(Content); } const llvm::Use *getUse() const { return vma::getUse(Content); } @@ -115,6 +116,15 @@ public: /// Has more than one candidate color bool isUndecided() const { return Candidates.countValid() > 1; } + ColorSet getCandidates() const { return Candidates; } + void setCandidates(ColorSet Color) { + revng_assert(Accepted.contains(Color)); + Candidates = Color; + } + + ColorSet getAccepted() const { return Accepted; } + +public: /// Print a textual representation of the node's content void print(llvm::raw_ostream &Out) const debug_function; diff --git a/lib/ValueManipulationAnalysis/ValueManipulationAnalysis.cpp b/lib/ValueManipulationAnalysis/ValueManipulationAnalysis.cpp index 2c143242c..0131f0feb 100644 --- a/lib/ValueManipulationAnalysis/ValueManipulationAnalysis.cpp +++ b/lib/ValueManipulationAnalysis/ValueManipulationAnalysis.cpp @@ -90,10 +90,10 @@ bool VMA::runOnFunction(Function &F) { // Populate Output Map for (const auto *N : TG.nodes()) { - revng_assert(N->Candidates.countValid() <= 1); + revng_assert(N->getCandidates().countValid() <= 1); if (N->isValue()) - ColorMap.insert({ N->getValue(), N->Candidates }); + ColorMap.insert({ N->getValue(), N->getCandidates() }); } return false; diff --git a/tests/unit/ValueManipulationAnalysis.cpp b/tests/unit/ValueManipulationAnalysis.cpp index 5f9e1a2d7..f3cd22019 100644 --- a/tests/unit/ValueManipulationAnalysis.cpp +++ b/tests/unit/ValueManipulationAnalysis.cpp @@ -56,7 +56,7 @@ static ColorCounter countColors(const TypeFlowGraph &TG) { for (const TypeFlowNode *const N : nodes(&TG)) for (size_t I = 0; I < MAX_COLORS; I++) - CC[I] += N->Candidates.Bits.test(I); + CC[I] += N->getCandidates().Bits.test(I); return CC; } @@ -116,7 +116,7 @@ static void checkShape(const TypeFlowGraph &TG, const ExpectedShape &Expected) { static void checkTGCorrectness(TypeFlowGraph &TG) { // Check consistency between the graph and the reverse map for (TypeFlowNode *N : TG.nodes()) { - auto MapIter = TG.ContentToNodeMap.find(N->Content); + auto MapIter = TG.ContentToNodeMap.find(N->getContent()); revng_check(MapIter != TG.ContentToNodeMap.end()); revng_check(MapIter->second == N); } @@ -126,12 +126,12 @@ static void checkTGCorrectness(TypeFlowGraph &TG) { auto NodeIter = llvm::find(TG.nodes(), Elem.second); revng_check(NodeIter != TG.nodes().end()); - revng_check((*NodeIter)->Content == Elem.first); + revng_check((*NodeIter)->getContent() == Elem.first); } for (const TypeFlowNode *N : TG.nodes()) { // Candidates should be a subset of accepted colors - revng_check(N->Accepted.contains(N->Candidates)); + revng_check(N->getAccepted().contains(N->getCandidates())); // Nodes can contain either uses or values revng_check(N->isUse() xor N->isValue()); @@ -162,6 +162,7 @@ static void checkInit(const char *Body, // Build the TG TypeFlowGraph TG = makeTypeFlowGraphFromFunction(F); + checkTGCorrectness(TG); checkShape(TG, ExpectedInit); @@ -173,7 +174,7 @@ static void checkInit(const char *Body, // Numberness propagateNumberness(TG); for (auto *N : TG.nodes()) - revng_check(not N->Candidates.Bits.test(NUMBERNESS_INDEX)); + revng_check(not N->getCandidates().Bits.test(NUMBERNESS_INDEX)); // Undirected graph makeBidirectional(TG); @@ -710,8 +711,8 @@ BOOST_AUTO_TEST_CASE(TestMajorityVoting) { makeBidirectional(G); applyMajorityVoting(G); - revng_check(Undecided1->Candidates == (POINTERNESS | UNSIGNEDNESS)); - revng_check(Undecided2->Candidates == (POINTERNESS | UNSIGNEDNESS)); + revng_check(Undecided1->getCandidates() == (POINTERNESS | UNSIGNEDNESS)); + revng_check(Undecided2->getCandidates() == (POINTERNESS | UNSIGNEDNESS)); TypeFlowNode *Decided5 = AddNode(G, POINTERNESS); Undecided1->addSuccessor(Decided5); @@ -719,6 +720,6 @@ BOOST_AUTO_TEST_CASE(TestMajorityVoting) { makeBidirectional(G); applyMajorityVoting(G); - revng_check(Undecided1->Candidates == POINTERNESS); - revng_check(Undecided2->Candidates == POINTERNESS); + revng_check(Undecided1->getCandidates() == POINTERNESS); + revng_check(Undecided2->getCandidates() == POINTERNESS); }