mirror of
https://github.com/revng/revng
synced 2026-06-21 14:07:57 +00:00
ab125b35b0
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
584 lines
16 KiB
C++
584 lines
16 KiB
C++
/// \file MarkForSerializationTest.cpp
|
|
/// Test for MarkForSerialization
|
|
|
|
//
|
|
// Copyright rev.ng Labs Srl. See LICENSE.md for details.
|
|
//
|
|
|
|
#include <compare>
|
|
#include <map>
|
|
#include <set>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#define BOOST_TEST_MODULE MarkForSerializationTest
|
|
bool init_unit_test();
|
|
#include "boost/test/unit_test.hpp"
|
|
|
|
#include "llvm/IR/Function.h"
|
|
#include "llvm/IR/Module.h"
|
|
#include "llvm/IR/Verifier.h"
|
|
|
|
#include "revng/Support/IRHelpers.h"
|
|
#include "revng/UnitTestHelpers/LLVMTestHelpers.h"
|
|
|
|
#include "revng-c/MarkForSerialization/MarkAnalysis.h"
|
|
#include "revng-c/MarkForSerialization/MarkForSerializationPass.h"
|
|
|
|
struct BBSerializationFlags {
|
|
std::string BBName;
|
|
std::vector<SerializationReason> InstrFlags;
|
|
};
|
|
|
|
using ExpectedDuplicatesType = std::vector<unsigned>;
|
|
using ExpectedFlagsType = std::vector<BBSerializationFlags>;
|
|
|
|
static void
|
|
runTestOnFunctionWithExpected(const char *Body,
|
|
const ExpectedDuplicatesType &ExpectedDups,
|
|
const ExpectedFlagsType &Expected) {
|
|
MarkLog.enable();
|
|
revng_log(MarkLog, "Running Test On Function: " << Body);
|
|
|
|
llvm::LLVMContext C;
|
|
std::unique_ptr<llvm::Module> M = loadModule(C, Body);
|
|
revng_check(not llvm::verifyModule(*M, &llvm::dbgs()));
|
|
|
|
// main is present and has a body
|
|
llvm::Function *F = M->getFunction("main");
|
|
revng_check(nullptr != F);
|
|
revng_check(not F->empty());
|
|
|
|
SerializationMap Results;
|
|
MarkAnalysis::Analysis Mark(*F, Results);
|
|
Mark.initialize();
|
|
Mark.run();
|
|
|
|
// We expect a vector of results for each BasicBlock in F, otherwise the
|
|
// Expected results are not well formed.
|
|
revng_check(F->size() == Expected.size());
|
|
|
|
for (const auto &[BB, BBFlags] : llvm::zip_first(*F, Expected)) {
|
|
const auto &[BBName, InstrFlagVec] = BBFlags;
|
|
// Name matches
|
|
revng_check(BB.hasName() and BB.getName().str() == BBName);
|
|
// Same number of instructions
|
|
revng_check(BB.size() == InstrFlagVec.size());
|
|
for (const auto &[I, ExpectedFlag] : llvm::zip_first(BB, InstrFlagVec)) {
|
|
// Check that the expected flags match the computed one.
|
|
// Using Results[] may create a None flag if non was computed but that's
|
|
// not a problem.
|
|
revng_log(MarkLog, dumpToString(&I));
|
|
revng_log(MarkLog,
|
|
"Results[&I].value() = " << Results[&I].value()
|
|
<< " ExpectedFlag = " << ExpectedFlag);
|
|
revng_check(Results[&I].value() == ExpectedFlag);
|
|
}
|
|
}
|
|
}
|
|
|
|
using InstrNameToLoadNamesMap = std::map<std::string, std::set<std::string>>;
|
|
|
|
BOOST_AUTO_TEST_CASE(AlwaysSerializeNoUses) {
|
|
|
|
const char *EmptyBody = R"LLVM(
|
|
unreachable
|
|
)LLVM";
|
|
|
|
ExpectedDuplicatesType ExpectedDups{ 1 };
|
|
|
|
ExpectedFlagsType ExpectedFlags{
|
|
BBSerializationFlags{ "initial_block", { AlwaysSerialize } },
|
|
};
|
|
|
|
runTestOnFunctionWithExpected(EmptyBody, ExpectedDups, ExpectedFlags);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(Ret) {
|
|
|
|
const char *Body = R"LLVM(
|
|
ret void
|
|
)LLVM";
|
|
|
|
ExpectedDuplicatesType ExpectedDups{ 1 };
|
|
|
|
ExpectedFlagsType ExpectedFlags{
|
|
BBSerializationFlags{ "initial_block", { AlwaysSerialize } },
|
|
};
|
|
|
|
runTestOnFunctionWithExpected(Body, ExpectedDups, ExpectedFlags);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(CallSideEffects) {
|
|
|
|
const char *Body = R"LLVM(
|
|
%bswapped = call i64 @llvm.bswap.i64(i64 1231231231)
|
|
unreachable
|
|
)LLVM";
|
|
|
|
ExpectedDuplicatesType ExpectedDups{ 1 };
|
|
|
|
ExpectedFlagsType ExpectedFlags{
|
|
BBSerializationFlags{
|
|
"initial_block", { HasSideEffects | AlwaysSerialize, AlwaysSerialize } },
|
|
};
|
|
|
|
runTestOnFunctionWithExpected(Body, ExpectedDups, ExpectedFlags);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(StoreSideEffects) {
|
|
|
|
const char *Body = R"LLVM(
|
|
store i64 123, i64 * inttoptr (i64 4294967296 to i64*)
|
|
unreachable
|
|
)LLVM";
|
|
|
|
ExpectedDuplicatesType ExpectedDups{ 1 };
|
|
|
|
ExpectedFlagsType ExpectedFlags{
|
|
BBSerializationFlags{
|
|
"initial_block", { HasSideEffects | AlwaysSerialize, AlwaysSerialize } },
|
|
};
|
|
|
|
runTestOnFunctionWithExpected(Body, ExpectedDups, ExpectedFlags);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(AllocaNeedsLocalVar) {
|
|
|
|
const char *Body = R"LLVM(
|
|
%alloca = alloca i64, align 8
|
|
unreachable
|
|
)LLVM";
|
|
|
|
ExpectedDuplicatesType ExpectedDups{ 1 };
|
|
|
|
ExpectedFlagsType ExpectedFlags{
|
|
BBSerializationFlags{
|
|
"initial_block",
|
|
{ NeedsLocalVarToComputeExpr | AlwaysSerialize, AlwaysSerialize } },
|
|
};
|
|
|
|
runTestOnFunctionWithExpected(Body, ExpectedDups, ExpectedFlags);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(InsertValue) {
|
|
|
|
const char *Body = R"LLVM(
|
|
%a = insertvalue {i64, i32} undef, i64 1, 0
|
|
unreachable
|
|
)LLVM";
|
|
|
|
ExpectedDuplicatesType ExpectedDups{ 1 };
|
|
|
|
ExpectedFlagsType ExpectedFlags{
|
|
BBSerializationFlags{
|
|
"initial_block",
|
|
{ NeedsLocalVarToComputeExpr | NeedsManyStatements | AlwaysSerialize,
|
|
AlwaysSerialize } },
|
|
};
|
|
|
|
runTestOnFunctionWithExpected(Body, ExpectedDups, ExpectedFlags);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(ManyUses) {
|
|
|
|
const char *Body = R"LLVM(
|
|
%pointer = inttoptr i64 4294967296 to i64*
|
|
%loaded = load i64, i64 * %pointer
|
|
%reloaded = load i64, i64 * %pointer
|
|
unreachable
|
|
)LLVM";
|
|
|
|
ExpectedDuplicatesType ExpectedDups{ 1 };
|
|
|
|
ExpectedFlagsType ExpectedFlags{
|
|
BBSerializationFlags{
|
|
"initial_block",
|
|
{ HasManyUses, AlwaysSerialize, AlwaysSerialize, AlwaysSerialize } },
|
|
};
|
|
|
|
runTestOnFunctionWithExpected(Body, ExpectedDups, ExpectedFlags);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(BranchNone) {
|
|
|
|
const char *Body = R"LLVM(
|
|
br label %next
|
|
|
|
next:
|
|
unreachable
|
|
)LLVM";
|
|
|
|
ExpectedDuplicatesType ExpectedDups{ 1, 1 };
|
|
|
|
ExpectedFlagsType ExpectedFlags{
|
|
BBSerializationFlags{ "initial_block", { None } },
|
|
BBSerializationFlags{ "next", { AlwaysSerialize } },
|
|
};
|
|
|
|
runTestOnFunctionWithExpected(Body, ExpectedDups, ExpectedFlags);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(Interfering) {
|
|
|
|
const char *Body = R"LLVM(
|
|
%pointer = inttoptr i64 4294967296 to i64*
|
|
%loaded = load i64, i64 * %pointer
|
|
store i64 undef, i64 * %pointer
|
|
store i64 %loaded, i64 * %pointer
|
|
unreachable
|
|
)LLVM";
|
|
|
|
ExpectedDuplicatesType ExpectedDups{ 1 };
|
|
|
|
ExpectedFlagsType ExpectedFlags{
|
|
BBSerializationFlags{ "initial_block",
|
|
{ HasManyUses,
|
|
HasInterferingSideEffects,
|
|
AlwaysSerialize | HasSideEffects,
|
|
AlwaysSerialize | HasSideEffects,
|
|
AlwaysSerialize } },
|
|
};
|
|
|
|
runTestOnFunctionWithExpected(Body, ExpectedDups, ExpectedFlags);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(NonInterfering) {
|
|
|
|
const char *Body = R"LLVM(
|
|
%pointer = inttoptr i64 4294967296 to i64*
|
|
%loaded = load i64, i64 * %pointer
|
|
store i64 %loaded, i64 * %pointer
|
|
unreachable
|
|
)LLVM";
|
|
|
|
ExpectedDuplicatesType ExpectedDups{ 1 };
|
|
|
|
ExpectedFlagsType ExpectedFlags{
|
|
BBSerializationFlags{ "initial_block",
|
|
{ HasManyUses,
|
|
None,
|
|
HasSideEffects | AlwaysSerialize,
|
|
AlwaysSerialize } },
|
|
};
|
|
|
|
runTestOnFunctionWithExpected(Body, ExpectedDups, ExpectedFlags);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(ComplexNonInterfering) {
|
|
|
|
const char *Body = R"LLVM(
|
|
%pointer = inttoptr i64 4294967296 to i64*
|
|
%loaded = load i64, i64 * %pointer
|
|
%sum1 = add i64 %loaded, 4
|
|
%sum2 = add i64 %sum1, 4
|
|
store i64 %sum2, i64 * %pointer
|
|
unreachable
|
|
)LLVM";
|
|
|
|
ExpectedDuplicatesType ExpectedDups{ 1 };
|
|
|
|
ExpectedFlagsType ExpectedFlags{
|
|
BBSerializationFlags{ /*.BBName =*/"initial_block",
|
|
/*.InstrFlags =*/{ HasManyUses,
|
|
None,
|
|
None,
|
|
None,
|
|
AlwaysSerialize | HasSideEffects,
|
|
AlwaysSerialize } },
|
|
};
|
|
|
|
runTestOnFunctionWithExpected(Body, ExpectedDups, ExpectedFlags);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(DoubleIndirectionWithoutSideEffects) {
|
|
|
|
const char *Body = R"LLVM(
|
|
%ptrtoptr = inttoptr i64 4294967296 to i64**
|
|
%ptr = load i64*, i64 **%ptrtoptr
|
|
%value = load i64, i64 *%ptr
|
|
%call = call i64 @llvm.bswap.i64(i64 %value)
|
|
unreachable
|
|
)LLVM";
|
|
|
|
ExpectedDuplicatesType ExpectedDups{ 1 };
|
|
|
|
ExpectedFlagsType ExpectedFlags{
|
|
BBSerializationFlags{ /*.BBName =*/"initial_block",
|
|
/*.InstrFlags =*/{ None,
|
|
None,
|
|
None,
|
|
AlwaysSerialize | HasSideEffects,
|
|
AlwaysSerialize } },
|
|
};
|
|
|
|
runTestOnFunctionWithExpected(Body, ExpectedDups, ExpectedFlags);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(DoubleIndirectionWithSideEffects) {
|
|
|
|
const char *Body = R"LLVM(
|
|
%ptrtoptr = inttoptr i64 4294967296 to i64**
|
|
%ptr = load i64*, i64 **%ptrtoptr
|
|
%call = call i64 @llvm.bswap.i64(i64 1032143324)
|
|
%value = load i64, i64 *%ptr
|
|
%othercall = call i64 @llvm.bswap.i64(i64 %value)
|
|
unreachable
|
|
)LLVM";
|
|
|
|
ExpectedDuplicatesType ExpectedDups{ 1 };
|
|
|
|
ExpectedFlagsType ExpectedFlags{
|
|
BBSerializationFlags{ /*.BBName =*/"initial_block",
|
|
/*.InstrFlags =*/{ None,
|
|
HasInterferingSideEffects,
|
|
AlwaysSerialize | HasSideEffects,
|
|
None,
|
|
AlwaysSerialize | HasSideEffects,
|
|
AlwaysSerialize } },
|
|
};
|
|
|
|
runTestOnFunctionWithExpected(Body, ExpectedDups, ExpectedFlags);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(ConditionalIsNotSerialized1) {
|
|
const char *Body = R"LLVM(
|
|
%pointer0 = inttoptr i64 4294967000 to i64*
|
|
%value0 = load i64, i64 *%pointer0
|
|
%pointer1 = inttoptr i64 4294967000 to i64*
|
|
%value1 = load i64, i64 *%pointer1
|
|
%pointer2 = inttoptr i64 4294967200 to i64*
|
|
%value2 = load i64, i64 *%pointer2
|
|
%cmp = icmp ult i64 %value1, %value2
|
|
br i1 %cmp, label %smaller, label %greater
|
|
|
|
smaller:
|
|
br label %end
|
|
|
|
greater:
|
|
br label %end
|
|
|
|
end:
|
|
store i64 %value0, i64 * %pointer0
|
|
unreachable
|
|
)LLVM";
|
|
|
|
ExpectedDuplicatesType ExpectedDups{ 1, 1, 1, 1 };
|
|
|
|
ExpectedFlagsType ExpectedFlags{
|
|
BBSerializationFlags{ /*.BBName =*/"initial_block",
|
|
/*.InstrFlags =*/
|
|
{
|
|
HasManyUses,
|
|
None,
|
|
None,
|
|
None,
|
|
None,
|
|
None,
|
|
None,
|
|
None,
|
|
} },
|
|
BBSerializationFlags{ /*.BBName =*/"smaller",
|
|
/*.InstrFlags =*/{ None } },
|
|
BBSerializationFlags{ /*.BBName =*/"greater",
|
|
/*.InstrFlags =*/{ None } },
|
|
BBSerializationFlags{
|
|
/*.BBName =*/"end",
|
|
/*.InstrFlags =*/{ HasSideEffects | AlwaysSerialize, AlwaysSerialize } },
|
|
};
|
|
|
|
runTestOnFunctionWithExpected(Body, ExpectedDups, ExpectedFlags);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(ConditionalIsNotSerialized2) {
|
|
const char *Body = R"LLVM(
|
|
%pointer0 = inttoptr i64 4294967000 to i64*
|
|
%value0 = load i64, i64 *%pointer0
|
|
%pointer1 = inttoptr i64 4294967000 to i64*
|
|
%value1 = load i64, i64 *%pointer1
|
|
%pointer2 = inttoptr i64 4294967200 to i64*
|
|
%value2 = load i64, i64 *%pointer2
|
|
%cmp = icmp ult i64 %value1, %value2
|
|
br i1 %cmp, label %smaller, label %greater
|
|
|
|
smaller:
|
|
br label %end
|
|
|
|
greater:
|
|
store i64 %value0, i64 * %pointer0
|
|
br label %end
|
|
|
|
end:
|
|
unreachable
|
|
)LLVM";
|
|
|
|
ExpectedDuplicatesType ExpectedDups{ 1, 1, 1, 1 };
|
|
|
|
ExpectedFlagsType ExpectedFlags{
|
|
BBSerializationFlags{ /*.BBName =*/"initial_block",
|
|
/*.InstrFlags =*/
|
|
{
|
|
HasManyUses,
|
|
None,
|
|
None,
|
|
None,
|
|
None,
|
|
None,
|
|
None,
|
|
None,
|
|
} },
|
|
BBSerializationFlags{ /*.BBName =*/"smaller",
|
|
/*.InstrFlags =*/{ None } },
|
|
BBSerializationFlags{
|
|
/*.BBName =*/"greater",
|
|
/*.InstrFlags =*/{ HasSideEffects | AlwaysSerialize, None } },
|
|
BBSerializationFlags{ /*.BBName =*/"end",
|
|
/*.InstrFlags =*/{ AlwaysSerialize } },
|
|
};
|
|
|
|
runTestOnFunctionWithExpected(Body, ExpectedDups, ExpectedFlags);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(SerializePendingInThenBranch) {
|
|
const char *Body = R"LLVM(
|
|
%pointer0 = inttoptr i64 4294967000 to i64*
|
|
%value0 = load i64, i64 *%pointer0
|
|
%pointer1 = inttoptr i64 4294967000 to i64*
|
|
%value1 = load i64, i64 *%pointer1
|
|
%pointer2 = inttoptr i64 4294967200 to i64*
|
|
%value2 = load i64, i64 *%pointer2
|
|
%cmp = icmp ult i64 %value1, %value2
|
|
br i1 %cmp, label %smaller, label %greater
|
|
|
|
smaller:
|
|
store i64 undef, i64 *undef
|
|
br label %end
|
|
|
|
greater:
|
|
br label %end
|
|
|
|
end:
|
|
%constant = add i64 %value0, 0
|
|
unreachable
|
|
)LLVM";
|
|
|
|
ExpectedDuplicatesType ExpectedDups{ 1, 1, 1, 1 };
|
|
|
|
ExpectedFlagsType ExpectedFlags{
|
|
BBSerializationFlags{ /*.BBName =*/"initial_block",
|
|
/*.InstrFlags =*/
|
|
{
|
|
None,
|
|
HasInterferingSideEffects,
|
|
None,
|
|
None,
|
|
None,
|
|
None,
|
|
None,
|
|
None,
|
|
} },
|
|
BBSerializationFlags{
|
|
/*.BBName =*/"smaller",
|
|
/*.InstrFlags =*/{ HasSideEffects | AlwaysSerialize, None } },
|
|
BBSerializationFlags{ /*.BBName =*/"greater",
|
|
/*.InstrFlags =*/{ None } },
|
|
BBSerializationFlags{
|
|
/*.BBName =*/"end",
|
|
/*.InstrFlags =*/{ AlwaysSerialize, AlwaysSerialize } },
|
|
};
|
|
|
|
runTestOnFunctionWithExpected(Body, ExpectedDups, ExpectedFlags);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(SerializePendingInElseBranch) {
|
|
const char *Body = R"LLVM(
|
|
%pointer0 = inttoptr i64 4294967000 to i64*
|
|
%value0 = load i64, i64 *%pointer0
|
|
%pointer1 = inttoptr i64 4294967000 to i64*
|
|
%value1 = load i64, i64 *%pointer1
|
|
%pointer2 = inttoptr i64 4294967200 to i64*
|
|
%value2 = load i64, i64 *%pointer2
|
|
%cmp = icmp ult i64 %value1, %value2
|
|
br i1 %cmp, label %smaller, label %greater
|
|
|
|
smaller:
|
|
br label %end
|
|
|
|
greater:
|
|
store i64 undef, i64 *undef
|
|
br label %end
|
|
|
|
end:
|
|
%constant = add i64 %value0, 0
|
|
unreachable
|
|
)LLVM";
|
|
|
|
ExpectedDuplicatesType ExpectedDups{ 1, 1, 1, 1 };
|
|
|
|
ExpectedFlagsType ExpectedFlags{
|
|
BBSerializationFlags{ /*.BBName =*/"initial_block",
|
|
/*.InstrFlags =*/
|
|
{
|
|
None,
|
|
HasInterferingSideEffects,
|
|
None,
|
|
None,
|
|
None,
|
|
None,
|
|
None,
|
|
None,
|
|
} },
|
|
BBSerializationFlags{ /*.BBName =*/"smaller",
|
|
/*.InstrFlags =*/{ None } },
|
|
BBSerializationFlags{
|
|
/*.BBName =*/"greater",
|
|
/*.InstrFlags =*/{ HasSideEffects | AlwaysSerialize, None } },
|
|
BBSerializationFlags{
|
|
/*.BBName =*/"end",
|
|
/*.InstrFlags =*/{ AlwaysSerialize, AlwaysSerialize } },
|
|
};
|
|
|
|
runTestOnFunctionWithExpected(Body, ExpectedDups, ExpectedFlags);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(Loop) {
|
|
const char *Body = R"LLVM(
|
|
%initptr = inttoptr i64 4294967000 to i64*
|
|
%initval = load i64, i64 *%initptr
|
|
br label %head
|
|
|
|
head:
|
|
%loopingvar = phi i64 [ %initval, %initial_block ], [ %loopval, %tail ]
|
|
br label %tail
|
|
|
|
tail:
|
|
%loopptr = inttoptr i64 4294967200 to i64*
|
|
%loopval = load i64, i64 *%loopptr
|
|
%cmp = icmp ult i64 undef, %loopingvar
|
|
br i1 %cmp, label %head, label %end
|
|
|
|
end:
|
|
unreachable
|
|
)LLVM";
|
|
|
|
ExpectedDuplicatesType ExpectedDups{ 1, 1, 1, 1 };
|
|
|
|
ExpectedFlagsType ExpectedFlags{
|
|
BBSerializationFlags{ /*.BBName =*/"initial_block",
|
|
/*.InstrFlags =*/
|
|
{
|
|
None,
|
|
None,
|
|
None,
|
|
} },
|
|
BBSerializationFlags{ /*.BBName =*/"head",
|
|
/*.InstrFlags =*/{ None, None } },
|
|
BBSerializationFlags{ /*.BBName =*/"tail",
|
|
/*.InstrFlags =*/{ None, None, None, None } },
|
|
BBSerializationFlags{ /*.BBName =*/"end",
|
|
/*.InstrFlags =*/{ AlwaysSerialize } },
|
|
};
|
|
|
|
runTestOnFunctionWithExpected(Body, ExpectedDups, ExpectedFlags);
|
|
}
|