/// \file Clift.cpp /// Tests for the Clift Dialect // // This file is distributed under the MIT License. See LICENSE.md for details. // #include #define BOOST_TEST_MODULE Clift bool init_unit_test(); #include "boost/test/unit_test.hpp" #include "mlir/IR/Builders.h" #include "mlir/IR/BuiltinOps.h" #include "mlir/IR/Diagnostics.h" #include "mlir/IR/Verifier.h" #include "mlir/Pass/PassManager.h" #include "mlir/Transforms/Passes.h" #include "revng/UnitTestHelpers/UnitTestHelpers.h" #include "revng-c/mlir/Dialect/Clift/IR/Clift.h" #include "revng-c/mlir/Dialect/Clift/IR/CliftAttributes.h" #include "revng-c/mlir/Dialect/Clift/IR/CliftOps.h" using namespace mlir::clift; class CliftTest { public: CliftTest() : module(mlir::ModuleOp::create(mlir::UnknownLoc::get(&context))), builder(module.getBodyRegion()) { registry.insert(); context.appendDialectRegistry(registry); context.loadAllAvailableDialects(); } void canonicalize() { mlir::PassManager manager(&context); manager.addPass(mlir::createCanonicalizerPass()); BOOST_ASSERT(manager.run(module).succeeded()); } auto getDiagnosticEmitter() { return [&]() { return module.emitError(); }; } protected: mlir::DialectRegistry registry; mlir::MLIRContext context; std::unique_ptr diagnostic; mlir::ModuleOp module; mlir::OpBuilder builder; }; BOOST_FIXTURE_TEST_SUITE(CliftTestSuite, CliftTest) BOOST_AUTO_TEST_CASE(CliftModuleCannotContainExtraneousTypes) { auto cliftModule = builder.create(builder.getUnknownLoc()); builder.createBlock(&cliftModule.getBody()); cliftModule->setAttr("dc", mlir::TypeAttr::get(mlir::IndexType::get(&context))); BOOST_TEST(cliftModule.verify().failed()); } BOOST_AUTO_TEST_CASE(CliftModuleCannotContaintTypesWithSameID) { auto cliftModule = builder.create(builder.getUnknownLoc()); builder.createBlock(&cliftModule.getBody()); auto TrueAttr = mlir::BoolAttr::get(&context, true); auto T1 = mlir::TypeAttr::get(DefinedType::get(&context, StructTypeAttr::get(&context, 1), TrueAttr)); auto T2 = mlir::TypeAttr::get(DefinedType::get(&context, UnionTypeAttr::get(&context, 1), TrueAttr)); cliftModule->setAttr("dc", T1); cliftModule->setAttr("dc2", T2); BOOST_TEST(cliftModule.verify().failed()); } BOOST_AUTO_TEST_CASE(LabelsWithoutGoToMustBeTriviallyDead) { auto label = builder.create(builder.getUnknownLoc()); builder.create(builder.getUnknownLoc(), label); BOOST_ASSERT(not module.getBody()->getOperations().empty()); canonicalize(); BOOST_ASSERT(module.getBody()->getOperations().empty()); } BOOST_AUTO_TEST_CASE(LabelsWithGoToMustBeAlive) { auto label = builder.create(builder.getUnknownLoc()); builder.create(builder.getUnknownLoc(), label); builder.create(builder.getUnknownLoc(), label); BOOST_CHECK(not module.getBody()->getOperations().empty()); canonicalize(); BOOST_TEST(module.getBody()->getOperations().size() == 3); } BOOST_AUTO_TEST_CASE(LabelsWithAGoToWithoutAssignMustFail) { auto label = builder.create(builder.getUnknownLoc()); builder.create(builder.getUnknownLoc(), label); BOOST_TEST(mlir::verify(module).failed()); } BOOST_AUTO_TEST_CASE(UnionAndStructsCantContainThemself) { auto UnionAttrT = UnionTypeAttr::get(builder.getContext(), 0); using DefinedT = DefinedType; auto UnionT = DefinedT::get(builder.getContext(), UnionAttrT, mlir::BoolAttr::get(builder.getContext(), false)); // Just check that you can't make a field out of a forward declared type, a // pointer to the type must be used instead. BOOST_TEST(FieldAttr::verify(getDiagnosticEmitter(), 0, UnionT, "field") .failed()); } BOOST_AUTO_TEST_CASE(UnionAndStructsCantContainFunctions) { auto VoidT = PrimitiveType::getVoid(builder.getContext(), 0); auto FunctionT = DefinedType::get(builder.getContext(), FunctionTypeAttr::get(0, VoidT), mlir::BoolAttr::get(builder.getContext(), false)); BOOST_TEST(FieldAttr::verify(getDiagnosticEmitter(), 0, FunctionT, "field") .failed()); } BOOST_AUTO_TEST_CASE(FunctionTypesCantContainVoidArgs) { auto VoidType = PrimitiveType::getVoid(builder.getContext(), 0); BOOST_TEST(FunctionArgumentAttr::verify(getDiagnosticEmitter(), VoidType, "") .failed()); } BOOST_AUTO_TEST_CASE(FunctionTypesCantContainFunctionTypes) { auto FunctionT = FunctionTypeAttr::get(0, PrimitiveType::getVoid(builder .getContext(), 0)); auto DefinedT = DefinedType::get(builder.getContext(), FunctionT, mlir::BoolAttr::get(builder.getContext(), false)); BOOST_TEST(FunctionTypeAttr::verify(getDiagnosticEmitter(), 1, "", DefinedT, {}) .failed()); } using namespace mlir::clift; BOOST_AUTO_TEST_CASE(PrimitiveTypesDefaultToNonConst) { auto Type = PrimitiveType::get(&context, PrimitiveKind::GenericKind, 4, mlir::BoolAttr::get(&context, false)); BOOST_TEST((Type.isConst() == false)); } BOOST_AUTO_TEST_CASE(CanWalkPointerTypes) { auto Type = PrimitiveType::get(&context, PrimitiveKind::GenericKind, 4, mlir::BoolAttr::get(&context, false)); auto Ptr = PointerType::get(&context, Type, 8, mlir::BoolAttr::get(&context, false)); size_t Count = 0; Ptr.walkSubTypes([&](mlir::Type Underlying) { BOOST_TEST((Underlying == Type)); Count++; }); BOOST_TEST(Count == 1); } BOOST_AUTO_TEST_SUITE_END()