mirror of
https://github.com/revng/revng
synced 2026-06-21 14:07:57 +00:00
a8da5e14ec
DeduplicateUnionFields does not depend on CollapseSingleChild, but can break if CollapseSingleChild has not run. However, we don't want to introduce an explicit dependency between the two steps, because CollapseSingleChild could soon become obsolete on its own, superseeded by a more powerful and costly step. This commit changes DeduplicateUnionFields with an additional pre-processing that runs CollapseSingleChild on each node at step one, to ensure the step does not fail if CollapseSingleChild child is not executed.
944 lines
32 KiB
C++
944 lines
32 KiB
C++
//
|
|
// Copyright rev.ng Srls. See LICENSE.md for details.
|
|
//
|
|
|
|
#define BOOST_TEST_MODULE DLASteps
|
|
bool init_unit_test();
|
|
|
|
#include "boost/test/unit_test.hpp"
|
|
|
|
#include "revng-c/DataLayoutAnalysis/DLATypeSystem.h"
|
|
#include "revng-c/Support/FunctionFileHelpers.h"
|
|
|
|
#include "lib/DataLayoutAnalysis/Middleend/DLAStep.h"
|
|
|
|
using LTSN = dla::LayoutTypeSystemNode;
|
|
|
|
using namespace llvm;
|
|
using namespace dla;
|
|
|
|
template<typename StepT>
|
|
static void runStep(LayoutTypeSystem &TS) {
|
|
// Enable expensive checks
|
|
VerifyLog.enable();
|
|
|
|
// Run Step
|
|
dla::StepManager SM;
|
|
revng_check(SM.addStep<StepT>());
|
|
SM.run(TS);
|
|
|
|
// Compress the equivalence classes
|
|
dla::VectEqClasses &Eq = TS.getEqClasses();
|
|
Eq.compress();
|
|
}
|
|
|
|
static LTSN *createRoot(LayoutTypeSystem &TS, unsigned Size = 0U) {
|
|
LTSN *Root = TS.createArtificialLayoutType();
|
|
Root->Size = Size;
|
|
|
|
return Root;
|
|
}
|
|
|
|
static LTSN *addInstanceAtOffset(LayoutTypeSystem &TS,
|
|
LTSN *Parent,
|
|
unsigned ChildOffset,
|
|
unsigned ChildSize) {
|
|
LTSN *Child = TS.createArtificialLayoutType();
|
|
Child->Size = ChildSize;
|
|
OffsetExpression OE{};
|
|
OE.Offset = ChildOffset;
|
|
TS.addInstanceLink(Parent, Child, std::move(OE));
|
|
|
|
return Child;
|
|
}
|
|
|
|
static LTSN *
|
|
addInheritance(LayoutTypeSystem &TS, LTSN *Parent, unsigned ChildSize = 0U) {
|
|
LTSN *Child = TS.createArtificialLayoutType();
|
|
Child->Size = ChildSize;
|
|
TS.addInheritanceLink(Parent, Child);
|
|
|
|
return Child;
|
|
}
|
|
|
|
static LTSN *
|
|
addEquality(LayoutTypeSystem &TS, LTSN *Parent, unsigned ChildSize = 0U) {
|
|
LTSN *Child = TS.createArtificialLayoutType();
|
|
Child->Size = ChildSize;
|
|
TS.addEqualityLink(Parent, Child);
|
|
|
|
return Child;
|
|
}
|
|
|
|
void checkNode(const LayoutTypeSystem &TS,
|
|
const LayoutTypeSystemNode *N,
|
|
const unsigned ExpectedSize,
|
|
const InterferingChildrenInfo ExpectedInfo,
|
|
const std::set<unsigned> &ExpectedEqClass) {
|
|
const dla::VectEqClasses &Eq = TS.getEqClasses();
|
|
revng_check(N);
|
|
revng_check(not Eq.isRemoved(N->ID));
|
|
revng_check(ExpectedSize == N->Size);
|
|
revng_check(ExpectedInfo == N->InterferingInfo);
|
|
|
|
const auto &EqClass = Eq.computeEqClass(N->ID);
|
|
revng_check(EqClass.size() == ExpectedEqClass.size());
|
|
for (auto &Collapsed : EqClass)
|
|
revng_check(ExpectedEqClass.contains(Collapsed));
|
|
}
|
|
|
|
// Test cases
|
|
|
|
// ----------------- CollapseIdentityAndInheritanceCC ---
|
|
|
|
///\brief Test an equality CC with a pointer edge
|
|
BOOST_AUTO_TEST_CASE(CollapseIdentityAndInheritanceCC_equality) {
|
|
dla::LayoutTypeSystem TS;
|
|
|
|
// Build TS
|
|
LTSN *Root = createRoot(TS);
|
|
LTSN *Node1 = addEquality(TS, Root);
|
|
LTSN *Node2 = addEquality(TS, Root);
|
|
LTSN *Node3 = addEquality(TS, Node2);
|
|
TS.addEqualityLink(Node1, Node3);
|
|
LTSN *PtrNode = createRoot(TS);
|
|
TS.addPointerLink(Node3, PtrNode);
|
|
|
|
runStep<dla::CollapseIdentityAndInheritanceCC>(TS);
|
|
|
|
// Check that equality nodes have been collapsed
|
|
revng_check(TS.getNumLayouts() == 2);
|
|
revng_check(llvm::is_contained(TS.getLayoutsRange(), Node2));
|
|
revng_check(llvm::is_contained(TS.getLayoutsRange(), PtrNode));
|
|
revng_check(Node2->Successors.size() == 1);
|
|
// Check that the pointer edge is still alive
|
|
const auto &[Child, Tag] = *(llvm::children_edges<LTSN *>(Node2).begin());
|
|
revng_check(Child == PtrNode);
|
|
revng_check(Tag->getKind() == dla::TypeLinkTag::LK_Pointer);
|
|
|
|
// Check Eq Classes
|
|
dla::VectEqClasses &Eq = TS.getEqClasses();
|
|
revng_check(Eq.getNumElements() == 5);
|
|
revng_check(Eq.getNumClasses() == 2);
|
|
checkNode(TS, Node2, 0, InterferingChildrenInfo::Unknown, { 0, 1, 2, 3 });
|
|
checkNode(TS, PtrNode, 0, InterferingChildrenInfo::Unknown, { 4 });
|
|
}
|
|
|
|
///\brief Test an inheritance loop with a pointer edge
|
|
BOOST_AUTO_TEST_CASE(CollapseIdentityAndInheritanceCC_inheritance) {
|
|
dla::LayoutTypeSystem TS;
|
|
|
|
// Build TS
|
|
LTSN *Root = createRoot(TS);
|
|
LTSN *Node1 = addInheritance(TS, Root);
|
|
LTSN *Node2 = addInheritance(TS, Root);
|
|
LTSN *Node3 = addInheritance(TS, Node2);
|
|
TS.addInheritanceLink(Node3, Root);
|
|
LTSN *Node4 = addInheritance(TS, Node1);
|
|
|
|
LTSN *PtrNode = createRoot(TS);
|
|
TS.addPointerLink(Node4, PtrNode);
|
|
|
|
runStep<dla::CollapseIdentityAndInheritanceCC>(TS);
|
|
// Check that inheritance loops have been collapsed
|
|
revng_check(TS.getNumLayouts() == 4);
|
|
revng_check(llvm::is_contained(TS.getLayoutsRange(), Node3));
|
|
revng_check(llvm::is_contained(TS.getLayoutsRange(), Node1));
|
|
revng_check(llvm::is_contained(TS.getLayoutsRange(), Node4));
|
|
revng_check(llvm::is_contained(TS.getLayoutsRange(), PtrNode));
|
|
revng_check(Node3->Successors.size() == 1);
|
|
// Check that the pointer edge is still alive
|
|
const auto &[Child, Tag] = *(llvm::children_edges<LTSN *>(Node4).begin());
|
|
revng_check(Child == PtrNode);
|
|
revng_check(Tag->getKind() == dla::TypeLinkTag::LK_Pointer);
|
|
|
|
// Check Eq Classes
|
|
dla::VectEqClasses &Eq = TS.getEqClasses();
|
|
revng_check(Eq.getNumElements() == 6);
|
|
revng_check(Eq.getNumClasses() == 4);
|
|
checkNode(TS, Node3, 0, InterferingChildrenInfo::Unknown, { 0, 2, 3 });
|
|
checkNode(TS, Node1, 0, InterferingChildrenInfo::Unknown, { 1 });
|
|
checkNode(TS, Node4, 0, InterferingChildrenInfo::Unknown, { 4 });
|
|
checkNode(TS, PtrNode, 0, InterferingChildrenInfo::Unknown, { 5 });
|
|
}
|
|
|
|
///\brief Test an inheritance CC with a backward instance edge (loop)
|
|
BOOST_AUTO_TEST_CASE(CollapseIdentityAndInheritanceCC_instance) {
|
|
dla::LayoutTypeSystem TS;
|
|
|
|
// Build TS
|
|
LTSN *Root = createRoot(TS);
|
|
LTSN *Node1 = addInheritance(TS, Root);
|
|
LTSN *Node2 = addInheritance(TS, Root);
|
|
LTSN *Node3 = addInheritance(TS, Node2);
|
|
TS.addInstanceLink(Node3, Root, OffsetExpression{});
|
|
LTSN *Node4 = addInstanceAtOffset(TS, Node1, 0, 8);
|
|
|
|
LTSN *PtrNode = createRoot(TS);
|
|
TS.addPointerLink(Node4, PtrNode);
|
|
|
|
// Run step
|
|
runStep<dla::CollapseIdentityAndInheritanceCC>(TS);
|
|
|
|
// Check that no node has been collapsed
|
|
revng_check(TS.getNumLayouts() == 6);
|
|
|
|
// Check that the pointer edge is still alive
|
|
const auto &[Child, Tag] = *(llvm::children_edges<LTSN *>(Node4).begin());
|
|
revng_check(Child == PtrNode);
|
|
revng_check(Tag->getKind() == dla::TypeLinkTag::LK_Pointer);
|
|
|
|
// Check that the instance back-edge has been removed
|
|
revng_check(Node3->Successors.size() == 0);
|
|
|
|
// Check Eq Classes
|
|
dla::VectEqClasses &Eq = TS.getEqClasses();
|
|
revng_check(Eq.getNumElements() == 6);
|
|
revng_check(Eq.getNumClasses() == 6);
|
|
}
|
|
|
|
// ----------------- RemoveTransitiveInheritanceEdges ---
|
|
|
|
///\brief Test that transitive edges are removed and pointer edges ignored
|
|
BOOST_AUTO_TEST_CASE(RemoveTransitiveInheritanceEdges_basic) {
|
|
dla::LayoutTypeSystem TS;
|
|
|
|
// Build TS
|
|
LTSN *Root = createRoot(TS);
|
|
LTSN *Node1 = addInheritance(TS, Root);
|
|
LTSN *Node2 = addInheritance(TS, Node1);
|
|
LTSN *Node3 = addInheritance(TS, Node2);
|
|
// Add transitive edges
|
|
TS.addInheritanceLink(Root, Node2);
|
|
TS.addInheritanceLink(Root, Node3);
|
|
// Add pointer edge
|
|
LTSN *PtrNode = createRoot(TS);
|
|
TS.addPointerLink(Node3, PtrNode);
|
|
TS.addInheritanceLink(Root, PtrNode);
|
|
|
|
// Run step
|
|
runStep<dla::RemoveTransitiveInheritanceEdges>(TS);
|
|
|
|
// Check that no node has been collapsed
|
|
revng_check(TS.getNumLayouts() == 5);
|
|
// Check that the pointer edges are still alive
|
|
const auto &[Child, Tag] = *(llvm::children_edges<LTSN *>(Node3).begin());
|
|
revng_check(Child == PtrNode);
|
|
revng_check(Tag->getKind() == dla::TypeLinkTag::LK_Pointer);
|
|
// Check that transitive edges have been removed
|
|
revng_check(Root->Successors.size() == 2);
|
|
revng_check(llvm::is_contained(llvm::children<LTSN *>(Root), Node1));
|
|
// The edge to the pointer node should not be removed
|
|
revng_check(llvm::is_contained(llvm::children<LTSN *>(Root), PtrNode));
|
|
|
|
// Check Eq Classes
|
|
dla::VectEqClasses &Eq = TS.getEqClasses();
|
|
revng_check(Eq.getNumElements() == 5);
|
|
revng_check(Eq.getNumClasses() == 5);
|
|
revng_check(not Eq.isRemoved(Node3->ID) and not Eq.isRemoved(PtrNode->ID));
|
|
}
|
|
|
|
// ----------------- MakeInheritanceTree ----------------
|
|
|
|
///\brief Test that inheritance "diamonds" are removed and pointer edges ignored
|
|
BOOST_AUTO_TEST_CASE(MakeInheritanceTree_diamond) {
|
|
dla::LayoutTypeSystem TS;
|
|
|
|
// Build TS
|
|
LTSN *Root = createRoot(TS);
|
|
LTSN *Node1 = addInheritance(TS, Root);
|
|
LTSN *Node2 = addInheritance(TS, Root);
|
|
LTSN *Node3 = addInheritance(TS, Node1);
|
|
TS.addInheritanceLink(Node2, Node3);
|
|
// Add pointer edge
|
|
LTSN *PtrNode = createRoot(TS);
|
|
TS.addPointerLink(Node3, PtrNode);
|
|
|
|
runStep<dla::MakeInheritanceTree>(TS);
|
|
// Check that nodes have been collapsed
|
|
revng_check(TS.getNumLayouts() == 4);
|
|
// Check that the pointer edges are still alive
|
|
const auto &[Child, Tag] = *(llvm::children_edges<LTSN *>(Node3).begin());
|
|
revng_check(Child == PtrNode);
|
|
revng_check(Tag->getKind() == dla::TypeLinkTag::LK_Pointer);
|
|
// Check diamonds have been collapsed
|
|
revng_check(Root->Successors.size() == 1);
|
|
revng_check(llvm::is_contained(llvm::children<LTSN *>(Root), Node1));
|
|
revng_check(not llvm::is_contained(llvm::children<LTSN *>(Root), Node2));
|
|
// Check Eq Classes
|
|
dla::VectEqClasses &Eq = TS.getEqClasses();
|
|
revng_check(Eq.getNumElements() == 5);
|
|
revng_check(Eq.getNumClasses() == 4);
|
|
checkNode(TS, Root, 0, InterferingChildrenInfo::Unknown, { 0 });
|
|
checkNode(TS, Node1, 0, InterferingChildrenInfo::Unknown, { 1, 2 });
|
|
checkNode(TS, Node3, 0, InterferingChildrenInfo::Unknown, { 3 });
|
|
checkNode(TS, PtrNode, 0, InterferingChildrenInfo::Unknown, { 4 });
|
|
}
|
|
|
|
///\brief Test that multiple inheritance is collapsed
|
|
BOOST_AUTO_TEST_CASE(MakeInheritanceTree_virtualPostDom) {
|
|
dla::LayoutTypeSystem TS;
|
|
|
|
// Build TS
|
|
LTSN *Root = createRoot(TS);
|
|
LTSN *Node1 = addInheritance(TS, Root);
|
|
LTSN *Node2 = addInheritance(TS, Root);
|
|
LTSN *Node3 = addInheritance(TS, Node1);
|
|
TS.addInheritanceLink(Node2, Node3);
|
|
/*LTSN *Node4=*/addInheritance(TS, Root);
|
|
// Add pointer edge
|
|
LTSN *PtrNode = createRoot(TS);
|
|
TS.addPointerLink(Node3, PtrNode);
|
|
|
|
// Run step
|
|
runStep<dla::MakeInheritanceTree>(TS);
|
|
|
|
// Check that nodes have been collapsed
|
|
revng_check(TS.getNumLayouts() == 3);
|
|
// Check that the pointer edges are still alive
|
|
const auto &[Child, Tag] = *(llvm::children_edges<LTSN *>(Node3).begin());
|
|
revng_check(Child == PtrNode);
|
|
revng_check(Tag->getKind() == dla::TypeLinkTag::LK_Pointer);
|
|
// Check that all inheritance children have been collapsed
|
|
revng_check(Root->Successors.size() == 1);
|
|
revng_check(llvm::is_contained(llvm::children<LTSN *>(Root), Node3));
|
|
// Check Eq Classes
|
|
dla::VectEqClasses &Eq = TS.getEqClasses();
|
|
revng_check(Eq.getNumElements() == 6);
|
|
revng_check(Eq.getNumClasses() == 3);
|
|
checkNode(TS, Root, 0, InterferingChildrenInfo::Unknown, { 0 });
|
|
checkNode(TS, Node3, 0, InterferingChildrenInfo::Unknown, { 1, 2, 3, 4 });
|
|
checkNode(TS, PtrNode, 0, InterferingChildrenInfo::Unknown, { 5 });
|
|
}
|
|
|
|
// ----------------- PruneLayoutNodesWithoutLayout ------
|
|
|
|
///\brief Test that branches without sized leaves are pruned
|
|
BOOST_AUTO_TEST_CASE(PruneLayoutNodesWithoutLayout_basic) {
|
|
dla::LayoutTypeSystem TS;
|
|
|
|
// Build TS
|
|
LTSN *Root = createRoot(TS);
|
|
std::vector<LTSN *> Level0 = {
|
|
addInstanceAtOffset(TS, Root, /*offset=*/0, /*size=*/0),
|
|
addInstanceAtOffset(TS, Root, /*offset=*/0, /*size=*/0)
|
|
};
|
|
std::vector<LTSN *> Level1 = {
|
|
addInstanceAtOffset(TS, Level0[0], /*offset=*/0, /*size=*/0),
|
|
addInstanceAtOffset(TS, Level0[0], /*offset=*/0, /*size=*/0),
|
|
addInstanceAtOffset(TS, Level0[1], /*offset=*/0, /*size=*/0),
|
|
addInstanceAtOffset(TS, Level0[1], /*offset=*/0, /*size=*/0)
|
|
};
|
|
std::vector<LTSN *> Leaves = {
|
|
addInstanceAtOffset(TS, Level1[0], /*offset=*/0, /*size=*/8),
|
|
addInstanceAtOffset(TS, Level1[1], /*offset=*/0, /*size=*/8),
|
|
addInstanceAtOffset(TS, Level1[2], /*offset=*/0, /*size=*/0),
|
|
addInstanceAtOffset(TS, Level1[3], /*offset=*/0, /*size=*/0)
|
|
};
|
|
// Add pointers
|
|
std::vector<LTSN *> PtrNodes;
|
|
for (LTSN *Leaf : Leaves) {
|
|
LTSN *PtrNode = createRoot(TS);
|
|
// PtrNode->Size = 8U;
|
|
TS.addPointerLink(Leaf, PtrNode);
|
|
PtrNodes.push_back(PtrNode);
|
|
}
|
|
|
|
// Run step
|
|
runStep<dla::PruneLayoutNodesWithoutLayout>(TS);
|
|
|
|
// Check final tree
|
|
revng_check(TS.getNumLayouts() == 6);
|
|
revng_check(Root->Successors.size() == 1);
|
|
revng_check(llvm::is_contained(llvm::children<LTSN *>(Root), Level0[0]));
|
|
revng_check(not llvm::is_contained(llvm::children<LTSN *>(Root), Level0[1]));
|
|
|
|
revng_check(Level0[0]->Successors.size() == 2);
|
|
revng_check(llvm::is_contained(llvm::children<LTSN *>(Level0[0]), Level1[0]));
|
|
revng_check(llvm::is_contained(llvm::children<LTSN *>(Level0[0]), Level1[1]));
|
|
|
|
revng_check(Level1[0]->Successors.size() == 1);
|
|
revng_check(llvm::is_contained(llvm::children<LTSN *>(Level1[0]), Leaves[0]));
|
|
revng_check(Level1[1]->Successors.size() == 1);
|
|
revng_check(llvm::is_contained(llvm::children<LTSN *>(Level1[1]), Leaves[1]));
|
|
|
|
revng_check(isLeaf(Leaves[0]) and isLeaf(Leaves[1]));
|
|
|
|
// Check Eq Classes
|
|
dla::VectEqClasses &Eq = TS.getEqClasses();
|
|
revng_check(Eq.getNumElements() == 15);
|
|
revng_check(Eq.getNumClasses() == 7);
|
|
|
|
// All leaves should have been removed
|
|
std::vector<unsigned> RemovedIDs = { 2, 5, 6, 9, 10, 11, 12, 13, 14 };
|
|
for (auto ID : RemovedIDs)
|
|
revng_check(Eq.isRemoved(ID));
|
|
}
|
|
|
|
// ----------------- CollapseSingleChild ----------------
|
|
|
|
///\brief Test nominal case with one parent and one instance child at offset 0
|
|
BOOST_AUTO_TEST_CASE(CollapseSingleChild_offsetZero) {
|
|
dla::LayoutTypeSystem TS;
|
|
|
|
// Build TS
|
|
LTSN *Parent = createRoot(TS, 0U);
|
|
/*LTSN *Child =*/addInstanceAtOffset(TS,
|
|
Parent,
|
|
/*offset=*/0U,
|
|
/*size=*/8U);
|
|
|
|
// Run step
|
|
runStep<dla::CollapseSingleChild>(TS);
|
|
|
|
// Check graph
|
|
revng_check(TS.getNumLayouts() == 1);
|
|
checkNode(TS, Parent, 8, InterferingChildrenInfo::Unknown, { 0, 1 });
|
|
}
|
|
|
|
///\brief Test the case where there is only one child but with offset > 0
|
|
BOOST_AUTO_TEST_CASE(CollapseSingleChild_offsetNonZero) {
|
|
dla::LayoutTypeSystem TS;
|
|
|
|
// Build TS
|
|
LTSN *Parent = createRoot(TS, 0U);
|
|
LTSN *Child = addInstanceAtOffset(TS,
|
|
Parent,
|
|
/*offset=*/8U,
|
|
/*size=*/8U);
|
|
|
|
// Run step
|
|
runStep<dla::CollapseSingleChild>(TS);
|
|
|
|
// Check graph
|
|
revng_check(TS.getNumLayouts() == 2);
|
|
checkNode(TS, Parent, 0, InterferingChildrenInfo::Unknown, { 0 });
|
|
checkNode(TS, Child, 8, InterferingChildrenInfo::Unknown, { 1 });
|
|
}
|
|
|
|
///\brief Test the case in which a node has many children (should not collapse)
|
|
BOOST_AUTO_TEST_CASE(CollapseSingleChild_multiChild) {
|
|
dla::LayoutTypeSystem TS;
|
|
|
|
// Build TS
|
|
LTSN *Parent = createRoot(TS, 0U);
|
|
LTSN *Child1 = addInstanceAtOffset(TS,
|
|
Parent,
|
|
/*offset=*/0U,
|
|
/*size=*/0U);
|
|
addInstanceAtOffset(TS,
|
|
Child1,
|
|
/*offset=*/0U,
|
|
/*size=*/8U);
|
|
LTSN *Child2 = addInstanceAtOffset(TS,
|
|
Parent,
|
|
/*offset=*/8U,
|
|
/*size=*/0U);
|
|
addInstanceAtOffset(TS,
|
|
Child2,
|
|
/*offset=*/0U,
|
|
/*size=*/8U);
|
|
|
|
// Run step
|
|
runStep<dla::CollapseSingleChild>(TS);
|
|
|
|
// Check graph
|
|
revng_check(TS.getNumLayouts() == 3);
|
|
checkNode(TS, Parent, 0, InterferingChildrenInfo::Unknown, { 0 });
|
|
checkNode(TS, Child1, 8, InterferingChildrenInfo::Unknown, { 1, 2 });
|
|
checkNode(TS, Child2, 8, InterferingChildrenInfo::Unknown, { 3, 4 });
|
|
}
|
|
|
|
///\brief Test the case in which a node has many parents (should not collapse)
|
|
BOOST_AUTO_TEST_CASE(CollapseSingleChild_multiParent) {
|
|
dla::LayoutTypeSystem TS;
|
|
|
|
// Build TS
|
|
LTSN *Parent1 = createRoot(TS, 0U);
|
|
LTSN *Parent2 = createRoot(TS, 0U);
|
|
LTSN *Child1 = addInstanceAtOffset(TS,
|
|
Parent1,
|
|
/*offset=*/8U,
|
|
/*size=*/0U);
|
|
TS.addInheritanceLink(Parent2, Child1);
|
|
/*LTSN *Child2 =*/addInstanceAtOffset(TS,
|
|
Child1,
|
|
/*offset=*/0U,
|
|
/*size=*/8U);
|
|
|
|
// Run step
|
|
runStep<dla::CollapseSingleChild>(TS);
|
|
|
|
// Check graph
|
|
revng_check(TS.getNumLayouts() == 3);
|
|
checkNode(TS, Parent1, 0, InterferingChildrenInfo::Unknown, { 0 });
|
|
checkNode(TS, Parent2, 0, InterferingChildrenInfo::Unknown, { 1 });
|
|
checkNode(TS, Child1, 8, InterferingChildrenInfo::Unknown, { 2, 3 });
|
|
}
|
|
|
|
///\brief Test the case in which there are multiple levels of single-childs to
|
|
/// be collapsed
|
|
BOOST_AUTO_TEST_CASE(CollapseSingleChild_multiLevel) {
|
|
dla::LayoutTypeSystem TS;
|
|
|
|
// Build TS
|
|
LTSN *Level0 = createRoot(TS, 0U);
|
|
LTSN *Level1 = addInstanceAtOffset(TS,
|
|
Level0,
|
|
/*offset=*/0U,
|
|
/*size=*/0U);
|
|
LTSN *Level2 = addInstanceAtOffset(TS,
|
|
Level1,
|
|
/*offset=*/0U,
|
|
/*size=*/0U);
|
|
LTSN *Level3 = addInstanceAtOffset(TS,
|
|
Level2,
|
|
/*offset=*/0U,
|
|
/*size=*/0U);
|
|
/*LTSN *Level4 = */ addInstanceAtOffset(TS,
|
|
Level3,
|
|
/*offset=*/0U,
|
|
/*size=*/8U);
|
|
|
|
// Run step
|
|
runStep<dla::CollapseSingleChild>(TS);
|
|
|
|
// Check graph
|
|
revng_check(TS.getNumLayouts() == 1);
|
|
checkNode(TS, Level0, 8, InterferingChildrenInfo::Unknown, { 0, 1, 2, 3, 4 });
|
|
}
|
|
|
|
// ----------------- ComputeUpperMemberAccesses ---------
|
|
|
|
///\brief Test member access computation
|
|
BOOST_AUTO_TEST_CASE(ComputeUpperMemberAccesses_basic) {
|
|
dla::LayoutTypeSystem TS;
|
|
|
|
// Build TS
|
|
LTSN *Root = createRoot(TS);
|
|
Root->Size = 0U;
|
|
|
|
LTSN *Child1 = createRoot(TS);
|
|
Child1->Size = 8U;
|
|
TS.addInstanceLink(Root, Child1, OffsetExpression{});
|
|
|
|
LTSN *Child2 = createRoot(TS);
|
|
Child2->Size = 8U;
|
|
OffsetExpression MultiOE;
|
|
MultiOE.Offset = 10U;
|
|
MultiOE.Strides = { 10U };
|
|
MultiOE.TripCounts = { 3U };
|
|
TS.addInstanceLink(Root, Child2, std::move(MultiOE));
|
|
|
|
LTSN *Child3 = createRoot(TS);
|
|
Child3->Size = 16U;
|
|
OffsetExpression SingleOE;
|
|
SingleOE.Offset = 30U;
|
|
TS.addInstanceLink(Root, Child3, std::move(SingleOE));
|
|
|
|
LTSN *Root2 = createRoot(TS);
|
|
LTSN *PtrNode = createRoot(TS);
|
|
PtrNode->Size = 8U;
|
|
TS.addInheritanceLink(Root2, PtrNode);
|
|
|
|
// Add pointer edge
|
|
TS.addPointerLink(PtrNode, Root);
|
|
|
|
// Run step
|
|
dla::StepManager SM;
|
|
revng_check(SM.addStep<CollapseIdentityAndInheritanceCC>());
|
|
revng_check(SM.addStep<ComputeUpperMemberAccesses>());
|
|
SM.run(TS);
|
|
// Compress the equivalence classes
|
|
dla::VectEqClasses &Eq = TS.getEqClasses();
|
|
Eq.compress();
|
|
|
|
// Check remaining nodes
|
|
revng_check(TS.getNumLayouts() == 6);
|
|
// Check edges
|
|
unsigned NInstance = 0U;
|
|
for (auto &[Child, Tag] : llvm::children_edges<LTSN *>(Root)) {
|
|
switch (Tag->getKind()) {
|
|
case TypeLinkTag::LK_Instance:
|
|
NInstance++;
|
|
break;
|
|
default:
|
|
revng_check(false);
|
|
}
|
|
}
|
|
revng_check(NInstance == 3);
|
|
// Check size
|
|
revng_check(Root->Size == 46);
|
|
revng_check(Root2->Size == 8);
|
|
|
|
// Check Eq Classes
|
|
revng_check(Eq.getNumElements() == 6);
|
|
revng_check(Eq.getNumClasses() == 6);
|
|
revng_check(not Eq.isRemoved(PtrNode->ID));
|
|
}
|
|
|
|
// ----------------- ComputeNonInterferingComponents ----
|
|
|
|
///\brief Test union nested inside a struct
|
|
BOOST_AUTO_TEST_CASE(ComputeNonInterferingComponents_basic) {
|
|
dla::LayoutTypeSystem TS;
|
|
|
|
// Build TS
|
|
LTSN *Root = createRoot(TS);
|
|
Root->Size = 0U;
|
|
|
|
LTSN *Child1 = createRoot(TS);
|
|
Child1->Size = 8U;
|
|
TS.addInstanceLink(Root, Child1, OffsetExpression{});
|
|
|
|
LTSN *Child2 = createRoot(TS);
|
|
Child2->Size = 8U;
|
|
OffsetExpression MultiOE;
|
|
MultiOE.Offset = 10U;
|
|
MultiOE.Strides = { 10U };
|
|
MultiOE.TripCounts = { 3U };
|
|
TS.addInstanceLink(Root, Child2, std::move(MultiOE));
|
|
|
|
LTSN *Child3 = createRoot(TS);
|
|
Child3->Size = 16U;
|
|
OffsetExpression SingleOE;
|
|
SingleOE.Offset = 30U;
|
|
TS.addInstanceLink(Root, Child3, std::move(SingleOE));
|
|
|
|
LTSN *Root2 = createRoot(TS);
|
|
LTSN *PtrNode = createRoot(TS);
|
|
PtrNode->Size = 8U;
|
|
TS.addInheritanceLink(Root2, PtrNode);
|
|
TS.addPointerLink(PtrNode, Root);
|
|
LTSN *UnionNode = addInstanceAtOffset(TS, Root2, 0U, 8U);
|
|
|
|
// Run step
|
|
VerifyLog.enable();
|
|
dla::StepManager SM;
|
|
revng_check(SM.addStep<CollapseIdentityAndInheritanceCC>());
|
|
revng_check(SM.addStep<ComputeUpperMemberAccesses>());
|
|
revng_check(SM.addStep<ComputeNonInterferingComponents>());
|
|
SM.run(TS);
|
|
// Compress the equivalence classes
|
|
dla::VectEqClasses &Eq = TS.getEqClasses();
|
|
Eq.compress();
|
|
|
|
// Check remaining nodes
|
|
revng_check(TS.getNumLayouts() == 8);
|
|
// Check edges
|
|
unsigned NInstance = 0U;
|
|
for (auto &[Child, Tag] : llvm::children_edges<LTSN *>(Root)) {
|
|
switch (Tag->getKind()) {
|
|
case TypeLinkTag::LK_Instance:
|
|
NInstance++;
|
|
break;
|
|
default:
|
|
revng_check(false);
|
|
}
|
|
}
|
|
revng_check(NInstance == 2);
|
|
// Check size
|
|
revng_check(Root->Size == 46);
|
|
revng_check(Root2->Size == 8);
|
|
revng_check(Root->InterferingInfo = AllChildrenAreNonInterfering);
|
|
revng_check(Child1->InterferingInfo = AllChildrenAreNonInterfering);
|
|
revng_check(Child2->InterferingInfo = AllChildrenAreNonInterfering);
|
|
revng_check(Root2->InterferingInfo = AllChildrenAreInterfering);
|
|
revng_check(PtrNode->InterferingInfo = AllChildrenAreNonInterfering);
|
|
revng_check(UnionNode->InterferingInfo = AllChildrenAreNonInterfering);
|
|
// Check new node
|
|
const auto &[FinalChild1, Tag1] = *(Child2->Predecessors.begin());
|
|
const auto &[FinalChild2, Tag2] = *(Child3->Predecessors.begin());
|
|
revng_check(Tag1->getOffsetExpr().Offset == 0U);
|
|
revng_check(Tag2->getOffsetExpr().Offset == 20U);
|
|
|
|
revng_check(FinalChild1 == FinalChild2);
|
|
|
|
// Check Eq Classes
|
|
revng_check(Eq.getNumElements() == 8);
|
|
revng_check(Eq.getNumClasses() == 8);
|
|
revng_check(not Eq.isRemoved(PtrNode->ID));
|
|
}
|
|
|
|
// ----------------- Propagate to accessors --------------
|
|
|
|
BOOST_AUTO_TEST_CASE(PropagateToAccessors) {
|
|
dla::LayoutTypeSystem TS;
|
|
|
|
// Build TS
|
|
LTSN *NodeA = createRoot(TS);
|
|
LTSN *NodeB = addInheritance(TS, NodeA);
|
|
LTSN *NodeC = addInheritance(TS, NodeA);
|
|
LTSN *NodeD = addInstanceAtOffset(TS, NodeB, /*offset=*/0, /*size=*/0);
|
|
/*LTSN *NodeE = */ addInstanceAtOffset(TS, NodeD, /*offset=*/0, /*size=*/8);
|
|
LTSN *NodeF = addInstanceAtOffset(TS, NodeC, /*offset=*/8, /*size=*/0);
|
|
/*LTSN *NodeG = */ addInstanceAtOffset(TS, NodeF, /*offset=*/0, /*size=*/8);
|
|
|
|
// Run steps
|
|
VerifyLog.enable();
|
|
dla::StepManager SM;
|
|
revng_check(SM.addStep<CollapseIdentityAndInheritanceCC>());
|
|
revng_check(SM.addStep<MakeInheritanceTree>());
|
|
revng_check(SM.addStep<CollapseSingleChild>());
|
|
revng_check(SM.addStep<ComputeUpperMemberAccesses>());
|
|
|
|
SM.run(TS);
|
|
|
|
// Compress the equivalence classes
|
|
dla::VectEqClasses &Eq = TS.getEqClasses();
|
|
Eq.compress();
|
|
|
|
// Check TS
|
|
revng_check(TS.getNumLayouts() == 3);
|
|
checkNode(TS, NodeA, 16, InterferingChildrenInfo::Unknown, { 0, 1, 2 });
|
|
checkNode(TS, NodeD, 8, InterferingChildrenInfo::Unknown, { 3, 4 });
|
|
checkNode(TS, NodeF, 8, InterferingChildrenInfo::Unknown, { 5, 6 });
|
|
}
|
|
|
|
// ----------------- Deduplicate Union Fields --------------
|
|
|
|
BOOST_AUTO_TEST_CASE(DeduplicateUnionFields_basic) {
|
|
dla::LayoutTypeSystem TS;
|
|
|
|
// Build TS
|
|
LTSN *NodeA = createRoot(TS);
|
|
LTSN *NodeB = addInheritance(TS, NodeA);
|
|
/*LTSN *NodeD =*/addInstanceAtOffset(TS, NodeB, /*offset=*/0, /*size=*/8);
|
|
/*LTSN *NodeE =*/addInstanceAtOffset(TS, NodeB, /*offset=*/8, /*size=*/8);
|
|
|
|
LTSN *NodeC = addInstanceAtOffset(TS, NodeA, /*offset=*/0, /*size=*/16);
|
|
LTSN *NodeF = addInstanceAtOffset(TS, NodeC, /*offset=*/0, /*size=*/8);
|
|
LTSN *NodeG = addInstanceAtOffset(TS, NodeC, /*offset=*/8, /*size=*/8);
|
|
|
|
LTSN *Node1 = addInstanceAtOffset(TS, NodeA, /*offset=*/0, /*size=*/12);
|
|
LTSN *Node2 = addInstanceAtOffset(TS, Node1, /*offset=*/4, /*size=*/8);
|
|
LTSN *Node3 = addInstanceAtOffset(TS, Node2, /*offset=*/0, /*size=*/4);
|
|
LTSN *Node4 = addInstanceAtOffset(TS, Node2, /*offset=*/4, /*size=*/4);
|
|
|
|
// Run steps
|
|
VerifyLog.enable();
|
|
dla::StepManager SM;
|
|
revng_check(SM.addStep<CollapseIdentityAndInheritanceCC>());
|
|
revng_check(SM.addStep<ComputeUpperMemberAccesses>());
|
|
revng_check(SM.addStep<ComputeNonInterferingComponents>());
|
|
revng_check(SM.addStep<DeduplicateUnionFields>());
|
|
revng_check(SM.addStep<ComputeNonInterferingComponents>());
|
|
|
|
SM.run(TS);
|
|
|
|
// Compress the equivalence classes
|
|
dla::VectEqClasses &Eq = TS.getEqClasses();
|
|
Eq.compress();
|
|
|
|
// Check TS
|
|
revng_check(TS.getNumLayouts() == 8);
|
|
checkNode(TS, NodeA, 16, AllChildrenAreInterfering, { 0 });
|
|
checkNode(TS, NodeC, 16, AllChildrenAreNonInterfering, { 1, 4 });
|
|
checkNode(TS, NodeF, 8, AllChildrenAreNonInterfering, { 2, 5 });
|
|
checkNode(TS, NodeG, 8, AllChildrenAreNonInterfering, { 3, 6 });
|
|
checkNode(TS, Node1, 12, AllChildrenAreNonInterfering, { 7 });
|
|
checkNode(TS, Node2, 8, AllChildrenAreNonInterfering, { 8 });
|
|
checkNode(TS, Node3, 4, AllChildrenAreNonInterfering, { 9 });
|
|
checkNode(TS, Node4, 4, AllChildrenAreNonInterfering, { 10 });
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(DeduplicateUnionFields_diamond) {
|
|
dla::LayoutTypeSystem TS;
|
|
|
|
// Build TS
|
|
LTSN *NodeA = createRoot(TS);
|
|
LTSN *NodeB = addInheritance(TS, NodeA);
|
|
NodeB->Size = 8;
|
|
/*LTSN *NodeC =*/addInstanceAtOffset(TS, NodeA, /*offset=*/0, /*size=*/8);
|
|
LTSN *NodeD = addInstanceAtOffset(TS, NodeA, /*offset=*/0, /*size=*/0);
|
|
LTSN *NodeE = addInstanceAtOffset(TS, NodeA, /*offset=*/0, /*size=*/0);
|
|
LTSN *NodeF = addInstanceAtOffset(TS, NodeA, /*offset=*/0, /*size=*/0);
|
|
LTSN *NodeG = addInstanceAtOffset(TS, NodeA, /*offset=*/0, /*size=*/0);
|
|
|
|
LTSN *NodeH = addInstanceAtOffset(TS, NodeD, /*offset=*/0, /*size=*/8);
|
|
OffsetExpression OE{};
|
|
OE.Offset = 0;
|
|
TS.addInstanceLink(NodeE, NodeH, std::move(OE));
|
|
|
|
LTSN *NodeI = addInstanceAtOffset(TS, NodeF, /*offset=*/0, /*size=*/8);
|
|
OffsetExpression OE2{};
|
|
OE2.Offset = 0;
|
|
TS.addInstanceLink(NodeG, NodeI, std::move(OE2));
|
|
|
|
// Run steps
|
|
VerifyLog.enable();
|
|
dla::StepManager SM;
|
|
revng_check(SM.addStep<CollapseIdentityAndInheritanceCC>());
|
|
revng_check(SM.addStep<ComputeUpperMemberAccesses>());
|
|
revng_check(SM.addStep<ComputeNonInterferingComponents>());
|
|
revng_check(SM.addStep<DeduplicateUnionFields>());
|
|
revng_check(SM.addStep<ComputeNonInterferingComponents>());
|
|
|
|
SM.run(TS);
|
|
|
|
// Compress the equivalence classes
|
|
dla::VectEqClasses &Eq = TS.getEqClasses();
|
|
Eq.compress();
|
|
|
|
// Check TS
|
|
revng_check(TS.getNumLayouts() == 1);
|
|
checkNode(TS,
|
|
NodeA,
|
|
8,
|
|
AllChildrenAreNonInterfering,
|
|
{ 0, 1, 2, 3, 4, 5, 6, 7, 8 });
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(DeduplicateUnionFields_commonNodeSymmetric) {
|
|
dla::LayoutTypeSystem TS;
|
|
|
|
// Build TS
|
|
LTSN *NodeUnion = createRoot(TS);
|
|
LTSN *NodeA = addInstanceAtOffset(TS, NodeUnion, /*offset=*/0, /*size=*/0);
|
|
LTSN *NodeB = addInstanceAtOffset(TS, NodeA, /*offset=*/0, /*size=*/8);
|
|
LTSN *NodeC = addInstanceAtOffset(TS, NodeA, /*offset=*/0, /*size=*/0);
|
|
/*LTSN *NodeD =*/addInstanceAtOffset(TS, NodeC, /*offset=*/8, /*size=*/8);
|
|
|
|
LTSN *NodeA1 = addInstanceAtOffset(TS, NodeUnion, /*offset=*/0, /*size=*/0);
|
|
LTSN *NodeC1 = addInstanceAtOffset(TS, NodeA1, /*offset=*/0, /*size=*/0);
|
|
LTSN *NodeD1 = addInstanceAtOffset(TS, NodeC1, /*offset=*/8, /*size=*/8);
|
|
OffsetExpression OE{};
|
|
OE.Offset = 0;
|
|
TS.addInstanceLink(NodeA1, NodeB, std::move(OE));
|
|
|
|
// Run steps
|
|
VerifyLog.enable();
|
|
dla::StepManager SM;
|
|
revng_check(SM.addStep<CollapseIdentityAndInheritanceCC>());
|
|
revng_check(SM.addStep<ComputeUpperMemberAccesses>());
|
|
revng_check(SM.addStep<ComputeNonInterferingComponents>());
|
|
revng_check(SM.addStep<DeduplicateUnionFields>());
|
|
revng_check(SM.addStep<ComputeNonInterferingComponents>());
|
|
|
|
SM.run(TS);
|
|
|
|
// Compress the equivalence classes
|
|
dla::VectEqClasses &Eq = TS.getEqClasses();
|
|
Eq.compress();
|
|
|
|
// Check TS
|
|
revng_check(TS.getNumLayouts() == 4);
|
|
checkNode(TS, NodeUnion, 16, AllChildrenAreInterfering, { 0, 1, 5 });
|
|
checkNode(TS, NodeB, 8, AllChildrenAreNonInterfering, { 2 });
|
|
checkNode(TS, NodeC1, 16, AllChildrenAreNonInterfering, { 3, 6 });
|
|
checkNode(TS, NodeD1, 8, AllChildrenAreNonInterfering, { 4, 7 });
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(DeduplicateUnionFields_commonNodeAsymmetric) {
|
|
dla::LayoutTypeSystem TS;
|
|
|
|
// Build TS
|
|
LTSN *NodeUnion = createRoot(TS);
|
|
LTSN *NodeA = addInstanceAtOffset(TS, NodeUnion, /*offset=*/0, /*size=*/0);
|
|
/*LTSN *NodeB =*/addInstanceAtOffset(TS, NodeA, /*offset=*/0, /*size=*/8);
|
|
LTSN *NodeC = addInstanceAtOffset(TS, NodeA, /*offset=*/0, /*size=*/0);
|
|
LTSN *NodeD = addInstanceAtOffset(TS, NodeC, /*offset=*/4, /*size=*/8);
|
|
|
|
LTSN *NodeA1 = addInstanceAtOffset(TS, NodeUnion, /*offset=*/0, /*size=*/0);
|
|
LTSN *NodeC1 = addInstanceAtOffset(TS, NodeA1, /*offset=*/0, /*size=*/0);
|
|
LTSN *NodeD1 = addInstanceAtOffset(TS, NodeC1, /*offset=*/4, /*size=*/8);
|
|
OffsetExpression OE{};
|
|
OE.Offset = 0;
|
|
TS.addInstanceLink(NodeA1, NodeD, std::move(OE));
|
|
|
|
// Run steps
|
|
VerifyLog.enable();
|
|
dla::StepManager SM;
|
|
revng_check(SM.addStep<CollapseIdentityAndInheritanceCC>());
|
|
revng_check(SM.addStep<ComputeUpperMemberAccesses>());
|
|
revng_check(SM.addStep<ComputeNonInterferingComponents>());
|
|
revng_check(SM.addStep<DeduplicateUnionFields>());
|
|
revng_check(SM.addStep<ComputeNonInterferingComponents>());
|
|
|
|
SM.run(TS);
|
|
|
|
// Compress the equivalence classes
|
|
dla::VectEqClasses &Eq = TS.getEqClasses();
|
|
Eq.compress();
|
|
|
|
// Check TS
|
|
revng_check(TS.getNumLayouts() == 3);
|
|
checkNode(TS, NodeUnion, 12, AllChildrenAreInterfering, { 0, 1, 5 });
|
|
checkNode(TS, NodeC1, 12, AllChildrenAreNonInterfering, { 3, 6 });
|
|
checkNode(TS, NodeD1, 8, AllChildrenAreNonInterfering, { 2, 4, 7 });
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(DeduplicateUnionFields_commonNodeAsymmetricCollapse) {
|
|
dla::LayoutTypeSystem TS;
|
|
|
|
// Build TS
|
|
LTSN *NodeUnion = createRoot(TS);
|
|
LTSN *NodeA = addInstanceAtOffset(TS, NodeUnion, /*offset=*/0, /*size=*/0);
|
|
LTSN *NodeB = addInstanceAtOffset(TS, NodeA, /*offset=*/0, /*size=*/8);
|
|
LTSN *NodeC = addInstanceAtOffset(TS, NodeA, /*offset=*/0, /*size=*/0);
|
|
LTSN *NodeD = addInstanceAtOffset(TS, NodeC, /*offset=*/0, /*size=*/8);
|
|
|
|
LTSN *NodeA1 = addInstanceAtOffset(TS, NodeUnion, /*offset=*/0, /*size=*/0);
|
|
LTSN *NodeC1 = addInstanceAtOffset(TS, NodeA1, /*offset=*/0, /*size=*/0);
|
|
/* LTSN *NodeD1 = */ addInstanceAtOffset(TS, NodeC1, /*offset=*/0, /*size=*/8);
|
|
OffsetExpression OE{};
|
|
OE.Offset = 0;
|
|
TS.addInstanceLink(NodeA1, NodeD, std::move(OE));
|
|
|
|
// Run steps
|
|
VerifyLog.enable();
|
|
dla::StepManager SM;
|
|
revng_check(SM.addStep<CollapseIdentityAndInheritanceCC>());
|
|
revng_check(SM.addStep<ComputeUpperMemberAccesses>());
|
|
revng_check(SM.addStep<ComputeNonInterferingComponents>());
|
|
revng_check(SM.addStep<DeduplicateUnionFields>());
|
|
revng_check(SM.addStep<ComputeNonInterferingComponents>());
|
|
|
|
SM.run(TS);
|
|
|
|
// Compress the equivalence classes
|
|
dla::VectEqClasses &Eq = TS.getEqClasses();
|
|
Eq.compress();
|
|
|
|
// Check TS
|
|
revng_check(TS.getNumLayouts() == 6);
|
|
checkNode(TS, NodeUnion, 8, AllChildrenAreInterfering, { 0 });
|
|
checkNode(TS, NodeA, 8, AllChildrenAreInterfering, { 1 });
|
|
checkNode(TS, NodeB, 8, AllChildrenAreNonInterfering, { 2 });
|
|
checkNode(TS, NodeC, 8, AllChildrenAreNonInterfering, { 3 });
|
|
|
|
checkNode(TS, NodeA1, 8, AllChildrenAreNonInterfering, { 5 });
|
|
checkNode(TS, NodeC1, 8, AllChildrenAreNonInterfering, { 4, 6, 7 });
|
|
}
|
|
|
|
// ----------------- Remove Conflicting edges --------------
|
|
|
|
BOOST_AUTO_TEST_CASE(RemoveConflictingEdges_basic) {
|
|
dla::LayoutTypeSystem TS;
|
|
|
|
// Build TS
|
|
LTSN *NodeA = createRoot(TS);
|
|
LTSN *NodeB = addInstanceAtOffset(TS, NodeA, /*offset=*/0, /*size=*/8);
|
|
TS.addInheritanceLink(NodeA, NodeB);
|
|
|
|
LTSN *Node1 = createRoot(TS);
|
|
LTSN *Node2 = addInstanceAtOffset(TS, Node1, /*offset=*/4, /*size=*/8);
|
|
TS.addInheritanceLink(Node1, Node2);
|
|
|
|
// Run steps
|
|
VerifyLog.enable();
|
|
dla::StepManager SM;
|
|
revng_check(SM.addStep<RemoveConflictingEdges>());
|
|
|
|
SM.run(TS);
|
|
|
|
// Compress the equivalence classes
|
|
dla::VectEqClasses &Eq = TS.getEqClasses();
|
|
Eq.compress();
|
|
|
|
// Check TS
|
|
revng_check(TS.getNumLayouts() == 4);
|
|
revng_check(NodeA->Successors.size() == 1);
|
|
revng_check(Node1->Successors.size() == 2);
|
|
}
|