Files
revng-revng/tests/Unit/DLASteps.cpp
T
Giacomo Vercesi ab125b35b0 Fix License headers
Change company name to "rev.ng Labs Srl" in all license headers
to reflect changed company name and legal status
Add missing license headers to files that didn't have one
2022-04-19 12:17:59 +02:00

737 lines
25 KiB
C++

//
// Copyright rev.ng Labs Srl. 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 *
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
/// Test an equality CC with a pointer edge
BOOST_AUTO_TEST_CASE(CollapseEquality) {
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::CollapseEqualitySCC>(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 });
}
/// Test an instance-at-offset-0 loop with a pointer edge
BOOST_AUTO_TEST_CASE(CollapseInstanceAtOffset0SCC_instance0) {
dla::LayoutTypeSystem TS;
// Build TS
LTSN *Root = createRoot(TS);
LTSN *Node1 = addInstanceAtOffset(TS, Root, 0, 0);
LTSN *Node2 = addInstanceAtOffset(TS, Root, 0, 0);
LTSN *Node3 = addInstanceAtOffset(TS, Node2, 0, 0);
TS.addInstanceLink(Node3, Root, OffsetExpression{});
LTSN *Node4 = addInstanceAtOffset(TS, Node1, 0, 0);
LTSN *PtrNode = createRoot(TS);
TS.addPointerLink(Node4, PtrNode);
runStep<dla::CollapseInstanceAtOffset0SCC>(TS);
// Check that instance-at-offset-0 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 });
}
/// Test an instance-at-offset-0 CC with a backward
/// instance-at-offset-nonzero
BOOST_AUTO_TEST_CASE(CollapseInstanceSCC_instancenon0) {
dla::LayoutTypeSystem TS;
// Build TS
LTSN *Root = createRoot(TS);
LTSN *Node1 = addInstanceAtOffset(TS, Root, 0, 0);
LTSN *Node2 = addInstanceAtOffset(TS, Root, 0, 0);
LTSN *Node3 = addInstanceAtOffset(TS, Node2, 0, 0);
TS.addInstanceLink(Node3, Root, OffsetExpression{ 8 });
LTSN *Node4 = addInstanceAtOffset(TS, Node1, 0, 16);
LTSN *PtrNode = createRoot(TS);
TS.addPointerLink(Node4, PtrNode);
// Run step
runStep<dla::CollapseInstanceAtOffset0SCC>(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);
}
// ----------------- PruneLayoutNodesWithoutLayout ------
/// 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 ----------------
/// 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 });
}
/// 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 });
}
/// 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 });
}
/// 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 ---------
/// 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.addInstanceLink(Root2, PtrNode, OffsetExpression{});
// Add pointer edge
TS.addPointerLink(PtrNode, Root);
// Run step
dla::StepManager SM;
revng_check(SM.addStep<CollapseEqualitySCC>());
revng_check(SM.addStep<CollapseInstanceAtOffset0SCC>());
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 ----
/// 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.addInstanceLink(Root2, PtrNode, OffsetExpression{});
TS.addPointerLink(PtrNode, Root);
LTSN *UnionNode = addInstanceAtOffset(TS, Root2, 0U, 8U);
// Run step
VerifyLog.enable();
dla::StepManager SM;
revng_check(SM.addStep<CollapseEqualitySCC>());
revng_check(SM.addStep<CollapseInstanceAtOffset0SCC>());
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));
}
// ----------------- Deduplicate Union Fields --------------
BOOST_AUTO_TEST_CASE(DeduplicateUnionFields_basic) {
dla::LayoutTypeSystem TS;
// Build TS
LTSN *NodeA = createRoot(TS);
LTSN *NodeB = addInstanceAtOffset(TS, NodeA, /*offset=*/0, /*size=*/0);
/*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<CollapseEqualitySCC>());
revng_check(SM.addStep<CollapseInstanceAtOffset0SCC>());
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 = addInstanceAtOffset(TS, NodeA, /*offset=*/0, /*size=*/0);
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<CollapseEqualitySCC>());
revng_check(SM.addStep<CollapseInstanceAtOffset0SCC>());
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<CollapseEqualitySCC>());
revng_check(SM.addStep<CollapseInstanceAtOffset0SCC>());
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<CollapseEqualitySCC>());
revng_check(SM.addStep<CollapseInstanceAtOffset0SCC>());
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<CollapseEqualitySCC>());
revng_check(SM.addStep<CollapseInstanceAtOffset0SCC>());
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 });
}