// Copyright Advanced Micro Devices, Inc., or its affiliates. // SPDX-License-Identifier: MIT #include #include #include #include #include #include #include #include #include "CustomMatchers.hpp" #include "CustomSections.hpp" #include "ExpressionMatchers.hpp" #include "TestContext.hpp" #include "TestKernels.hpp" #include #include #include #include #include #include #include #include #include #include using namespace rocRoller; namespace ExpressionTest { TEST_CASE("Expression identical and equivalent", "[expression]") { auto context = TestContext::ForDefaultTarget(); auto a = Expression::literal(1u); auto ap = Expression::literal(1); auto b = Expression::literal(2u); auto zero = Expression::literal(0u); auto rc = std::make_shared( context.get(), Register::Type::Vector, DataType::Int32, 1); rc->allocateNow(); auto rd = std::make_shared( context.get(), Register::Type::Vector, DataType::Float, 1); rd->allocateNow(); auto c = rc->expression(); auto d = rd->expression(); auto cve = std::make_shared(nullptr, DataType::Float, 0); auto cvf = std::make_shared(nullptr, DataType::Float, 8); auto e = std::make_shared(cve); auto f = std::make_shared(cvf); auto expr1 = a + b; auto expr2 = a + b; auto expr3 = a - b; CHECK(identical(expr1, expr2)); CHECK_FALSE(identical(expr1, expr3)); CHECK_FALSE(identical(ap + b, expr3)); CHECK_THAT(expr1, IdenticalTo(expr2)); CHECK_THAT(expr1, !IdenticalTo(expr3)); CHECK_THAT(ap + b, !IdenticalTo(expr3)); CHECK(equivalent(expr1, expr2)); CHECK_FALSE(equivalent(expr1, expr3)); CHECK_FALSE(equivalent(ap + b, expr3)); CHECK_THAT(expr1, EquivalentTo(expr2)); CHECK_THAT(expr1, !EquivalentTo(expr3)); CHECK_THAT(ap + b, !EquivalentTo(expr3)); CHECK_THAT(b + ap, !EquivalentTo(expr3)); auto expr4 = c + convert(DataType::UInt32, d); auto expr5 = c + convert(DataType::UInt32, d) + zero; CHECK_FALSE(identical(expr1, expr4)); CHECK_FALSE(identical(expr4, expr5)); CHECK(identical(expr4, simplify(expr5))); CHECK_THAT(expr1, !IdenticalTo(expr4)); CHECK_THAT(expr4, !IdenticalTo(expr5)); CHECK_THAT(simplify(expr5), IdenticalTo(expr4)); CHECK_FALSE(equivalent(expr1, expr4)); CHECK_FALSE(equivalent(expr4, expr5)); CHECK(equivalent(expr4, simplify(expr5))); auto expr6 = e / f % d; auto expr7 = convert(DataType::Float, a) + f; CHECK_FALSE(identical(expr6, expr7)); CHECK_FALSE(identical(e, f)); CHECK_THAT(expr6, !IdenticalTo(expr7)); CHECK_THAT(e, !IdenticalTo(f)); CHECK(Expression::identical(nullptr, nullptr)); CHECK_FALSE(identical(nullptr, a)); CHECK_FALSE(identical(a, nullptr)); CHECK_THAT(nullptr, IdenticalTo(nullptr)); CHECK_THAT(nullptr, !IdenticalTo(a)); CHECK_THAT(a, !IdenticalTo(nullptr)); CHECK_FALSE(equivalent(expr6, expr7)); CHECK_FALSE(equivalent(e, f)); CHECK_THAT(expr6, !EquivalentTo(expr7)); CHECK_THAT(e, !EquivalentTo(f)); CHECK(Expression::equivalent(nullptr, nullptr)); CHECK_FALSE(equivalent(nullptr, a)); CHECK_FALSE(equivalent(a, nullptr)); // Commutative tests CHECK_FALSE(identical(a + b, b + a)); CHECK_FALSE(identical(a - b, b - a)); CHECK(equivalent(a + b, b + a)); CHECK_FALSE(equivalent(a - b, b - a)); CHECK(equivalent(a * b, b * a)); CHECK_FALSE(equivalent(a / b, b / a)); CHECK_FALSE(equivalent(a % b, b % a)); CHECK_FALSE(equivalent(a << b, b << a)); CHECK_FALSE(equivalent(a >> b, b >> a)); CHECK(equivalent(a & b, b & a)); CHECK(equivalent(a | b, b | a)); CHECK(equivalent(a ^ b, b ^ a)); // Unallocated auto rg = std::make_shared( context.get(), Register::Type::Vector, DataType::Int32, 1); // Unallocated auto rh = std::make_shared( context.get(), Register::Type::Vector, DataType::Int32, 1); CHECK(Expression::identical(rg->expression(), rg->expression())); CHECK_FALSE(Expression::identical(rg->expression(), rh->expression())); CHECK(Expression::equivalent(rg->expression(), rg->expression())); CHECK_FALSE(Expression::equivalent(rg->expression(), rh->expression())); // Null Expression::ExpressionPtr n = nullptr; CHECK_FALSE(Expression::equivalent(n + n, a + n)); CHECK_FALSE(Expression::equivalent(n + n, n + a)); // Test convert to different types should not be identical or equivalent auto convertFloat = Expression::convert(DataType::Float, rc->expression()); auto convertInt64 = Expression::convert(DataType::Int64, rc->expression()); auto convertUInt32 = Expression::convert(DataType::UInt32, rc->expression()); CHECK_FALSE(identical(convertFloat, convertInt64)); CHECK_FALSE(identical(convertFloat, convertUInt32)); CHECK_FALSE(identical(convertInt64, convertUInt32)); CHECK_FALSE(equivalent(convertFloat, convertInt64)); CHECK_FALSE(equivalent(convertFloat, convertUInt32)); CHECK_FALSE(equivalent(convertInt64, convertUInt32)); } TEST_CASE("Expression contains and split", "[expression]") { using Expression::literal; auto context = TestContext::ForDefaultTarget(); auto lit = literal(5); auto reg = [&]() { auto rc = std::make_shared( context.get(), Register::Type::Vector, DataType::Int32, 1); rc->allocateNow(); return rc->expression(); }(); auto commandArg = []() { auto command = std::make_shared(); auto scalar = command->addOperation(Operations::Scalar(DataType::Int64)); auto commandArgPtr = command->allocateArgument(DataType::Int64, scalar, ArgumentType::Value); return commandArgPtr->expression(); }(); auto kernelArg = []() { auto kernelArgPtr = std::make_shared( AssemblyKernelArgument{"arg", DataType::Int32}); return std::make_shared(kernelArgPtr); }(); auto dataFlowTag = std::make_shared( Expression::DataFlowTag{4, Register::Type::Vector, DataType::Int16}); auto waveTile = []() { auto waveTilePtr = std::make_shared(); return std::make_shared(waveTilePtr); }(); SECTION("Simple") { auto expr = reg + commandArg; CHECK(contains(expr)); CHECK_THAT(expr, Contains()); CHECK_FALSE(contains(expr)); CHECK_THAT(expr, !Contains()); CHECK_FALSE(contains(expr)); CHECK_THAT(expr, !Contains()); CHECK(contains(expr)); CHECK_THAT(expr, Contains()); CHECK(contains(expr)); CHECK_THAT(expr, Contains()); CHECK_FALSE(contains(expr)); CHECK_THAT(expr, !Contains()); CHECK_FALSE(contains(expr)); CHECK_THAT(expr, !Contains()); SECTION("Split") { auto [lhs, rhs] = split(expr); CHECK_THAT(lhs, IdenticalTo(reg)); CHECK_THAT(rhs, IdenticalTo(commandArg)); CHECK_THROWS_AS(split(expr), FatalError); } } SECTION("More complex") { auto expr = (reg + commandArg) * -lit; CHECK_THAT(expr, Contains()); CHECK_THAT(expr, !Contains()); CHECK_THAT(expr, Contains()); CHECK_THAT(expr, Contains()); CHECK_THAT(expr, !Contains()); CHECK_THAT(expr, Contains()); CHECK_THAT(expr, Contains()); SECTION("Split") { auto [lhs, rhs] = split(expr); CHECK_THAT(lhs, IdenticalTo(reg + commandArg)); CHECK_THAT(rhs, IdenticalTo(-lit)); CHECK_THROWS_AS(split(expr), FatalError); auto [llhs, lrhs] = split(lhs); CHECK_THAT(llhs, IdenticalTo(reg)); CHECK_THAT(lrhs, IdenticalTo(commandArg)); auto [irhs] = split(rhs); CHECK_THAT(irhs, IdenticalTo(lit)); } } SECTION("Complex") { auto expr = (dataFlowTag & lit << ~kernelArg) < (commandArg ^ lit); CHECK_THAT(expr, !Contains()); CHECK_THAT(expr, Contains()); CHECK_THAT(expr, Contains()); CHECK_THAT(expr, Contains()); CHECK_THAT(expr, Contains()); CHECK_THAT(expr, Contains()); CHECK_THAT(expr, Contains()); CHECK_THAT(expr, Contains()); CHECK_THAT(expr, Contains()); } SECTION("Matrix Multiply") { auto expr = std::make_shared( Expression::MatrixMultiply(waveTile, waveTile, waveTile)); CHECK_THAT(expr, !Contains()); CHECK_THAT(expr, Contains()); CHECK_THAT(expr, Contains()); } SECTION("Ternary") { auto expr = conditional(reg < lit, addShiftL(reg, dataFlowTag + reg, lit), multiplyAdd(reg, lit, dataFlowTag)); CHECK_THAT(expr, !Contains()); CHECK_THAT(expr, !Contains()); CHECK_THAT(expr, Contains()); CHECK_THAT(expr, Contains()); CHECK_THAT(expr, Contains()); CHECK_THAT(expr, Contains()); CHECK_THAT(expr, Contains()); CHECK_THAT(expr, !Contains()); CHECK_THAT(expr, Contains()); CHECK_THAT(expr, Contains()); SECTION("Split") { auto [lhs, r1hs, r2hs] = split(expr); CHECK_THAT(lhs, IdenticalTo(reg < lit)); CHECK_THAT(r1hs, IdenticalTo(addShiftL(reg, dataFlowTag + reg, lit))); CHECK_THAT(r2hs, IdenticalTo(multiplyAdd(reg, lit, dataFlowTag))); CHECK_THROWS_AS(split(expr), FatalError); SECTION("Split <") { auto [compLhs, compRhs] = split(lhs); CHECK_THAT(compLhs, IdenticalTo(reg)); CHECK_THAT(compRhs, IdenticalTo(lit)); } SECTION("Split AddShiftL") { auto [aslLhs, aslR1hs, aslR2hs] = split(r1hs); CHECK_THAT(aslLhs, IdenticalTo(reg)); CHECK_THAT(aslR1hs, IdenticalTo(dataFlowTag + reg)); CHECK_THAT(aslR2hs, IdenticalTo(lit)); } SECTION("Split MultiplyAdd") { auto [fmaLhs, fmaR1hs, fmaR2hs] = split(r2hs); CHECK_THAT(fmaLhs, IdenticalTo(reg)); CHECK_THAT(fmaR1hs, IdenticalTo(lit)); CHECK_THAT(fmaR2hs, IdenticalTo(dataFlowTag)); } } } } }