diff --git a/src/writer/spirv/builder.cc b/src/writer/spirv/builder.cc index 1bbb2b6ba7..ea82524a1b 100644 --- a/src/writer/spirv/builder.cc +++ b/src/writer/spirv/builder.cc @@ -653,6 +653,15 @@ bool Builder::GenerateFunction(const ast::Function* func_ast) { } } + if (!LastIsTerminator(func_ast->body)) { + if (func->ReturnType()->Is()) { + push_function_inst(spv::Op::OpReturn, {}); + } else { + auto zero = GenerateConstantNullIfNeeded(func->ReturnType()); + push_function_inst(spv::Op::OpReturnValue, {Operand::Int(zero)}); + } + } + if (func_ast->IsEntryPoint()) { if (!GenerateEntryPoint(func_ast, func_id)) { return false; diff --git a/src/writer/spirv/builder_accessor_expression_test.cc b/src/writer/spirv/builder_accessor_expression_test.cc index 2e154fb521..75f90e005b 100644 --- a/src/writer/spirv/builder_accessor_expression_test.cc +++ b/src/writer/spirv/builder_accessor_expression_test.cc @@ -787,6 +787,7 @@ TEST_F(BuilderTest, IndexAccessor_Of_Vec) { EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"()"); EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(%18 = OpCompositeExtract %6 %16 1 +OpReturn )"); Validate(b); @@ -832,6 +833,7 @@ TEST_F(BuilderTest, IndexAccessor_Of_Array_Of_f32) { EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(%18 = OpCompositeExtract %6 %16 2 %20 = OpCompositeExtract %7 %18 1 +OpReturn )"); Validate(b); @@ -931,6 +933,7 @@ TEST_F(BuilderTest, IndexAccessor_Array_Literal) { EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), ""); EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(%15 = OpCompositeExtract %6 %12 2 +OpReturn )"); Validate(b); @@ -979,6 +982,7 @@ TEST_F(BuilderTest, IndexAccessor_Array_Dynamic) { %20 = OpLoad %18 %16 %22 = OpAccessChain %21 %13 %20 %23 = OpLoad %6 %22 +OpReturn )"); Validate(b); @@ -1031,6 +1035,7 @@ TEST_F(BuilderTest, IndexAccessor_Matrix_Dynamic) { %22 = OpLoad %20 %18 %24 = OpAccessChain %23 %15 %22 %25 = OpLoad %6 %24 +OpReturn )"); Validate(b); diff --git a/src/writer/spirv/builder_call_test.cc b/src/writer/spirv/builder_call_test.cc index 24035d9e8f..ba9d852c51 100644 --- a/src/writer/spirv/builder_call_test.cc +++ b/src/writer/spirv/builder_call_test.cc @@ -29,23 +29,15 @@ TEST_F(BuilderTest, Expression_Call) { func_params.push_back(Param("a", ty.f32())); func_params.push_back(Param("b", ty.f32())); - auto* a_func = - Func("a_func", func_params, ty.f32(), - ast::StatementList{Return(Add("a", "b"))}, ast::DecorationList{}); - + auto* a_func = Func("a_func", func_params, ty.f32(), {Return(Add("a", "b"))}); auto* func = - Func("main", {}, ty.void_(), ast::StatementList{}, ast::DecorationList{}); - - auto* expr = Call("a_func", 1.f, 1.f); - - WrapInFunction(expr); + Func("main", {}, ty.void_(), {Assign(Phony(), Call("a_func", 1.f, 1.f))}); spirv::Builder& b = Build(); ASSERT_TRUE(b.GenerateFunction(a_func)) << b.error(); ASSERT_TRUE(b.GenerateFunction(func)) << b.error(); - EXPECT_EQ(b.GenerateCallExpression(expr), 12u) << b.error(); EXPECT_EQ(DumpBuilder(b), R"(OpName %3 "a_func" OpName %4 "a" OpName %5 "b" @@ -75,23 +67,16 @@ TEST_F(BuilderTest, Statement_Call) { func_params.push_back(Param("a", ty.f32())); func_params.push_back(Param("b", ty.f32())); - auto* a_func = - Func("a_func", func_params, ty.f32(), - ast::StatementList{Return(Add("a", "b"))}, ast::DecorationList{}); + auto* a_func = Func("a_func", func_params, ty.f32(), {Return(Add("a", "b"))}); auto* func = - Func("main", {}, ty.void_(), ast::StatementList{}, ast::DecorationList{}); - - auto* expr = CallStmt(Call("a_func", 1.f, 1.f)); - - WrapInFunction(expr); + Func("main", {}, ty.void_(), {CallStmt(Call("a_func", 1.f, 1.f))}); spirv::Builder& b = Build(); ASSERT_TRUE(b.GenerateFunction(a_func)) << b.error(); ASSERT_TRUE(b.GenerateFunction(func)) << b.error(); - EXPECT_TRUE(b.GenerateStatement(expr)) << b.error(); EXPECT_EQ(DumpBuilder(b), R"(OpName %3 "a_func" OpName %4 "a" OpName %5 "b" diff --git a/src/writer/spirv/builder_if_test.cc b/src/writer/spirv/builder_if_test.cc index 12063472c5..d47fe24bbb 100644 --- a/src/writer/spirv/builder_if_test.cc +++ b/src/writer/spirv/builder_if_test.cc @@ -452,26 +452,24 @@ TEST_F(BuilderTest, If_WithReturn) { // if (true) { // return; // } - auto* if_body = Block(Return()); - auto* expr = - create(Expr(true), if_body, ast::ElseStatementList{}); - WrapInFunction(expr); + auto* fn = Func("f", {}, ty.void_(), {If(true, Block(Return()))}); spirv::Builder& b = Build(); - b.push_function(Function{}); - - EXPECT_TRUE(b.GenerateIfStatement(expr)) << b.error(); - EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeBool -%2 = OpConstantTrue %1 + EXPECT_TRUE(b.GenerateFunction(fn)) << b.error(); + EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid +%1 = OpTypeFunction %2 +%5 = OpTypeBool +%6 = OpConstantTrue %5 )"); EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), - R"(OpSelectionMerge %3 None -OpBranchConditional %2 %4 %3 -%4 = OpLabel + R"(OpSelectionMerge %7 None +OpBranchConditional %6 %8 %7 +%8 = OpLabel +OpReturn +%7 = OpLabel OpReturn -%3 = OpLabel )"); } @@ -480,24 +478,28 @@ TEST_F(BuilderTest, If_WithReturnValue) { // return false; // } // return true; - auto* if_body = Block(Return(false)); - auto* expr = If(Expr(true), if_body); - Func("test", {}, ty.bool_(), {expr, Return(true)}, {}); + + auto* fn = Func("f", {}, ty.bool_(), + { + If(true, Block(Return(false))), + Return(true), + }); + spirv::Builder& b = Build(); - b.push_function(Function{}); - - EXPECT_TRUE(b.GenerateIfStatement(expr)) << b.error(); - EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeBool -%2 = OpConstantTrue %1 -%5 = OpConstantFalse %1 + EXPECT_TRUE(b.GenerateFunction(fn)) << b.error(); + EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeBool +%1 = OpTypeFunction %2 +%5 = OpConstantTrue %2 +%8 = OpConstantFalse %2 )"); EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), - R"(OpSelectionMerge %3 None -OpBranchConditional %2 %4 %3 -%4 = OpLabel + R"(OpSelectionMerge %6 None +OpBranchConditional %5 %7 %6 +%7 = OpLabel +OpReturnValue %8 +%6 = OpLabel OpReturnValue %5 -%3 = OpLabel )"); } @@ -512,24 +514,28 @@ TEST_F(BuilderTest, If_WithNestedBlockReturnValue) { // } // } // return true; - auto* if_body = Block(Block(Block(Block(Return(false))))); - auto* expr = If(Expr(true), if_body); - Func("test", {}, ty.bool_(), {expr, Return(true)}, {}); + + auto* fn = Func("f", {}, ty.bool_(), + { + If(true, Block(Block(Block(Block(Return(false)))))), + Return(true), + }); + spirv::Builder& b = Build(); - b.push_function(Function{}); - - EXPECT_TRUE(b.GenerateIfStatement(expr)) << b.error(); - EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeBool -%2 = OpConstantTrue %1 -%5 = OpConstantFalse %1 + EXPECT_TRUE(b.GenerateFunction(fn)) << b.error(); + EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeBool +%1 = OpTypeFunction %2 +%5 = OpConstantTrue %2 +%8 = OpConstantFalse %2 )"); EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), - R"(OpSelectionMerge %3 None -OpBranchConditional %2 %4 %3 -%4 = OpLabel + R"(OpSelectionMerge %6 None +OpBranchConditional %5 %7 %6 +%7 = OpLabel +OpReturnValue %8 +%6 = OpLabel OpReturnValue %5 -%3 = OpLabel )"); } @@ -539,29 +545,27 @@ TEST_F(BuilderTest, If_WithLoad_Bug327) { // } auto* var = Global("a", ty.bool_(), ast::StorageClass::kPrivate); - - auto* expr = - create(Expr("a"), Block(), ast::ElseStatementList{}); - WrapInFunction(expr); + auto* fn = Func("f", {}, ty.void_(), {If("a", Block())}); spirv::Builder& b = Build(); - b.push_function(Function{}); ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error(); - - EXPECT_TRUE(b.GenerateIfStatement(expr)) << b.error(); + EXPECT_TRUE(b.GenerateFunction(fn)) << b.error(); EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeBool %2 = OpTypePointer Private %3 %4 = OpConstantNull %3 %1 = OpVariable %2 Private %4 +%6 = OpTypeVoid +%5 = OpTypeFunction %6 )"); EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), - R"(%5 = OpLoad %3 %1 -OpSelectionMerge %6 None -OpBranchConditional %5 %7 %6 -%7 = OpLabel -OpBranch %6 -%6 = OpLabel + R"(%9 = OpLoad %3 %1 +OpSelectionMerge %10 None +OpBranchConditional %9 %11 %10 +%11 = OpLabel +OpBranch %10 +%10 = OpLabel +OpReturn )"); } diff --git a/src/writer/spirv/builder_intrinsic_test.cc b/src/writer/spirv/builder_intrinsic_test.cc index f7c068d62e..490eb04f16 100644 --- a/src/writer/spirv/builder_intrinsic_test.cc +++ b/src/writer/spirv/builder_intrinsic_test.cc @@ -16,6 +16,7 @@ #include "src/ast/stage_decoration.h" #include "src/ast/struct_block_decoration.h" #include "src/sem/depth_texture_type.h" +#include "src/utils/string.h" #include "src/writer/spirv/spv_dump.h" #include "src/writer/spirv/test_helper.h" @@ -41,53 +42,60 @@ inline std::ostream& operator<<(std::ostream& out, IntrinsicData data) { using IntrinsicBoolTest = IntrinsicBuilderTestWithParam; TEST_P(IntrinsicBoolTest, Call_Bool_Scalar) { auto param = GetParam(); - auto* var = Global("v", ty.bool_(), ast::StorageClass::kPrivate); - auto* expr = Call(param.name, "v"); - WrapInFunction(expr); + auto* func = Func("a_func", {}, ty.void_(), + { + Assign(Phony(), expr), + }); spirv::Builder& b = Build(); - b.push_function(Function{}); ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error(); + ASSERT_TRUE(b.GenerateFunction(func)) << b.error(); - EXPECT_EQ(b.GenerateCallExpression(expr), 6u) << b.error(); EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeBool %2 = OpTypePointer Private %3 %4 = OpConstantNull %3 %1 = OpVariable %2 Private %4 +%6 = OpTypeVoid +%5 = OpTypeFunction %6 )"); // both any and all are 'passthrough' for scalar booleans EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), - "%6 = OpLoad %3 %1\n"); + "%10 = OpLoad %3 %1\nOpReturn\n"); } TEST_P(IntrinsicBoolTest, Call_Bool_Vector) { auto param = GetParam(); - auto* var = Global("v", ty.vec3(), ast::StorageClass::kPrivate); - auto* expr = Call(param.name, "v"); - WrapInFunction(expr); + auto* func = Func("a_func", {}, ty.void_(), + { + Assign(Phony(), expr), + }); spirv::Builder& b = Build(); - b.push_function(Function{}); ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error(); + ASSERT_TRUE(b.GenerateFunction(func)) << b.error(); - EXPECT_EQ(b.GenerateCallExpression(expr), 6u) << b.error(); EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeBool %3 = OpTypeVector %4 3 %2 = OpTypePointer Private %3 %5 = OpConstantNull %3 %1 = OpVariable %2 Private %5 +%7 = OpTypeVoid +%6 = OpTypeFunction %7 )"); - EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), - R"(%7 = OpLoad %3 %1 -%6 = )" + param.op + - " %4 %7\n"); + + auto expected = utils::ReplaceAll(R"(%11 = OpLoad %3 %1 +%10 = ${op} %4 %11 +OpReturn +)", + "${op}", param.op); + EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), expected); } INSTANTIATE_TEST_SUITE_P(IntrinsicBuilderTest, IntrinsicBoolTest, @@ -97,56 +105,66 @@ INSTANTIATE_TEST_SUITE_P(IntrinsicBuilderTest, using IntrinsicFloatTest = IntrinsicBuilderTestWithParam; TEST_P(IntrinsicFloatTest, Call_Float_Scalar) { auto param = GetParam(); - auto* var = Global("v", ty.f32(), ast::StorageClass::kPrivate); - auto* expr = Call(param.name, "v"); - WrapInFunction(expr); + auto* func = Func("a_func", {}, ty.void_(), + { + Assign(Phony(), expr), + }); spirv::Builder& b = Build(); - b.push_function(Function{}); ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error(); + ASSERT_TRUE(b.GenerateFunction(func)) << b.error(); - EXPECT_EQ(b.GenerateCallExpression(expr), 5u) << b.error(); EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32 %2 = OpTypePointer Private %3 %4 = OpConstantNull %3 %1 = OpVariable %2 Private %4 -%6 = OpTypeBool +%6 = OpTypeVoid +%5 = OpTypeFunction %6 +%10 = OpTypeBool )"); - EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), - R"(%7 = OpLoad %3 %1 -%5 = )" + param.op + - " %6 %7\n"); + + auto expected = utils::ReplaceAll(R"(%11 = OpLoad %3 %1 +%9 = ${op} %10 %11 +OpReturn +)", + "${op}", param.op); + EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), expected); } TEST_P(IntrinsicFloatTest, Call_Float_Vector) { auto param = GetParam(); - auto* var = Global("v", ty.vec3(), ast::StorageClass::kPrivate); - auto* expr = Call(param.name, "v"); - WrapInFunction(expr); + auto* func = Func("a_func", {}, ty.void_(), + { + Assign(Phony(), expr), + }); spirv::Builder& b = Build(); - b.push_function(Function{}); ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error(); + ASSERT_TRUE(b.GenerateFunction(func)) << b.error(); - EXPECT_EQ(b.GenerateCallExpression(expr), 6u) << b.error(); EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32 %3 = OpTypeVector %4 3 %2 = OpTypePointer Private %3 %5 = OpConstantNull %3 %1 = OpVariable %2 Private %5 -%8 = OpTypeBool -%7 = OpTypeVector %8 3 +%7 = OpTypeVoid +%6 = OpTypeFunction %7 +%12 = OpTypeBool +%11 = OpTypeVector %12 3 )"); - EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), - R"(%9 = OpLoad %3 %1 -%6 = )" + param.op + - " %7 %9\n"); + + auto expected = utils::ReplaceAll(R"(%13 = OpLoad %3 %1 +%10 = ${op} %11 %13 +OpReturn +)", + "${op}", param.op); + EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), expected); } INSTANTIATE_TEST_SUITE_P(IntrinsicBuilderTest, IntrinsicFloatTest, @@ -155,75 +173,81 @@ INSTANTIATE_TEST_SUITE_P(IntrinsicBuilderTest, TEST_F(IntrinsicBuilderTest, IsFinite_Scalar) { auto* var = Global("v", ty.f32(), ast::StorageClass::kPrivate); - auto* expr = Call("isFinite", "v"); - WrapInFunction(expr); - - spirv::Builder& b = Build(); - - b.push_function(Function{}); - ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error(); - - EXPECT_EQ(b.GenerateCallExpression(expr), 5u) << b.error(); - EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32 -%2 = OpTypePointer Private %3 -%4 = OpConstantNull %3 -%1 = OpVariable %2 Private %4 -%6 = OpTypeBool -)"); - EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), - R"(%7 = OpLoad %3 %1 -%8 = OpIsInf %6 %7 -%9 = OpIsNan %6 %7 -%10 = OpLogicalOr %6 %8 %9 -%5 = OpLogicalNot %6 %10 -)"); -} - -TEST_F(IntrinsicBuilderTest, IsFinite_Vector) { - auto* var = Global("v", ty.vec3(), ast::StorageClass::kPrivate); - - auto* expr = Call("isFinite", "v"); - WrapInFunction(expr); - - spirv::Builder& b = Build(); - - b.push_function(Function{}); - ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error(); - - EXPECT_EQ(b.GenerateCallExpression(expr), 6u) << b.error(); - EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32 -%3 = OpTypeVector %4 3 -%2 = OpTypePointer Private %3 -%5 = OpConstantNull %3 -%1 = OpVariable %2 Private %5 -%8 = OpTypeBool -%7 = OpTypeVector %8 3 -)"); - EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), - R"(%9 = OpLoad %3 %1 -%10 = OpIsInf %7 %9 -%11 = OpIsNan %7 %9 -%12 = OpLogicalOr %7 %10 %11 -%6 = OpLogicalNot %7 %12 -)"); -} - -TEST_F(IntrinsicBuilderTest, IsNormal_Scalar) { - auto* var = Global("v", ty.f32(), ast::StorageClass::kPrivate); - - auto* expr = Call("isNormal", "v"); - WrapInFunction(expr); - - auto* func = Func("a_func", ast::VariableList{}, ty.void_(), - ast::StatementList{}, ast::DecorationList{}); + auto* func = Func("a_func", {}, ty.void_(), + { + Assign(Phony(), expr), + }); + + spirv::Builder& b = Build(); + + ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error(); + ASSERT_TRUE(b.GenerateFunction(func)) << b.error(); + + EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32 +%2 = OpTypePointer Private %3 +%4 = OpConstantNull %3 +%1 = OpVariable %2 Private %4 +%6 = OpTypeVoid +%5 = OpTypeFunction %6 +%10 = OpTypeBool +)"); + EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), + R"(%11 = OpLoad %3 %1 +%12 = OpIsInf %10 %11 +%13 = OpIsNan %10 %11 +%14 = OpLogicalOr %10 %12 %13 +%9 = OpLogicalNot %10 %14 +OpReturn +)"); +} + +TEST_F(IntrinsicBuilderTest, IsFinite_Vector) { + auto* var = Global("v", ty.vec3(), ast::StorageClass::kPrivate); + auto* expr = Call("isFinite", "v"); + auto* func = Func("a_func", {}, ty.void_(), + { + Assign(Phony(), expr), + }); + + spirv::Builder& b = Build(); + + ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error(); + ASSERT_TRUE(b.GenerateFunction(func)) << b.error(); + + EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32 +%3 = OpTypeVector %4 3 +%2 = OpTypePointer Private %3 +%5 = OpConstantNull %3 +%1 = OpVariable %2 Private %5 +%7 = OpTypeVoid +%6 = OpTypeFunction %7 +%12 = OpTypeBool +%11 = OpTypeVector %12 3 +)"); + EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), + R"(%13 = OpLoad %3 %1 +%14 = OpIsInf %11 %13 +%15 = OpIsNan %11 %13 +%16 = OpLogicalOr %11 %14 %15 +%10 = OpLogicalNot %11 %16 +OpReturn +)"); +} + +TEST_F(IntrinsicBuilderTest, IsNormal_Scalar) { + auto* var = Global("v", ty.f32(), ast::StorageClass::kPrivate); + auto* expr = Call("isNormal", "v"); + auto* func = Func("a_func", {}, ty.void_(), + { + Assign(Phony(), expr), + }); spirv::Builder& b = Build(); ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error(); ASSERT_TRUE(b.GenerateFunction(func)) << b.error(); - EXPECT_EQ(b.GenerateCallExpression(expr), 9u) << b.error(); auto got = DumpBuilder(b); EXPECT_EQ(got, R"(%12 = OpExtInstImport "GLSL.std.450" OpName %1 "v" @@ -253,19 +277,17 @@ OpFunctionEnd TEST_F(IntrinsicBuilderTest, IsNormal_Vector) { auto* var = Global("v", ty.vec2(), ast::StorageClass::kPrivate); - auto* expr = Call("isNormal", "v"); - WrapInFunction(expr); - - auto* func = Func("a_func", ast::VariableList{}, ty.void_(), - ast::StatementList{}, ast::DecorationList{}); + auto* func = Func("a_func", {}, ty.void_(), + { + Assign(Phony(), expr), + }); spirv::Builder& b = Build(); ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error(); ASSERT_TRUE(b.GenerateFunction(func)) << b.error(); - EXPECT_EQ(b.GenerateCallExpression(expr), 10u) << b.error(); auto got = DumpBuilder(b); EXPECT_EQ(got, R"(%14 = OpExtInstImport "GLSL.std.450" OpName %1 "v" @@ -302,104 +324,124 @@ OpFunctionEnd using IntrinsicIntTest = IntrinsicBuilderTestWithParam; TEST_P(IntrinsicIntTest, Call_SInt_Scalar) { auto param = GetParam(); - auto* var = Global("v", ty.i32(), ast::StorageClass::kPrivate); - auto* expr = Call(param.name, "v"); - WrapInFunction(expr); + auto* func = Func("a_func", {}, ty.void_(), + { + Assign(Phony(), expr), + }); spirv::Builder& b = Build(); - b.push_function(Function{}); ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error(); + ASSERT_TRUE(b.GenerateFunction(func)) << b.error(); - EXPECT_EQ(b.GenerateCallExpression(expr), 5u) << b.error(); EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeInt 32 1 %2 = OpTypePointer Private %3 %4 = OpConstantNull %3 %1 = OpVariable %2 Private %4 +%6 = OpTypeVoid +%5 = OpTypeFunction %6 )"); - EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), - R"(%6 = OpLoad %3 %1 -%5 = )" + param.op + - " %3 %6\n"); + + auto expected = utils::ReplaceAll(R"(%10 = OpLoad %3 %1 +%9 = ${op} %3 %10 +OpReturn +)", + "${op}", param.op); + EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), expected); } TEST_P(IntrinsicIntTest, Call_SInt_Vector) { auto param = GetParam(); - auto* var = Global("v", ty.vec3(), ast::StorageClass::kPrivate); - auto* expr = Call(param.name, "v"); - WrapInFunction(expr); + auto* func = Func("a_func", {}, ty.void_(), + { + Assign(Phony(), expr), + }); spirv::Builder& b = Build(); - b.push_function(Function{}); ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error(); + ASSERT_TRUE(b.GenerateFunction(func)) << b.error(); - EXPECT_EQ(b.GenerateCallExpression(expr), 6u) << b.error(); EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeInt 32 1 %3 = OpTypeVector %4 3 %2 = OpTypePointer Private %3 %5 = OpConstantNull %3 %1 = OpVariable %2 Private %5 +%7 = OpTypeVoid +%6 = OpTypeFunction %7 )"); - EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), - R"(%7 = OpLoad %3 %1 -%6 = )" + param.op + - " %3 %7\n"); + + auto expected = utils::ReplaceAll(R"(%11 = OpLoad %3 %1 +%10 = ${op} %3 %11 +OpReturn +)", + "${op}", param.op); + EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), expected); } TEST_P(IntrinsicIntTest, Call_UInt_Scalar) { auto param = GetParam(); - auto* var = Global("v", ty.u32(), ast::StorageClass::kPrivate); - auto* expr = Call(param.name, "v"); - WrapInFunction(expr); + auto* func = Func("a_func", {}, ty.void_(), + { + Assign(Phony(), expr), + }); spirv::Builder& b = Build(); - b.push_function(Function{}); ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error(); + ASSERT_TRUE(b.GenerateFunction(func)) << b.error(); - EXPECT_EQ(b.GenerateCallExpression(expr), 5u) << b.error(); EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeInt 32 0 %2 = OpTypePointer Private %3 %4 = OpConstantNull %3 %1 = OpVariable %2 Private %4 +%6 = OpTypeVoid +%5 = OpTypeFunction %6 )"); - EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), - R"(%6 = OpLoad %3 %1 -%5 = )" + param.op + - " %3 %6\n"); + + auto expected = utils::ReplaceAll(R"(%10 = OpLoad %3 %1 +%9 = ${op} %3 %10 +OpReturn +)", + "${op}", param.op); + EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), expected); } TEST_P(IntrinsicIntTest, Call_UInt_Vector) { auto param = GetParam(); - auto* var = Global("v", ty.vec3(), ast::StorageClass::kPrivate); - auto* expr = Call(param.name, "v"); - WrapInFunction(expr); + auto* func = Func("a_func", {}, ty.void_(), + { + Assign(Phony(), expr), + }); spirv::Builder& b = Build(); - b.push_function(Function{}); ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error(); + ASSERT_TRUE(b.GenerateFunction(func)) << b.error(); - EXPECT_EQ(b.GenerateCallExpression(expr), 6u) << b.error(); EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeInt 32 0 %3 = OpTypeVector %4 3 %2 = OpTypePointer Private %3 %5 = OpConstantNull %3 %1 = OpVariable %2 Private %5 +%7 = OpTypeVoid +%6 = OpTypeFunction %7 )"); - EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), - R"(%7 = OpLoad %3 %1 -%6 = )" + param.op + - " %3 %7\n"); + + auto expected = utils::ReplaceAll(R"(%11 = OpLoad %3 %1 +%10 = ${op} %3 %11 +OpReturn +)", + "${op}", param.op); + EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), expected); } INSTANTIATE_TEST_SUITE_P( IntrinsicBuilderTest, @@ -409,141 +451,151 @@ INSTANTIATE_TEST_SUITE_P( TEST_F(IntrinsicBuilderTest, Call_Dot_F32) { auto* var = Global("v", ty.vec3(), ast::StorageClass::kPrivate); - auto* expr = Call("dot", "v", "v"); - WrapInFunction(expr); + auto* func = Func("a_func", {}, ty.void_(), + { + Assign(Phony(), expr), + }); spirv::Builder& b = Build(); - b.push_function(Function{}); ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error(); + ASSERT_TRUE(b.GenerateFunction(func)) << b.error(); - EXPECT_EQ(b.GenerateCallExpression(expr), 6u) << b.error(); EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32 %3 = OpTypeVector %4 3 %2 = OpTypePointer Private %3 %5 = OpConstantNull %3 %1 = OpVariable %2 Private %5 +%7 = OpTypeVoid +%6 = OpTypeFunction %7 )"); EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), - R"(%7 = OpLoad %3 %1 -%8 = OpLoad %3 %1 -%6 = OpDot %4 %7 %8 + R"(%11 = OpLoad %3 %1 +%12 = OpLoad %3 %1 +%10 = OpDot %4 %11 %12 +OpReturn )"); } TEST_F(IntrinsicBuilderTest, Call_Dot_U32) { auto* var = Global("v", ty.vec3(), ast::StorageClass::kPrivate); - auto* expr = Call("dot", "v", "v"); - WrapInFunction(expr); + auto* func = Func("a_func", {}, ty.void_(), + { + Assign(Phony(), expr), + }); spirv::Builder& b = Build(); - b.push_function(Function{}); ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error(); + ASSERT_TRUE(b.GenerateFunction(func)) << b.error(); - EXPECT_EQ(b.GenerateCallExpression(expr), 6u) << b.error(); EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeInt 32 0 %3 = OpTypeVector %4 3 %2 = OpTypePointer Private %3 %5 = OpConstantNull %3 %1 = OpVariable %2 Private %5 +%7 = OpTypeVoid +%6 = OpTypeFunction %7 )"); EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), - R"(%7 = OpLoad %3 %1 -%8 = OpLoad %3 %1 -%9 = OpCompositeExtract %4 %7 0 -%10 = OpCompositeExtract %4 %8 0 -%11 = OpIMul %4 %9 %10 -%12 = OpCompositeExtract %4 %7 1 -%13 = OpCompositeExtract %4 %8 1 -%14 = OpIMul %4 %12 %13 -%15 = OpIAdd %4 %11 %14 -%16 = OpCompositeExtract %4 %7 2 -%17 = OpCompositeExtract %4 %8 2 + R"(%11 = OpLoad %3 %1 +%12 = OpLoad %3 %1 +%13 = OpCompositeExtract %4 %11 0 +%14 = OpCompositeExtract %4 %12 0 +%15 = OpIMul %4 %13 %14 +%16 = OpCompositeExtract %4 %11 1 +%17 = OpCompositeExtract %4 %12 1 %18 = OpIMul %4 %16 %17 -%6 = OpIAdd %4 %15 %18 +%19 = OpIAdd %4 %15 %18 +%20 = OpCompositeExtract %4 %11 2 +%21 = OpCompositeExtract %4 %12 2 +%22 = OpIMul %4 %20 %21 +%10 = OpIAdd %4 %19 %22 +OpReturn )"); } TEST_F(IntrinsicBuilderTest, Call_Dot_I32) { auto* var = Global("v", ty.vec3(), ast::StorageClass::kPrivate); - auto* expr = Call("dot", "v", "v"); - WrapInFunction(expr); + auto* func = Func("a_func", {}, ty.void_(), + { + Assign(Phony(), expr), + }); spirv::Builder& b = Build(); - b.push_function(Function{}); ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error(); + ASSERT_TRUE(b.GenerateFunction(func)) << b.error(); - EXPECT_EQ(b.GenerateCallExpression(expr), 6u) << b.error(); EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeInt 32 1 %3 = OpTypeVector %4 3 %2 = OpTypePointer Private %3 %5 = OpConstantNull %3 %1 = OpVariable %2 Private %5 +%7 = OpTypeVoid +%6 = OpTypeFunction %7 )"); EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), - R"(%7 = OpLoad %3 %1 -%8 = OpLoad %3 %1 -%9 = OpCompositeExtract %4 %7 0 -%10 = OpCompositeExtract %4 %8 0 -%11 = OpIMul %4 %9 %10 -%12 = OpCompositeExtract %4 %7 1 -%13 = OpCompositeExtract %4 %8 1 -%14 = OpIMul %4 %12 %13 -%15 = OpIAdd %4 %11 %14 -%16 = OpCompositeExtract %4 %7 2 -%17 = OpCompositeExtract %4 %8 2 + R"(%11 = OpLoad %3 %1 +%12 = OpLoad %3 %1 +%13 = OpCompositeExtract %4 %11 0 +%14 = OpCompositeExtract %4 %12 0 +%15 = OpIMul %4 %13 %14 +%16 = OpCompositeExtract %4 %11 1 +%17 = OpCompositeExtract %4 %12 1 %18 = OpIMul %4 %16 %17 -%6 = OpIAdd %4 %15 %18 +%19 = OpIAdd %4 %15 %18 +%20 = OpCompositeExtract %4 %11 2 +%21 = OpCompositeExtract %4 %12 2 +%22 = OpIMul %4 %20 %21 +%10 = OpIAdd %4 %19 %22 +OpReturn )"); } using IntrinsicDeriveTest = IntrinsicBuilderTestWithParam; TEST_P(IntrinsicDeriveTest, Call_Derivative_Scalar) { auto param = GetParam(); - auto* var = Global("v", ty.f32(), ast::StorageClass::kPrivate); - auto* expr = Call(param.name, "v"); - Func("func", {}, ty.void_(), {CallStmt(expr)}, - {create(ast::PipelineStage::kFragment)}); + auto* func = Func("func", {}, ty.void_(), {CallStmt(expr)}, + {Stage(ast::PipelineStage::kFragment)}); spirv::Builder& b = Build(); - b.push_function(Function{}); ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error(); + ASSERT_TRUE(b.GenerateFunction(func)) << b.error(); - EXPECT_EQ(b.GenerateCallExpression(expr), 5u) << b.error(); EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32 %2 = OpTypePointer Private %3 %4 = OpConstantNull %3 %1 = OpVariable %2 Private %4 +%6 = OpTypeVoid +%5 = OpTypeFunction %6 )"); - EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), - R"(%6 = OpLoad %3 %1 -%5 = )" + param.op + - " %3 %6\n"); + + auto expected = utils::ReplaceAll(R"(%10 = OpLoad %3 %1 +%9 = ${op} %3 %10 +OpReturn +)", + "${op}", param.op); + EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), expected); } TEST_P(IntrinsicDeriveTest, Call_Derivative_Vector) { auto param = GetParam(); - auto* var = Global("v", ty.vec3(), ast::StorageClass::kPrivate); - auto* expr = Call(param.name, "v"); - Func("func", {}, ty.void_(), {CallStmt(expr)}, - {create(ast::PipelineStage::kFragment)}); + auto* func = Func("func", {}, ty.void_(), {CallStmt(expr)}, + {Stage(ast::PipelineStage::kFragment)}); spirv::Builder& b = Build(); - b.push_function(Function{}); ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error(); - - EXPECT_EQ(b.GenerateCallExpression(expr), 6u) << b.error(); + ASSERT_TRUE(b.GenerateFunction(func)) << b.error(); if (param.name != "dpdx" && param.name != "dpdy" && param.name != "fwidth") { EXPECT_EQ(DumpInstructions(b.capabilities()), @@ -556,11 +608,16 @@ TEST_P(IntrinsicDeriveTest, Call_Derivative_Vector) { %2 = OpTypePointer Private %3 %5 = OpConstantNull %3 %1 = OpVariable %2 Private %5 +%7 = OpTypeVoid +%6 = OpTypeFunction %7 )"); - EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), - R"(%7 = OpLoad %3 %1 -%6 = )" + param.op + - " %3 %7\n"); + + auto expected = utils::ReplaceAll(R"(%11 = OpLoad %3 %1 +%10 = ${op} %3 %11 +OpReturn +)", + "${op}", param.op); + EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), expected); } INSTANTIATE_TEST_SUITE_P( IntrinsicBuilderTest, @@ -580,17 +637,17 @@ TEST_F(IntrinsicBuilderTest, Call_Select) { auto* bool_v3 = Global("bool_v3", ty.vec3(), ast::StorageClass::kPrivate); - auto* expr = Call("select", "v3", "v3", "bool_v3"); - WrapInFunction(expr); + auto* func = Func("a_func", {}, ty.void_(), + { + Assign(Phony(), expr), + }); spirv::Builder& b = Build(); - b.push_function(Function{}); ASSERT_TRUE(b.GenerateGlobalVariable(v3)) << b.error(); ASSERT_TRUE(b.GenerateGlobalVariable(bool_v3)) << b.error(); - - EXPECT_EQ(b.GenerateCallExpression(expr), 11u) << b.error(); + ASSERT_TRUE(b.GenerateFunction(func)) << b.error(); EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32 %3 = OpTypeVector %4 3 @@ -602,12 +659,15 @@ TEST_F(IntrinsicBuilderTest, Call_Select) { %7 = OpTypePointer Private %8 %10 = OpConstantNull %8 %6 = OpVariable %7 Private %10 +%12 = OpTypeVoid +%11 = OpTypeFunction %12 )"); EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), - R"(%12 = OpLoad %8 %6 -%13 = OpLoad %3 %1 -%14 = OpLoad %3 %1 -%11 = OpSelect %3 %12 %13 %14 + R"(%16 = OpLoad %8 %6 +%17 = OpLoad %3 %1 +%18 = OpLoad %3 %1 +%15 = OpSelect %3 %16 %17 %18 +OpReturn )"); } @@ -674,19 +734,17 @@ TEST_F(IntrinsicBuilderTest, Call_TextureSampleCompare_Twice) { TEST_F(IntrinsicBuilderTest, Call_GLSLMethod_WithLoad) { auto* var = Global("ident", ty.f32(), ast::StorageClass::kPrivate); - auto* expr = Call("round", "ident"); - WrapInFunction(expr); - - auto* func = Func("a_func", ast::VariableList{}, ty.void_(), - ast::StatementList{}, ast::DecorationList{}); + auto* func = Func("a_func", {}, ty.void_(), + { + Assign(Phony(), expr), + }); spirv::Builder& b = Build(); ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error(); ASSERT_TRUE(b.GenerateFunction(func)) << b.error(); - EXPECT_EQ(b.GenerateCallExpression(expr), 9u) << b.error(); EXPECT_EQ(DumpBuilder(b), R"(%10 = OpExtInstImport "GLSL.std.450" OpName %1 "ident" OpName %7 "a_func" @@ -709,18 +767,16 @@ using Intrinsic_Builtin_SingleParam_Float_Test = IntrinsicBuilderTestWithParam; TEST_P(Intrinsic_Builtin_SingleParam_Float_Test, Call_Scalar) { auto param = GetParam(); - auto* expr = Call(param.name, 1.0f); - WrapInFunction(expr); - - auto* func = Func("a_func", ast::VariableList{}, ty.void_(), - ast::StatementList{}, ast::DecorationList{}); + auto* func = Func("a_func", {}, ty.void_(), + { + Assign(Phony(), expr), + }); spirv::Builder& b = Build(); ASSERT_TRUE(b.GenerateFunction(func)) << b.error(); - EXPECT_EQ(b.GenerateCallExpression(expr), 5u) << b.error(); EXPECT_EQ(DumpBuilder(b), R"(%7 = OpExtInstImport "GLSL.std.450" OpName %3 "a_func" %2 = OpTypeVoid @@ -738,18 +794,16 @@ OpFunctionEnd TEST_P(Intrinsic_Builtin_SingleParam_Float_Test, Call_Vector) { auto param = GetParam(); - auto* expr = Call(param.name, vec2(1.0f, 1.0f)); - WrapInFunction(expr); - - auto* func = Func("a_func", ast::VariableList{}, ty.void_(), - ast::StatementList{}, ast::DecorationList{}); + auto* func = Func("a_func", {}, ty.void_(), + { + Assign(Phony(), expr), + }); spirv::Builder& b = Build(); ASSERT_TRUE(b.GenerateFunction(func)) << b.error(); - EXPECT_EQ(b.GenerateCallExpression(expr), 5u) << b.error(); EXPECT_EQ(DumpBuilder(b), R"(%8 = OpExtInstImport "GLSL.std.450" OpName %3 "a_func" %2 = OpTypeVoid @@ -794,17 +848,15 @@ INSTANTIATE_TEST_SUITE_P(IntrinsicBuilderTest, TEST_F(IntrinsicBuilderTest, Call_Length_Scalar) { auto* expr = Call("length", 1.0f); - - WrapInFunction(expr); - - auto* func = Func("a_func", ast::VariableList{}, ty.void_(), - ast::StatementList{}, ast::DecorationList{}); + auto* func = Func("a_func", {}, ty.void_(), + { + Assign(Phony(), expr), + }); spirv::Builder& b = Build(); ASSERT_TRUE(b.GenerateFunction(func)) << b.error(); - EXPECT_EQ(b.GenerateCallExpression(expr), 5u) << b.error(); EXPECT_EQ(DumpBuilder(b), R"(%7 = OpExtInstImport "GLSL.std.450" OpName %3 "a_func" %2 = OpTypeVoid @@ -821,16 +873,15 @@ OpFunctionEnd TEST_F(IntrinsicBuilderTest, Call_Length_Vector) { auto* expr = Call("length", vec2(1.0f, 1.0f)); - WrapInFunction(expr); - - auto* func = Func("a_func", ast::VariableList{}, ty.void_(), - ast::StatementList{}, ast::DecorationList{}); + auto* func = Func("a_func", {}, ty.void_(), + { + Assign(Phony(), expr), + }); spirv::Builder& b = Build(); ASSERT_TRUE(b.GenerateFunction(func)) << b.error(); - EXPECT_EQ(b.GenerateCallExpression(expr), 5u) << b.error(); EXPECT_EQ(DumpBuilder(b), R"(%7 = OpExtInstImport "GLSL.std.450" OpName %3 "a_func" %2 = OpTypeVoid @@ -849,16 +900,15 @@ OpFunctionEnd TEST_F(IntrinsicBuilderTest, Call_Normalize) { auto* expr = Call("normalize", vec2(1.0f, 1.0f)); - WrapInFunction(expr); - - auto* func = Func("a_func", ast::VariableList{}, ty.void_(), - ast::StatementList{}, ast::DecorationList{}); + auto* func = Func("a_func", {}, ty.void_(), + { + Assign(Phony(), expr), + }); spirv::Builder& b = Build(); ASSERT_TRUE(b.GenerateFunction(func)) << b.error(); - EXPECT_EQ(b.GenerateCallExpression(expr), 5u) << b.error(); EXPECT_EQ(DumpBuilder(b), R"(%8 = OpExtInstImport "GLSL.std.450" OpName %3 "a_func" %2 = OpTypeVoid @@ -879,19 +929,16 @@ using Intrinsic_Builtin_DualParam_Float_Test = IntrinsicBuilderTestWithParam; TEST_P(Intrinsic_Builtin_DualParam_Float_Test, Call_Scalar) { auto param = GetParam(); - auto* expr = Call(param.name, 1.0f, 1.0f); - - WrapInFunction(expr); - - auto* func = Func("a_func", ast::VariableList{}, ty.void_(), - ast::StatementList{}, ast::DecorationList{}); + auto* func = Func("a_func", {}, ty.void_(), + { + Assign(Phony(), expr), + }); spirv::Builder& b = Build(); ASSERT_TRUE(b.GenerateFunction(func)) << b.error(); - EXPECT_EQ(b.GenerateCallExpression(expr), 5u) << b.error(); EXPECT_EQ(DumpBuilder(b), R"(%7 = OpExtInstImport "GLSL.std.450" OpName %3 "a_func" %2 = OpTypeVoid @@ -909,19 +956,16 @@ OpFunctionEnd TEST_P(Intrinsic_Builtin_DualParam_Float_Test, Call_Vector) { auto param = GetParam(); - auto* expr = Call(param.name, vec2(1.0f, 1.0f), vec2(1.0f, 1.0f)); - - WrapInFunction(expr); - - auto* func = Func("a_func", ast::VariableList{}, ty.void_(), - ast::StatementList{}, ast::DecorationList{}); + auto* func = Func("a_func", {}, ty.void_(), + { + Assign(Phony(), expr), + }); spirv::Builder& b = Build(); ASSERT_TRUE(b.GenerateFunction(func)) << b.error(); - EXPECT_EQ(b.GenerateCallExpression(expr), 5u) << b.error(); EXPECT_EQ(DumpBuilder(b), R"(%8 = OpExtInstImport "GLSL.std.450" OpName %3 "a_func" %2 = OpTypeVoid @@ -948,17 +992,15 @@ INSTANTIATE_TEST_SUITE_P(IntrinsicBuilderTest, TEST_F(IntrinsicBuilderTest, Call_Reflect_Vector) { auto* expr = Call("reflect", vec2(1.0f, 1.0f), vec2(1.0f, 1.0f)); - - WrapInFunction(expr); - - auto* func = Func("a_func", ast::VariableList{}, ty.void_(), - ast::StatementList{}, ast::DecorationList{}); + auto* func = Func("a_func", {}, ty.void_(), + { + Assign(Phony(), expr), + }); spirv::Builder& b = Build(); ASSERT_TRUE(b.GenerateFunction(func)) << b.error(); - EXPECT_EQ(b.GenerateCallExpression(expr), 5u) << b.error(); EXPECT_EQ(DumpBuilder(b), R"(%8 = OpExtInstImport "GLSL.std.450" OpName %3 "a_func" %2 = OpTypeVoid @@ -977,17 +1019,15 @@ OpFunctionEnd TEST_F(IntrinsicBuilderTest, Call_Distance_Scalar) { auto* expr = Call("distance", 1.0f, 1.0f); - - WrapInFunction(expr); - - auto* func = Func("a_func", ast::VariableList{}, ty.void_(), - ast::StatementList{}, ast::DecorationList{}); + auto* func = Func("a_func", {}, ty.void_(), + { + Assign(Phony(), expr), + }); spirv::Builder& b = Build(); ASSERT_TRUE(b.GenerateFunction(func)) << b.error(); - EXPECT_EQ(b.GenerateCallExpression(expr), 5u) << b.error(); EXPECT_EQ(DumpBuilder(b), R"(%7 = OpExtInstImport "GLSL.std.450" OpName %3 "a_func" %2 = OpTypeVoid @@ -1004,17 +1044,15 @@ OpFunctionEnd TEST_F(IntrinsicBuilderTest, Call_Distance_Vector) { auto* expr = Call("distance", vec2(1.0f, 1.0f), vec2(1.0f, 1.0f)); - - WrapInFunction(expr); - - auto* func = Func("a_func", ast::VariableList{}, ty.void_(), - ast::StatementList{}, ast::DecorationList{}); + auto* func = Func("a_func", {}, ty.void_(), + { + Assign(Phony(), expr), + }); spirv::Builder& b = Build(); ASSERT_TRUE(b.GenerateFunction(func)) << b.error(); - EXPECT_EQ(b.GenerateCallExpression(expr), 5u) << b.error(); EXPECT_EQ(DumpBuilder(b), R"(%7 = OpExtInstImport "GLSL.std.450" OpName %3 "a_func" %2 = OpTypeVoid @@ -1034,17 +1072,15 @@ OpFunctionEnd TEST_F(IntrinsicBuilderTest, Call_Cross) { auto* expr = Call("cross", vec3(1.0f, 1.0f, 1.0f), vec3(1.0f, 1.0f, 1.0f)); - - WrapInFunction(expr); - - auto* func = Func("a_func", ast::VariableList{}, ty.void_(), - ast::StatementList{}, ast::DecorationList{}); + auto* func = Func("a_func", {}, ty.void_(), + { + Assign(Phony(), expr), + }); spirv::Builder& b = Build(); ASSERT_TRUE(b.GenerateFunction(func)) << b.error(); - EXPECT_EQ(b.GenerateCallExpression(expr), 5u) << b.error(); EXPECT_EQ(DumpBuilder(b), R"(%8 = OpExtInstImport "GLSL.std.450" OpName %3 "a_func" %2 = OpTypeVoid @@ -1065,18 +1101,16 @@ using Intrinsic_Builtin_ThreeParam_Float_Test = IntrinsicBuilderTestWithParam; TEST_P(Intrinsic_Builtin_ThreeParam_Float_Test, Call_Scalar) { auto param = GetParam(); - auto* expr = Call(param.name, 1.0f, 1.0f, 1.0f); - WrapInFunction(expr); - - auto* func = Func("a_func", ast::VariableList{}, ty.void_(), - ast::StatementList{}, ast::DecorationList{}); + auto* func = Func("a_func", {}, ty.void_(), + { + Assign(Phony(), expr), + }); spirv::Builder& b = Build(); ASSERT_TRUE(b.GenerateFunction(func)) << b.error(); - EXPECT_EQ(b.GenerateCallExpression(expr), 5u) << b.error(); EXPECT_EQ(DumpBuilder(b), R"(%7 = OpExtInstImport "GLSL.std.450" OpName %3 "a_func" %2 = OpTypeVoid @@ -1094,20 +1128,17 @@ OpFunctionEnd TEST_P(Intrinsic_Builtin_ThreeParam_Float_Test, Call_Vector) { auto param = GetParam(); - auto* expr = Call(param.name, vec2(1.0f, 1.0f), vec2(1.0f, 1.0f), vec2(1.0f, 1.0f)); - - WrapInFunction(expr); - - auto* func = Func("a_func", ast::VariableList{}, ty.void_(), - ast::StatementList{}, ast::DecorationList{}); + auto* func = Func("a_func", {}, ty.void_(), + { + Assign(Phony(), expr), + }); spirv::Builder& b = Build(); ASSERT_TRUE(b.GenerateFunction(func)) << b.error(); - EXPECT_EQ(b.GenerateCallExpression(expr), 5u) << b.error(); EXPECT_EQ(DumpBuilder(b), R"(%8 = OpExtInstImport "GLSL.std.450" OpName %3 "a_func" %2 = OpTypeVoid @@ -1136,17 +1167,15 @@ INSTANTIATE_TEST_SUITE_P(IntrinsicBuilderTest, TEST_F(IntrinsicBuilderTest, Call_FaceForward_Vector) { auto* expr = Call("faceForward", vec2(1.0f, 1.0f), vec2(1.0f, 1.0f), vec2(1.0f, 1.0f)); - - WrapInFunction(expr); - - auto* func = Func("a_func", ast::VariableList{}, ty.void_(), - ast::StatementList{}, ast::DecorationList{}); + auto* func = Func("a_func", {}, ty.void_(), + { + Assign(Phony(), expr), + }); spirv::Builder& b = Build(); ASSERT_TRUE(b.GenerateFunction(func)) << b.error(); - EXPECT_EQ(b.GenerateCallExpression(expr), 5u) << b.error(); EXPECT_EQ(DumpBuilder(b), R"(%8 = OpExtInstImport "GLSL.std.450" OpName %3 "a_func" %2 = OpTypeVoid @@ -1167,18 +1196,16 @@ using Intrinsic_Builtin_SingleParam_Sint_Test = IntrinsicBuilderTestWithParam; TEST_P(Intrinsic_Builtin_SingleParam_Sint_Test, Call_Scalar) { auto param = GetParam(); - auto* expr = Call(param.name, 1); - WrapInFunction(expr); - - auto* func = Func("a_func", ast::VariableList{}, ty.void_(), - ast::StatementList{}, ast::DecorationList{}); + auto* func = Func("a_func", {}, ty.void_(), + { + Assign(Phony(), expr), + }); spirv::Builder& b = Build(); ASSERT_TRUE(b.GenerateFunction(func)) << b.error(); - EXPECT_EQ(b.GenerateCallExpression(expr), 5u) << b.error(); EXPECT_EQ(DumpBuilder(b), R"(%7 = OpExtInstImport "GLSL.std.450" OpName %3 "a_func" %2 = OpTypeVoid @@ -1196,18 +1223,16 @@ OpFunctionEnd TEST_P(Intrinsic_Builtin_SingleParam_Sint_Test, Call_Vector) { auto param = GetParam(); - auto* expr = Call(param.name, vec2(1, 1)); - WrapInFunction(expr); - - auto* func = Func("a_func", ast::VariableList{}, ty.void_(), - ast::StatementList{}, ast::DecorationList{}); + auto* func = Func("a_func", {}, ty.void_(), + { + Assign(Phony(), expr), + }); spirv::Builder& b = Build(); ASSERT_TRUE(b.GenerateFunction(func)) << b.error(); - EXPECT_EQ(b.GenerateCallExpression(expr), 5u) << b.error(); EXPECT_EQ(DumpBuilder(b), R"(%8 = OpExtInstImport "GLSL.std.450" OpName %3 "a_func" %2 = OpTypeVoid @@ -1232,16 +1257,15 @@ INSTANTIATE_TEST_SUITE_P(IntrinsicBuilderTest, using Intrinsic_Builtin_Abs_Uint_Test = IntrinsicBuilderTest; TEST_F(Intrinsic_Builtin_Abs_Uint_Test, Call_Scalar) { auto* expr = Call("abs", 1u); - WrapInFunction(expr); - - auto* func = Func("a_func", ast::VariableList{}, ty.void_(), - ast::StatementList{}, ast::DecorationList{}); + auto* func = Func("a_func", {}, ty.void_(), + { + Assign(Phony(), expr), + }); spirv::Builder& b = Build(); ASSERT_TRUE(b.GenerateFunction(func)) << b.error(); - EXPECT_EQ(b.GenerateCallExpression(expr), 7u) << b.error(); EXPECT_EQ(DumpBuilder(b), R"(OpName %3 "a_func" %2 = OpTypeVoid %1 = OpTypeFunction %2 @@ -1256,16 +1280,15 @@ OpFunctionEnd TEST_F(Intrinsic_Builtin_Abs_Uint_Test, Call_Vector) { auto* expr = Call("abs", vec2(1u, 1u)); - WrapInFunction(expr); - - auto* func = Func("a_func", ast::VariableList{}, ty.void_(), - ast::StatementList{}, ast::DecorationList{}); + auto* func = Func("a_func", {}, ty.void_(), + { + Assign(Phony(), expr), + }); spirv::Builder& b = Build(); ASSERT_TRUE(b.GenerateFunction(func)) << b.error(); - EXPECT_EQ(b.GenerateCallExpression(expr), 9u) << b.error(); EXPECT_EQ(DumpBuilder(b), R"(OpName %3 "a_func" %2 = OpTypeVoid %1 = OpTypeFunction %2 @@ -1284,18 +1307,16 @@ using Intrinsic_Builtin_DualParam_SInt_Test = IntrinsicBuilderTestWithParam; TEST_P(Intrinsic_Builtin_DualParam_SInt_Test, Call_Scalar) { auto param = GetParam(); - auto* expr = Call(param.name, 1, 1); - WrapInFunction(expr); - - auto* func = Func("a_func", ast::VariableList{}, ty.void_(), - ast::StatementList{}, ast::DecorationList{}); + auto* func = Func("a_func", {}, ty.void_(), + { + Assign(Phony(), expr), + }); spirv::Builder& b = Build(); ASSERT_TRUE(b.GenerateFunction(func)) << b.error(); - EXPECT_EQ(b.GenerateCallExpression(expr), 5u) << b.error(); EXPECT_EQ(DumpBuilder(b), R"(%7 = OpExtInstImport "GLSL.std.450" OpName %3 "a_func" %2 = OpTypeVoid @@ -1313,18 +1334,16 @@ OpFunctionEnd TEST_P(Intrinsic_Builtin_DualParam_SInt_Test, Call_Vector) { auto param = GetParam(); - auto* expr = Call(param.name, vec2(1, 1), vec2(1, 1)); - WrapInFunction(expr); - - auto* func = Func("a_func", ast::VariableList{}, ty.void_(), - ast::StatementList{}, ast::DecorationList{}); + auto* func = Func("a_func", {}, ty.void_(), + { + Assign(Phony(), expr), + }); spirv::Builder& b = Build(); ASSERT_TRUE(b.GenerateFunction(func)) << b.error(); - EXPECT_EQ(b.GenerateCallExpression(expr), 5u) << b.error(); EXPECT_EQ(DumpBuilder(b), R"(%8 = OpExtInstImport "GLSL.std.450" OpName %3 "a_func" %2 = OpTypeVoid @@ -1350,18 +1369,16 @@ using Intrinsic_Builtin_DualParam_UInt_Test = IntrinsicBuilderTestWithParam; TEST_P(Intrinsic_Builtin_DualParam_UInt_Test, Call_Scalar) { auto param = GetParam(); - auto* expr = Call(param.name, 1u, 1u); - WrapInFunction(expr); - - auto* func = Func("a_func", ast::VariableList{}, ty.void_(), - ast::StatementList{}, ast::DecorationList{}); + auto* func = Func("a_func", {}, ty.void_(), + { + Assign(Phony(), expr), + }); spirv::Builder& b = Build(); ASSERT_TRUE(b.GenerateFunction(func)) << b.error(); - EXPECT_EQ(b.GenerateCallExpression(expr), 5u) << b.error(); EXPECT_EQ(DumpBuilder(b), R"(%7 = OpExtInstImport "GLSL.std.450" OpName %3 "a_func" %2 = OpTypeVoid @@ -1379,18 +1396,16 @@ OpFunctionEnd TEST_P(Intrinsic_Builtin_DualParam_UInt_Test, Call_Vector) { auto param = GetParam(); - auto* expr = Call(param.name, vec2(1u, 1u), vec2(1u, 1u)); - WrapInFunction(expr); - - auto* func = Func("a_func", ast::VariableList{}, ty.void_(), - ast::StatementList{}, ast::DecorationList{}); + auto* func = Func("a_func", {}, ty.void_(), + { + Assign(Phony(), expr), + }); spirv::Builder& b = Build(); ASSERT_TRUE(b.GenerateFunction(func)) << b.error(); - EXPECT_EQ(b.GenerateCallExpression(expr), 5u) << b.error(); EXPECT_EQ(DumpBuilder(b), R"(%8 = OpExtInstImport "GLSL.std.450" OpName %3 "a_func" %2 = OpTypeVoid @@ -1416,18 +1431,16 @@ using Intrinsic_Builtin_ThreeParam_Sint_Test = IntrinsicBuilderTestWithParam; TEST_P(Intrinsic_Builtin_ThreeParam_Sint_Test, Call_Scalar) { auto param = GetParam(); - auto* expr = Call(param.name, 1, 1, 1); - WrapInFunction(expr); - - auto* func = Func("a_func", ast::VariableList{}, ty.void_(), - ast::StatementList{}, ast::DecorationList{}); + auto* func = Func("a_func", {}, ty.void_(), + { + Assign(Phony(), expr), + }); spirv::Builder& b = Build(); ASSERT_TRUE(b.GenerateFunction(func)) << b.error(); - EXPECT_EQ(b.GenerateCallExpression(expr), 5u) << b.error(); EXPECT_EQ(DumpBuilder(b), R"(%7 = OpExtInstImport "GLSL.std.450" OpName %3 "a_func" %2 = OpTypeVoid @@ -1445,20 +1458,17 @@ OpFunctionEnd TEST_P(Intrinsic_Builtin_ThreeParam_Sint_Test, Call_Vector) { auto param = GetParam(); - auto* expr = Call(param.name, vec2(1, 1), vec2(1, 1), vec2(1, 1)); - - WrapInFunction(expr); - - auto* func = Func("a_func", ast::VariableList{}, ty.void_(), - ast::StatementList{}, ast::DecorationList{}); + auto* func = Func("a_func", {}, ty.void_(), + { + Assign(Phony(), expr), + }); spirv::Builder& b = Build(); ASSERT_TRUE(b.GenerateFunction(func)) << b.error(); - EXPECT_EQ(b.GenerateCallExpression(expr), 5u) << b.error(); EXPECT_EQ(DumpBuilder(b), R"(%8 = OpExtInstImport "GLSL.std.450" OpName %3 "a_func" %2 = OpTypeVoid @@ -1483,18 +1493,16 @@ using Intrinsic_Builtin_ThreeParam_Uint_Test = IntrinsicBuilderTestWithParam; TEST_P(Intrinsic_Builtin_ThreeParam_Uint_Test, Call_Scalar) { auto param = GetParam(); - auto* expr = Call(param.name, 1u, 1u, 1u); - WrapInFunction(expr); - - auto* func = Func("a_func", ast::VariableList{}, ty.void_(), - ast::StatementList{}, ast::DecorationList{}); + auto* func = Func("a_func", {}, ty.void_(), + { + Assign(Phony(), expr), + }); spirv::Builder& b = Build(); ASSERT_TRUE(b.GenerateFunction(func)) << b.error(); - EXPECT_EQ(b.GenerateCallExpression(expr), 5u) << b.error(); EXPECT_EQ(DumpBuilder(b), R"(%7 = OpExtInstImport "GLSL.std.450" OpName %3 "a_func" %2 = OpTypeVoid @@ -1512,20 +1520,17 @@ OpFunctionEnd TEST_P(Intrinsic_Builtin_ThreeParam_Uint_Test, Call_Vector) { auto param = GetParam(); - auto* expr = Call(param.name, vec2(1u, 1u), vec2(1u, 1u), vec2(1u, 1u)); - - WrapInFunction(expr); - - auto* func = Func("a_func", ast::VariableList{}, ty.void_(), - ast::StatementList{}, ast::DecorationList{}); + auto* func = Func("a_func", {}, ty.void_(), + { + Assign(Phony(), expr), + }); spirv::Builder& b = Build(); ASSERT_TRUE(b.GenerateFunction(func)) << b.error(); - EXPECT_EQ(b.GenerateCallExpression(expr), 5u) << b.error(); EXPECT_EQ(DumpBuilder(b), R"(%8 = OpExtInstImport "GLSL.std.450" OpName %3 "a_func" %2 = OpTypeVoid @@ -1628,35 +1633,32 @@ OpFunctionEnd TEST_F(IntrinsicBuilderTest, Call_Determinant) { auto* var = Global("var", ty.mat3x3(), ast::StorageClass::kPrivate); - auto* expr = Call("determinant", "var"); - WrapInFunction(expr); - - auto* func = Func("a_func", ast::VariableList{}, ty.void_(), - ast::StatementList{}, ast::DecorationList{}); + auto* func = Func("a_func", {}, ty.void_(), + { + Assign(Phony(), expr), + }); spirv::Builder& b = Build(); + ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error(); ASSERT_TRUE(b.GenerateFunction(func)) << b.error(); - ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error(); - EXPECT_EQ(b.GenerateCallExpression(expr), 11u) << b.error(); - EXPECT_EQ(DumpBuilder(b), R"(%12 = OpExtInstImport "GLSL.std.450" -OpName %3 "a_func" -OpName %5 "var" -%2 = OpTypeVoid -%1 = OpTypeFunction %2 -%9 = OpTypeFloat 32 -%8 = OpTypeVector %9 3 -%7 = OpTypeMatrix %8 3 -%6 = OpTypePointer Private %7 -%10 = OpConstantNull %7 -%5 = OpVariable %6 Private %10 -%3 = OpFunction %2 None %1 -%4 = OpLabel -%13 = OpLoad %7 %5 -%11 = OpExtInst %9 %12 Determinant %13 +OpName %1 "var" +OpName %9 "a_func" +%5 = OpTypeFloat 32 +%4 = OpTypeVector %5 3 +%3 = OpTypeMatrix %4 3 +%2 = OpTypePointer Private %3 +%6 = OpConstantNull %3 +%1 = OpVariable %2 Private %6 +%8 = OpTypeVoid +%7 = OpTypeFunction %8 +%9 = OpFunction %8 None %7 +%10 = OpLabel +%13 = OpLoad %3 %1 +%11 = OpExtInst %5 %12 Determinant %13 OpReturn OpFunctionEnd )"); @@ -1664,35 +1666,32 @@ OpFunctionEnd TEST_F(IntrinsicBuilderTest, Call_Transpose) { auto* var = Global("var", ty.mat2x3(), ast::StorageClass::kPrivate); - auto* expr = Call("transpose", "var"); - WrapInFunction(expr); - - auto* func = Func("a_func", ast::VariableList{}, ty.void_(), - ast::StatementList{}, ast::DecorationList{}); + auto* func = Func("a_func", {}, ty.void_(), + { + Assign(Phony(), expr), + }); spirv::Builder& b = Build(); + ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error(); ASSERT_TRUE(b.GenerateFunction(func)) << b.error(); - ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error(); - EXPECT_EQ(b.GenerateCallExpression(expr), 11u) << b.error(); - - EXPECT_EQ(DumpBuilder(b), R"(OpName %3 "a_func" -OpName %5 "var" -%2 = OpTypeVoid -%1 = OpTypeFunction %2 -%9 = OpTypeFloat 32 -%8 = OpTypeVector %9 3 -%7 = OpTypeMatrix %8 2 -%6 = OpTypePointer Private %7 -%10 = OpConstantNull %7 -%5 = OpVariable %6 Private %10 -%13 = OpTypeVector %9 2 + EXPECT_EQ(DumpBuilder(b), R"(OpName %1 "var" +OpName %9 "a_func" +%5 = OpTypeFloat 32 +%4 = OpTypeVector %5 3 +%3 = OpTypeMatrix %4 2 +%2 = OpTypePointer Private %3 +%6 = OpConstantNull %3 +%1 = OpVariable %2 Private %6 +%8 = OpTypeVoid +%7 = OpTypeFunction %8 +%13 = OpTypeVector %5 2 %12 = OpTypeMatrix %13 3 -%3 = OpFunction %2 None %1 -%4 = OpLabel -%14 = OpLoad %7 %5 +%9 = OpFunction %8 None %7 +%10 = OpLabel +%14 = OpLoad %3 %1 %11 = OpTranspose %12 %14 OpReturn OpFunctionEnd @@ -1707,10 +1706,9 @@ TEST_F(IntrinsicBuilderTest, Call_ArrayLength) { create(1), create(2), }); - auto* expr = Call("arrayLength", AddressOf(MemberAccessor("b", "a"))); - Func("a_func", ast::VariableList{}, ty.void_(), + Func("a_func", {}, ty.void_(), ast::StatementList{ CallStmt(expr), }, @@ -1737,6 +1735,7 @@ TEST_F(IntrinsicBuilderTest, Call_ArrayLength) { EXPECT_EQ(expected_types, got_types); auto* expected_instructions = R"(%10 = OpArrayLength %11 %1 0 +OpReturn )"; auto got_instructions = DumpInstructions(b.functions()[0].instructions()); EXPECT_EQ(expected_instructions, got_instructions); @@ -1756,10 +1755,9 @@ TEST_F(IntrinsicBuilderTest, Call_ArrayLength_OtherMembersInStruct) { create(1), create(2), }); - auto* expr = Call("arrayLength", AddressOf(MemberAccessor("b", "a"))); - Func("a_func", ast::VariableList{}, ty.void_(), + Func("a_func", {}, ty.void_(), ast::StatementList{ CallStmt(expr), }, @@ -1786,6 +1784,7 @@ TEST_F(IntrinsicBuilderTest, Call_ArrayLength_OtherMembersInStruct) { EXPECT_EQ(expected_types, got_types); auto* expected_instructions = R"(%10 = OpArrayLength %11 %1 1 +OpReturn )"; auto got_instructions = DumpInstructions(b.functions()[0].instructions()); EXPECT_EQ(expected_instructions, got_instructions); @@ -1806,7 +1805,7 @@ TEST_F(IntrinsicBuilderTest, Call_ArrayLength_ViaLets) { auto* p2 = Const("p2", nullptr, AddressOf(MemberAccessor(Deref(p), "a"))); auto* expr = Call("arrayLength", p2); - Func("a_func", ast::VariableList{}, ty.void_(), + Func("a_func", {}, ty.void_(), ast::StatementList{ Decl(p), Decl(p2), @@ -1835,6 +1834,7 @@ TEST_F(IntrinsicBuilderTest, Call_ArrayLength_ViaLets) { EXPECT_EQ(expected_types, got_types); auto* expected_instructions = R"(%10 = OpArrayLength %11 %1 0 +OpReturn )"; auto got_instructions = DumpInstructions(b.functions()[0].instructions()); EXPECT_EQ(expected_instructions, got_instructions); @@ -1867,7 +1867,7 @@ TEST_F(IntrinsicBuilderTest, Call_ArrayLength_ViaLets_WithPtrNoise) { auto* p3 = Const("p3", nullptr, AddressOf(MemberAccessor(Deref(p2), "a"))); auto* expr = Call("arrayLength", AddressOf(Deref(p3))); - Func("a_func", ast::VariableList{}, ty.void_(), + Func("a_func", {}, ty.void_(), ast::StatementList{ Decl(p), Decl(p2), @@ -1897,6 +1897,7 @@ TEST_F(IntrinsicBuilderTest, Call_ArrayLength_ViaLets_WithPtrNoise) { EXPECT_EQ(expected_types, got_types); auto* expected_instructions = R"(%10 = OpArrayLength %11 %1 0 +OpReturn )"; auto got_instructions = DumpInstructions(b.functions()[0].instructions()); EXPECT_EQ(expected_instructions, got_instructions); @@ -1928,7 +1929,7 @@ TEST_F(IntrinsicBuilderTest, Call_AtomicLoad) { create(2), }); - Func("a_func", ast::VariableList{}, ty.void_(), + Func("a_func", {}, ty.void_(), ast::StatementList{ Decl(Const("u", ty.u32(), Call("atomicLoad", AddressOf(MemberAccessor("b", "u"))))), @@ -1962,6 +1963,7 @@ TEST_F(IntrinsicBuilderTest, Call_AtomicLoad) { %10 = OpAtomicLoad %4 %15 %11 %12 %19 = OpAccessChain %18 %1 %11 %16 = OpAtomicLoad %5 %19 %11 %12 +OpReturn )"; auto got_instructions = DumpInstructions(b.functions()[0].instructions()); EXPECT_EQ(expected_instructions, got_instructions); @@ -1995,7 +1997,7 @@ TEST_F(IntrinsicBuilderTest, Call_AtomicStore) { create(2), }); - Func("a_func", ast::VariableList{}, ty.void_(), + Func("a_func", {}, ty.void_(), ast::StatementList{ Decl(Var("u", nullptr, Expr(1u))), Decl(Var("i", nullptr, Expr(2))), @@ -2040,6 +2042,7 @@ OpAtomicStore %22 %10 %19 %23 %27 = OpAccessChain %26 %1 %10 %28 = OpLoad %5 %15 OpAtomicStore %27 %10 %19 %28 +OpReturn )"; auto got_instructions = DumpInstructions(b.functions()[0].instructions()); EXPECT_EQ(expected_instructions, got_instructions); @@ -2071,7 +2074,7 @@ TEST_P(Intrinsic_Builtin_AtomicRMW_i32, Test) { create(2), }); - Func("a_func", ast::VariableList{}, ty.void_(), + Func("a_func", {}, ty.void_(), ast::StatementList{ Decl(Var("v", nullptr, Expr(10))), Decl(Const("x", ty.i32(), @@ -2108,6 +2111,7 @@ TEST_P(Intrinsic_Builtin_AtomicRMW_i32, Test) { %20 = OpLoad %4 %10 )"; expected_instructions += "%13 = " + GetParam().op + " %4 %19 %15 %16 %20\n"; + expected_instructions += "OpReturn\n"; auto got_instructions = DumpInstructions(b.functions()[0].instructions()); EXPECT_EQ(expected_instructions, got_instructions); @@ -2148,7 +2152,7 @@ TEST_P(Intrinsic_Builtin_AtomicRMW_u32, Test) { create(2), }); - Func("a_func", ast::VariableList{}, ty.void_(), + Func("a_func", {}, ty.void_(), ast::StatementList{ Decl(Var("v", nullptr, Expr(10u))), Decl(Const("x", ty.u32(), @@ -2184,6 +2188,7 @@ TEST_P(Intrinsic_Builtin_AtomicRMW_u32, Test) { %19 = OpLoad %4 %10 )"; expected_instructions += "%13 = " + GetParam().op + " %4 %18 %14 %15 %19\n"; + expected_instructions += "OpReturn\n"; auto got_instructions = DumpInstructions(b.functions()[0].instructions()); EXPECT_EQ(expected_instructions, got_instructions); @@ -2226,7 +2231,7 @@ TEST_F(IntrinsicBuilderTest, Call_AtomicExchange) { create(2), }); - Func("a_func", ast::VariableList{}, ty.void_(), + Func("a_func", {}, ty.void_(), ast::StatementList{ Decl(Var("u", nullptr, Expr(10u))), Decl(Var("i", nullptr, Expr(10))), @@ -2274,6 +2279,7 @@ OpStore %15 %14 %28 = OpAccessChain %27 %1 %19 %29 = OpLoad %5 %15 %25 = OpAtomicExchange %5 %28 %19 %20 %29 +OpReturn )"; auto got_instructions = DumpInstructions(b.functions()[0].instructions()); EXPECT_EQ(expected_instructions, got_instructions); @@ -2305,7 +2311,7 @@ TEST_F(IntrinsicBuilderTest, Call_AtomicCompareExchangeWeak) { create(2), }); - Func("a_func", ast::VariableList{}, ty.void_(), + Func("a_func", {}, ty.void_(), ast::StatementList{ Decl(Const("u", ty.vec2(), Call("atomicCompareExchangeWeak", @@ -2356,6 +2362,7 @@ TEST_F(IntrinsicBuilderTest, Call_AtomicCompareExchangeWeak) { %31 = OpIEqual %19 %30 %28 %34 = OpSelect %5 %31 %33 %32 %23 = OpCompositeConstruct %24 %30 %34 +OpReturn )"; auto got_instructions = DumpInstructions(b.functions()[0].instructions()); EXPECT_EQ(expected_instructions, got_instructions); @@ -2371,16 +2378,12 @@ TEST_P(Intrinsic_Builtin_DataPacking_Test, Binary) { bool pack4 = param.name == "pack4x8snorm" || param.name == "pack4x8unorm"; auto* call = pack4 ? Call(param.name, vec4(1.0f, 1.0f, 1.0f, 1.0f)) : Call(param.name, vec2(1.0f, 1.0f)); - WrapInFunction(call); - - auto* func = Func("a_func", ast::VariableList{}, ty.void_(), - ast::StatementList{}, ast::DecorationList{}); + auto* func = Func("a_func", {}, ty.void_(), {CallStmt(call)}); spirv::Builder& b = Build(); ASSERT_TRUE(b.GenerateFunction(func)) << b.error(); - EXPECT_EQ(b.GenerateCallExpression(call), 5u) << b.error(); if (pack4) { EXPECT_EQ(DumpBuilder(b), R"(%7 = OpExtInstImport "GLSL.std.450" OpName %3 "a_func" @@ -2433,17 +2436,12 @@ TEST_P(Intrinsic_Builtin_DataUnpacking_Test, Binary) { auto param = GetParam(); bool pack4 = param.name == "unpack4x8snorm" || param.name == "unpack4x8unorm"; - auto* call = Call(param.name, 1u); - WrapInFunction(call); - - auto* func = Func("a_func", ast::VariableList{}, ty.void_(), - ast::StatementList{}, ast::DecorationList{}); + auto* func = Func("a_func", {}, ty.void_(), {CallStmt(Call(param.name, 1u))}); spirv::Builder& b = Build(); ASSERT_TRUE(b.GenerateFunction(func)) << b.error(); - EXPECT_EQ(b.GenerateCallExpression(call), 5u) << b.error(); if (pack4) { EXPECT_EQ(DumpBuilder(b), R"(%8 = OpExtInstImport "GLSL.std.450" OpName %3 "a_func" @@ -2489,7 +2487,7 @@ INSTANTIATE_TEST_SUITE_P( IntrinsicData{"unpack2x16float", "UnpackHalf2x16"})); TEST_F(IntrinsicBuilderTest, Call_WorkgroupBarrier) { - Func("f", ast::VariableList{}, ty.void_(), + Func("f", {}, ty.void_(), ast::StatementList{ CallStmt(Call("workgroupBarrier")), }, @@ -2514,6 +2512,7 @@ TEST_F(IntrinsicBuilderTest, Call_WorkgroupBarrier) { EXPECT_EQ(expected_types, got_types); auto* expected_instructions = R"(OpControlBarrier %7 %7 %8 +OpReturn )"; auto got_instructions = DumpInstructions(b.functions()[0].instructions()); EXPECT_EQ(expected_instructions, got_instructions); @@ -2522,7 +2521,7 @@ TEST_F(IntrinsicBuilderTest, Call_WorkgroupBarrier) { } TEST_F(IntrinsicBuilderTest, Call_StorageBarrier) { - Func("f", ast::VariableList{}, ty.void_(), + Func("f", {}, ty.void_(), ast::StatementList{ CallStmt(Call("storageBarrier")), }, @@ -2547,6 +2546,7 @@ TEST_F(IntrinsicBuilderTest, Call_StorageBarrier) { EXPECT_EQ(expected_types, got_types); auto* expected_instructions = R"(OpControlBarrier %7 %7 %8 +OpReturn )"; auto got_instructions = DumpInstructions(b.functions()[0].instructions()); EXPECT_EQ(expected_instructions, got_instructions); @@ -2585,6 +2585,7 @@ TEST_F(IntrinsicBuilderTest, Call_Ignore) { EXPECT_EQ(expected_types, got_types); auto* expected_instructions = R"(%15 = OpFunctionCall %2 %3 %16 %17 %18 +OpReturn )"; auto got_instructions = DumpInstructions(b.functions()[1].instructions()); EXPECT_EQ(expected_instructions, got_instructions); diff --git a/src/writer/spirv/builder_switch_test.cc b/src/writer/spirv/builder_switch_test.cc index 462ce25563..42d7de6e4c 100644 --- a/src/writer/spirv/builder_switch_test.cc +++ b/src/writer/spirv/builder_switch_test.cc @@ -60,13 +60,13 @@ TEST_F(BuilderTest, Switch_WithCase) { auto* v = Global("v", ty.i32(), ast::StorageClass::kPrivate); auto* a = Global("a", ty.i32(), ast::StorageClass::kPrivate); - auto* expr = Switch("a", /**/ - Case(Expr(1), Block(Assign("v", 1))), - Case(Expr(2), Block(Assign("v", 2))), DefaultCase()); - WrapInFunction(expr); - - auto* func = Func("a_func", {}, ty.void_(), ast::StatementList{}, - ast::DecorationList{}); + auto* func = Func("a_func", {}, ty.void_(), + { + Switch("a", // + Case(Expr(1), Block(Assign("v", 1))), // + Case(Expr(2), Block(Assign("v", 2))), // + DefaultCase()), + }); spirv::Builder& b = Build(); @@ -74,8 +74,6 @@ TEST_F(BuilderTest, Switch_WithCase) { ASSERT_TRUE(b.GenerateGlobalVariable(a)) << b.error(); ASSERT_TRUE(b.GenerateFunction(func)) << b.error(); - EXPECT_TRUE(b.GenerateSwitchStatement(expr)) << b.error(); - EXPECT_EQ(DumpBuilder(b), R"(OpName %1 "v" OpName %5 "a" OpName %8 "a_func" @@ -119,13 +117,13 @@ TEST_F(BuilderTest, Switch_WithCase_Unsigned) { auto* v = Global("v", ty.i32(), ast::StorageClass::kPrivate); auto* a = Global("a", ty.u32(), ast::StorageClass::kPrivate); - auto* expr = Switch("a", Case(Expr(1u), Block(Assign("v", 1))), - Case(Expr(2u), Block(Assign("v", 2))), DefaultCase()); - - WrapInFunction(expr); - - auto* func = Func("a_func", {}, ty.void_(), ast::StatementList{}, - ast::DecorationList{}); + auto* func = Func("a_func", {}, ty.void_(), + { + Switch("a", // + Case(Expr(1u), Block(Assign("v", 1))), // + Case(Expr(2u), Block(Assign("v", 2))), // + DefaultCase()), + }); spirv::Builder& b = Build(); @@ -133,8 +131,6 @@ TEST_F(BuilderTest, Switch_WithCase_Unsigned) { ASSERT_TRUE(b.GenerateGlobalVariable(a)) << b.error(); ASSERT_TRUE(b.GenerateFunction(func)) << b.error(); - EXPECT_TRUE(b.GenerateSwitchStatement(expr)) << b.error(); - EXPECT_EQ(DumpBuilder(b), R"(OpName %1 "v" OpName %5 "a" OpName %11 "a_func" @@ -178,18 +174,11 @@ TEST_F(BuilderTest, Switch_WithDefault) { auto* v = Global("v", ty.i32(), ast::StorageClass::kPrivate); auto* a = Global("a", ty.i32(), ast::StorageClass::kPrivate); - auto* default_body = Block(Assign("v", 1)); - - ast::CaseStatementList cases; - cases.push_back( - create(ast::CaseSelectorList{}, default_body)); - - auto* expr = create(Expr("a"), cases); - - WrapInFunction(expr); - - auto* func = Func("a_func", {}, ty.void_(), ast::StatementList{}, - ast::DecorationList{}); + auto* func = Func("a_func", {}, ty.void_(), + { + Switch("a", // + DefaultCase(Block(Assign("v", 1)))), // + }); spirv::Builder& b = Build(); @@ -197,8 +186,6 @@ TEST_F(BuilderTest, Switch_WithDefault) { ASSERT_TRUE(b.GenerateGlobalVariable(a)) << b.error(); ASSERT_TRUE(b.GenerateFunction(func)) << b.error(); - EXPECT_TRUE(b.GenerateSwitchStatement(expr)) << b.error(); - EXPECT_EQ(DumpBuilder(b), R"(OpName %1 "v" OpName %5 "a" OpName %8 "a_func" @@ -237,31 +224,15 @@ TEST_F(BuilderTest, Switch_WithCaseAndDefault) { auto* v = Global("v", ty.i32(), ast::StorageClass::kPrivate); auto* a = Global("a", ty.i32(), ast::StorageClass::kPrivate); - auto* case_1_body = Block(Assign("v", Expr(1))); - - auto* case_2_body = Block(Assign("v", Expr(2))); - - auto* default_body = Block(Assign("v", Expr(3))); - - ast::CaseSelectorList selector_1; - selector_1.push_back(Expr(1)); - - ast::CaseSelectorList selector_2; - selector_2.push_back(Expr(2)); - selector_2.push_back(Expr(3)); - - ast::CaseStatementList cases; - cases.push_back(create(selector_1, case_1_body)); - cases.push_back(create(selector_2, case_2_body)); - cases.push_back( - create(ast::CaseSelectorList{}, default_body)); - - auto* expr = create(Expr("a"), cases); - - WrapInFunction(expr); - - auto* func = Func("a_func", {}, ty.void_(), ast::StatementList{}, - ast::DecorationList{}); + auto* func = Func("a_func", {}, ty.void_(), + { + Switch(Expr("a"), // + Case(Expr(1), // + Block(Assign("v", 1))), // + Case({Expr(2), Expr(3)}, // + Block(Assign("v", 2))), // + DefaultCase(Block(Assign("v", 3)))), + }); spirv::Builder& b = Build(); @@ -269,8 +240,6 @@ TEST_F(BuilderTest, Switch_WithCaseAndDefault) { ASSERT_TRUE(b.GenerateGlobalVariable(a)) << b.error(); ASSERT_TRUE(b.GenerateFunction(func)) << b.error(); - EXPECT_TRUE(b.GenerateSwitchStatement(expr)) << b.error(); - EXPECT_EQ(DumpBuilder(b), R"(OpName %1 "v" OpName %5 "a" OpName %8 "a_func" @@ -318,31 +287,15 @@ TEST_F(BuilderTest, Switch_CaseWithFallthrough) { auto* v = Global("v", ty.i32(), ast::StorageClass::kPrivate); auto* a = Global("a", ty.i32(), ast::StorageClass::kPrivate); - auto* case_1_body = - Block(Assign("v", Expr(1)), create()); - - auto* case_2_body = Block(Assign("v", Expr(2))); - - auto* default_body = Block(Assign("v", Expr(3))); - - ast::CaseSelectorList selector_1; - selector_1.push_back(Expr(1)); - - ast::CaseSelectorList selector_2; - selector_2.push_back(Expr(2)); - - ast::CaseStatementList cases; - cases.push_back(create(selector_1, case_1_body)); - cases.push_back(create(selector_2, case_2_body)); - cases.push_back( - create(ast::CaseSelectorList{}, default_body)); - - auto* expr = create(Expr("a"), cases); - - WrapInFunction(expr); - - auto* func = Func("a_func", {}, ty.void_(), ast::StatementList{}, - ast::DecorationList{}); + auto* func = Func("a_func", {}, ty.void_(), + { + Switch(Expr("a"), // + Case(Expr(1), // + Block(Assign("v", 1), Fallthrough())), // + Case(Expr(2), // + Block(Assign("v", 2))), // + DefaultCase(Block(Assign("v", 3)))), + }); spirv::Builder& b = Build(); @@ -350,8 +303,6 @@ TEST_F(BuilderTest, Switch_CaseWithFallthrough) { ASSERT_TRUE(b.GenerateGlobalVariable(a)) << b.error(); ASSERT_TRUE(b.GenerateFunction(func)) << b.error(); - EXPECT_TRUE(b.GenerateSwitchStatement(expr)) << b.error(); - EXPECT_EQ(DumpBuilder(b), R"(OpName %1 "v" OpName %5 "a" OpName %8 "a_func" @@ -398,17 +349,16 @@ TEST_F(BuilderTest, Switch_WithNestedBreak) { auto* v = Global("v", ty.i32(), ast::StorageClass::kPrivate); auto* a = Global("a", ty.i32(), ast::StorageClass::kPrivate); - auto* expr = Switch( - "a", /**/ - Case(Expr(1), Block(/**/ + auto* func = Func( + "a_func", {}, ty.void_(), + { + Switch("a", // + Case(Expr(1), // + Block( // If(Expr(true), Block(create())), Assign("v", 1))), - DefaultCase()); - - WrapInFunction(expr); - - auto* func = Func("a_func", {}, ty.void_(), ast::StatementList{}, - ast::DecorationList{}); + DefaultCase()), + }); spirv::Builder& b = Build(); @@ -416,8 +366,6 @@ TEST_F(BuilderTest, Switch_WithNestedBreak) { ASSERT_TRUE(b.GenerateGlobalVariable(a)) << b.error(); ASSERT_TRUE(b.GenerateFunction(func)) << b.error(); - EXPECT_TRUE(b.GenerateSwitchStatement(expr)) << b.error(); - EXPECT_EQ(DumpBuilder(b), R"(OpName %1 "v" OpName %5 "a" OpName %8 "a_func" diff --git a/src/writer/spirv/function.cc b/src/writer/spirv/function.cc index 5c5c726afa..01da96ce9d 100644 --- a/src/writer/spirv/function.cc +++ b/src/writer/spirv/function.cc @@ -17,15 +17,6 @@ namespace tint { namespace writer { namespace spirv { -namespace { - -// Returns true if the given Op is a function terminator -bool OpIsFunctionTerminator(spv::Op op) { - return op == spv::Op::OpReturn || op == spv::Op::OpReturnValue || - op == spv::Op::OpKill; -} - -} // namespace Function::Function() : declaration_(Instruction{spv::Op::OpNop, {}}), @@ -56,17 +47,6 @@ void Function::iterate(std::function cb) const { cb(inst); } - bool needs_terminator = false; - if (instructions_.empty()) { - needs_terminator = true; - } else { - const auto& last = instructions_.back(); - needs_terminator = !OpIsFunctionTerminator(last.opcode()); - } - if (needs_terminator) { - cb(Instruction{spv::Op::OpReturn, {}}); - } - cb(Instruction{spv::Op::OpFunctionEnd, {}}); }