Files
revng-revng/tests/Unit/stackanalysis.cpp
T
Alessandro Di Federico a5af28621b Introducing the stack analysis
The stack analysis is the foundation to obtain accurate information
about the body of a function, which registers are callee-saved,
arguments, return values and so on.

It is implemented as a pass to run in revamb-dump.

This commit also introduces analysis tests specific to what we aim to
obtain from the analysis and also some basic unit tests for data
structures related to the stack analysis.
2017-08-12 16:56:23 +02:00

175 lines
5.1 KiB
C++

/// \file stackanalysis.cpp
/// \brief Tests for StackAnalysis data structures
//
// This file is distributed under the MIT License. See LICENSE.md for details.
//
// Standard includes
// Boost includes
#define BOOST_TEST_MODULE StackAnalysis
#include <boost/test/unit_test.hpp>
// Local includes
#include "stackanalysis_impl.h"
using namespace StackAnalysis;
BOOST_TEST_DONT_PRINT_LOG_VALUE(ASID)
BOOST_TEST_DONT_PRINT_LOG_VALUE(ASSlot)
BOOST_TEST_DONT_PRINT_LOG_VALUE(std::vector<ASID>)
static_assert(ASID::RestOfTheStackID == ASID::LastStackID - 1,
"We expect RST to be right before SP0");
const ASID SP0 = ASID::lastStackID();
const ASID SP1 = ASID(SP0.id() + 1);
const ASID GLB = ASID::globalID();
const ASID CPU = ASID::cpuID();
const ASID RST = ASID::restOfTheStackID();
const ASID DED = ASID::deadStackID();
const ASID Invalid = ASID::invalidID();
using ASVector = std::vector<ASID>;
ASVector toVector(ASSet S) {
ASVector Result;
std::copy(S.begin(), S.end(), std::back_inserter(Result));
return Result;
}
BOOST_AUTO_TEST_CASE(TestAddressSpaceID) {
// Test ordering
BOOST_TEST(SP0.lowerThanOrEqual(SP0, Invalid));
BOOST_TEST(!SP0.greaterThan(SP0, Invalid));
BOOST_TEST(SP0.greaterThan(SP1, Invalid));
BOOST_TEST(SP0.greaterThan(GLB, Invalid));
BOOST_TEST(SP0.greaterThan(RST, Invalid));
BOOST_TEST(RST.greaterThan(SP0, Invalid));
BOOST_TEST(SP1.lowerThanOrEqual(RST, SP0));
BOOST_TEST(SP0.greaterThan(RST, SP0));
// Test moving and capping
BOOST_TEST(SP0.getCallerStack(Invalid.id()) == SP1);
BOOST_TEST(SP0.getCallerStack(SP0.id()) == RST);
BOOST_TEST(SP0.shiftAddressSpaces(+1) == SP1);
BOOST_TEST(SP1.shiftAddressSpaces(-1) == SP0);
BOOST_TEST(SP0.shiftAddressSpaces(-1) == DED);
BOOST_TEST(SP1.shiftAddressSpaces(-2) == DED);
BOOST_TEST(CPU.shiftAddressSpaces(-1) == CPU);
BOOST_TEST(CPU.shiftAddressSpaces(+1) == CPU);
BOOST_TEST(GLB.shiftAddressSpaces(-1) == GLB);
BOOST_TEST(GLB.shiftAddressSpaces(+1) == GLB);
BOOST_TEST(GLB.cap(SP0.id()) == GLB);
BOOST_TEST(SP0.cap(SP0.id()) == SP0);
BOOST_TEST(SP1.cap(SP0.id()) == RST);
}
BOOST_AUTO_TEST_CASE(TestASFunction) {
ASID GLB = ASID::globalID();
ASID CPU = ASID::cpuID();
// Test membership and adding element
ASSet ASF = ASSet::singleElement(CPU);
BOOST_TEST(toVector(ASF) == (ASVector { CPU }));
BOOST_TEST(ASF[CPU] == true);
BOOST_TEST(ASF[GLB] == false);
ASF.add(GLB);
BOOST_TEST(toVector(ASF) == (ASVector { GLB, CPU }));
BOOST_TEST(ASF[CPU] == true);
BOOST_TEST(ASF[GLB] == true);
ASF.add(RST);
BOOST_TEST(toVector(ASF) == (ASVector { GLB, CPU, RST }));
BOOST_TEST(ASF.contains(SP1, SP0));
BOOST_TEST(!ASF.contains(SP1, SP1));
// Test lowerThanOrEqual
ASSet Other = ASF;
Other.add(SP0);
BOOST_TEST(toVector(ASF) == (ASVector { GLB, CPU, RST }));
BOOST_TEST(toVector(Other) == (ASVector { GLB, CPU, RST, SP0 }));
BOOST_TEST(ASF.lowerThanOrEqual(Other, Invalid));
ASF.add(SP1);
BOOST_TEST(toVector(ASF) == (ASVector { GLB, CPU, RST, SP1 }));
BOOST_TEST(ASF.greaterThan(Other, Invalid));
BOOST_TEST(ASF.lowerThanOrEqual(Other, SP0));
// Test combine
ASSet Tmp;
Tmp = Other;
Tmp.combine(ASF, Invalid);
BOOST_TEST(toVector(Tmp) == (ASVector { GLB, CPU, RST, SP0, SP1 }));
Tmp = Other;
Tmp.combine(ASF, SP0);
BOOST_TEST(toVector(Tmp) == (ASVector { GLB, CPU, RST, SP0 }));
ASSet A = ASSet::singleElement(CPU);
ASSet B = ASSet::singleElement(SP1);
Tmp = A;
Tmp.combine(B, SP0);
BOOST_TEST(toVector(Tmp) == (ASVector { CPU, RST }));
Tmp = A;
Tmp.combine(B, SP1);
BOOST_TEST(toVector(Tmp) == (ASVector { CPU, SP1 }));
// Test drop
Tmp = A;
Tmp.drop(CPU);
BOOST_TEST(toVector(Tmp) == (ASVector { }));
BOOST_TEST(Tmp.empty());
// Test shiftAddressSpaces
Tmp = Other;
BOOST_TEST(toVector(Tmp) == (ASVector { GLB, CPU, RST, SP0 }));
Tmp.shiftAddressSpaces(+1);
BOOST_TEST(toVector(Tmp) == (ASVector { GLB, CPU, RST, SP1 }));
Tmp.shiftAddressSpaces(-1);
BOOST_TEST(toVector(Tmp) == (ASVector { GLB, CPU, RST, SP0 }));
Tmp.shiftAddressSpaces(-1);
BOOST_TEST(toVector(Tmp) == (ASVector { DED, GLB, CPU, RST }));
// Test capAddressSpaces
Tmp = Other;
BOOST_TEST(toVector(Tmp) == (ASVector { GLB, CPU, RST, SP0 }));
Tmp.capAddressSpaces(RST.id());
BOOST_TEST(toVector(Tmp) == (ASVector { GLB, CPU, RST }));
Tmp.add(SP1);
BOOST_TEST(toVector(Tmp) == (ASVector { GLB, CPU, RST, SP1 }));
Tmp.capAddressSpaces(SP0.id());
BOOST_TEST(toVector(Tmp) == (ASVector { GLB, CPU, RST }));
}
BOOST_AUTO_TEST_CASE(TestASSlot) {
// Test comparisons
ASSlot SP1Slot(SP1, 0);
ASSlot RSTSlot(RST, 0);
BOOST_TEST(SP1Slot == SP1Slot);
BOOST_TEST(SP1Slot != RSTSlot);
BOOST_TEST(SP1Slot.greaterThan(RSTSlot, Invalid));
BOOST_TEST(SP1Slot.lowerThanOrEqual(RSTSlot, SP0));
// Test addition and masking
SP1Slot.add(-5);
BOOST_TEST(SP1Slot.offset() == -5);
SP1Slot.add(+10);
BOOST_TEST(SP1Slot.offset() == +5);
SP1Slot.mask(1);
BOOST_TEST(SP1Slot.offset() == +1);
// Test flattening
BOOST_TEST(toVector(SP1Slot.flatten()) == (ASVector { SP1 }));
// Test usage in a map
std::map<ASSlot, int> Map;
Map[SP1Slot] = 0;
BOOST_TEST(Map.count(SP1Slot) != 0);
}