writer/spirv: Fix trailing emission of OpReturn
writer::spirv::Function attempted to append a trailing OpReturn if the
function does not end with a terminating instruction. This wasn't
considering functions that have a non-void return type.
This has now been moved to spirv::Builder::GenerateFunction(),
where we can actually examine the function return type, and generate a
zero-expression to return if we need to.
Note: this was masked by WGSL validation that required all functions to
end with a return statement.
Bug: tint:1302
Change-Id: Iddfeda25a956622c318b8235dc6fc093a2a5c26d
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/71604
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: David Neto <dneto@google.com>
diff --git a/src/writer/spirv/builder.cc b/src/writer/spirv/builder.cc
index 1bbb2b6..ea82524 100644
--- a/src/writer/spirv/builder.cc
+++ b/src/writer/spirv/builder.cc
@@ -653,6 +653,15 @@
}
}
+ if (!LastIsTerminator(func_ast->body)) {
+ if (func->ReturnType()->Is<sem::Void>()) {
+ 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 2e154fb..75f90e0 100644
--- a/src/writer/spirv/builder_accessor_expression_test.cc
+++ b/src/writer/spirv/builder_accessor_expression_test.cc
@@ -787,6 +787,7 @@
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 @@
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 @@
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 @@
%20 = OpLoad %18 %16
%22 = OpAccessChain %21 %13 %20
%23 = OpLoad %6 %22
+OpReturn
)");
Validate(b);
@@ -1031,6 +1035,7 @@
%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 24035d9..ba9d852 100644
--- a/src/writer/spirv/builder_call_test.cc
+++ b/src/writer/spirv/builder_call_test.cc
@@ -29,23 +29,15 @@
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 @@
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 1206347..d47fe24 100644
--- a/src/writer/spirv/builder_if_test.cc
+++ b/src/writer/spirv/builder_if_test.cc
@@ -452,26 +452,24 @@
// if (true) {
// return;
// }
- auto* if_body = Block(Return());
- auto* expr =
- create<ast::IfStatement>(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
-%3 = OpLabel
+%7 = OpLabel
+OpReturn
)");
}
@@ -480,24 +478,28 @@
// 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 @@
// }
// }
// 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 @@
// }
auto* var = Global("a", ty.bool_(), ast::StorageClass::kPrivate);
-
- auto* expr =
- create<ast::IfStatement>(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 f7c068d..490eb04 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 @@
using IntrinsicBoolTest = IntrinsicBuilderTestWithParam<IntrinsicData>;
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<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"(%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 @@
using IntrinsicFloatTest = IntrinsicBuilderTestWithParam<IntrinsicData>;
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<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), 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 @@
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<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), 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(b.GenerateCallExpression(expr), 9u) << 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<f32>(), 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();
+
auto got = DumpBuilder(b);
EXPECT_EQ(got, R"(%12 = OpExtInstImport "GLSL.std.450"
OpName %1 "v"
@@ -253,19 +277,17 @@
TEST_F(IntrinsicBuilderTest, IsNormal_Vector) {
auto* var = Global("v", ty.vec2<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(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 @@
using IntrinsicIntTest = IntrinsicBuilderTestWithParam<IntrinsicData>;
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<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), 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<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), 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 @@
TEST_F(IntrinsicBuilderTest, Call_Dot_F32) {
auto* var = Global("v", ty.vec3<f32>(), 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<u32>(), 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<i32>(), 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<IntrinsicData>;
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::StageDecoration>(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<f32>(), ast::StorageClass::kPrivate);
-
auto* expr = Call(param.name, "v");
- Func("func", {}, ty.void_(), {CallStmt(expr)},
- {create<ast::StageDecoration>(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 @@
%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 @@
auto* bool_v3 =
Global("bool_v3", ty.vec3<bool>(), 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 @@
%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_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 @@
IntrinsicBuilderTestWithParam<IntrinsicData>;
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 @@
TEST_P(Intrinsic_Builtin_SingleParam_Float_Test, Call_Vector) {
auto param = GetParam();
-
auto* expr = Call(param.name, vec2<f32>(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 @@
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 @@
TEST_F(IntrinsicBuilderTest, Call_Length_Vector) {
auto* expr = Call("length", vec2<f32>(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 @@
TEST_F(IntrinsicBuilderTest, Call_Normalize) {
auto* expr = Call("normalize", vec2<f32>(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 @@
IntrinsicBuilderTestWithParam<IntrinsicData>;
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 @@
TEST_P(Intrinsic_Builtin_DualParam_Float_Test, Call_Vector) {
auto param = GetParam();
-
auto* expr = Call(param.name, vec2<f32>(1.0f, 1.0f), vec2<f32>(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 @@
TEST_F(IntrinsicBuilderTest, Call_Reflect_Vector) {
auto* expr = Call("reflect", vec2<f32>(1.0f, 1.0f), vec2<f32>(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 @@
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 @@
TEST_F(IntrinsicBuilderTest, Call_Distance_Vector) {
auto* expr = Call("distance", vec2<f32>(1.0f, 1.0f), vec2<f32>(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 @@
TEST_F(IntrinsicBuilderTest, Call_Cross) {
auto* expr =
Call("cross", vec3<f32>(1.0f, 1.0f, 1.0f), vec3<f32>(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 @@
IntrinsicBuilderTestWithParam<IntrinsicData>;
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 @@
TEST_P(Intrinsic_Builtin_ThreeParam_Float_Test, Call_Vector) {
auto param = GetParam();
-
auto* expr = Call(param.name, vec2<f32>(1.0f, 1.0f), vec2<f32>(1.0f, 1.0f),
vec2<f32>(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 @@
TEST_F(IntrinsicBuilderTest, Call_FaceForward_Vector) {
auto* expr = Call("faceForward", vec2<f32>(1.0f, 1.0f), vec2<f32>(1.0f, 1.0f),
vec2<f32>(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 @@
IntrinsicBuilderTestWithParam<IntrinsicData>;
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 @@
TEST_P(Intrinsic_Builtin_SingleParam_Sint_Test, Call_Vector) {
auto param = GetParam();
-
auto* expr = Call(param.name, vec2<i32>(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 @@
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 @@
TEST_F(Intrinsic_Builtin_Abs_Uint_Test, Call_Vector) {
auto* expr = Call("abs", vec2<u32>(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 @@
IntrinsicBuilderTestWithParam<IntrinsicData>;
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 @@
TEST_P(Intrinsic_Builtin_DualParam_SInt_Test, Call_Vector) {
auto param = GetParam();
-
auto* expr = Call(param.name, vec2<i32>(1, 1), vec2<i32>(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 @@
IntrinsicBuilderTestWithParam<IntrinsicData>;
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 @@
TEST_P(Intrinsic_Builtin_DualParam_UInt_Test, Call_Vector) {
auto param = GetParam();
-
auto* expr = Call(param.name, vec2<u32>(1u, 1u), vec2<u32>(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 @@
IntrinsicBuilderTestWithParam<IntrinsicData>;
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 @@
TEST_P(Intrinsic_Builtin_ThreeParam_Sint_Test, Call_Vector) {
auto param = GetParam();
-
auto* expr =
Call(param.name, vec2<i32>(1, 1), vec2<i32>(1, 1), vec2<i32>(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 @@
IntrinsicBuilderTestWithParam<IntrinsicData>;
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 @@
TEST_P(Intrinsic_Builtin_ThreeParam_Uint_Test, Call_Vector) {
auto param = GetParam();
-
auto* expr =
Call(param.name, vec2<u32>(1u, 1u), vec2<u32>(1u, 1u), vec2<u32>(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 @@
TEST_F(IntrinsicBuilderTest, Call_Determinant) {
auto* var = Global("var", ty.mat3x3<f32>(), 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 @@
TEST_F(IntrinsicBuilderTest, Call_Transpose) {
auto* var = Global("var", ty.mat2x3<f32>(), 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 @@
create<ast::BindingDecoration>(1),
create<ast::GroupDecoration>(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 @@
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 @@
create<ast::BindingDecoration>(1),
create<ast::GroupDecoration>(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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
create<ast::GroupDecoration>(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 @@
%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 @@
create<ast::GroupDecoration>(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 @@
%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 @@
create<ast::GroupDecoration>(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 @@
%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 @@
create<ast::GroupDecoration>(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 @@
%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 @@
create<ast::GroupDecoration>(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 @@
%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 @@
create<ast::GroupDecoration>(2),
});
- Func("a_func", ast::VariableList{}, ty.void_(),
+ Func("a_func", {}, ty.void_(),
ast::StatementList{
Decl(Const("u", ty.vec2<u32>(),
Call("atomicCompareExchangeWeak",
@@ -2356,6 +2362,7 @@
%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 @@
bool pack4 = param.name == "pack4x8snorm" || param.name == "pack4x8unorm";
auto* call = pack4 ? Call(param.name, vec4<float>(1.0f, 1.0f, 1.0f, 1.0f))
: Call(param.name, vec2<float>(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 @@
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 @@
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 @@
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_StorageBarrier) {
- Func("f", ast::VariableList{}, ty.void_(),
+ Func("f", {}, ty.void_(),
ast::StatementList{
CallStmt(Call("storageBarrier")),
},
@@ -2547,6 +2546,7 @@
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 @@
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 462ce25..42d7de6 100644
--- a/src/writer/spirv/builder_switch_test.cc
+++ b/src/writer/spirv/builder_switch_test.cc
@@ -60,13 +60,13 @@
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 @@
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 @@
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 @@
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 @@
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::CaseStatement>(ast::CaseSelectorList{}, default_body));
-
- auto* expr = create<ast::SwitchStatement>(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 @@
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 @@
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<ast::CaseStatement>(selector_1, case_1_body));
- cases.push_back(create<ast::CaseStatement>(selector_2, case_2_body));
- cases.push_back(
- create<ast::CaseStatement>(ast::CaseSelectorList{}, default_body));
-
- auto* expr = create<ast::SwitchStatement>(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 @@
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 @@
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<ast::FallthroughStatement>());
-
- 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<ast::CaseStatement>(selector_1, case_1_body));
- cases.push_back(create<ast::CaseStatement>(selector_2, case_2_body));
- cases.push_back(
- create<ast::CaseStatement>(ast::CaseSelectorList{}, default_body));
-
- auto* expr = create<ast::SwitchStatement>(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 @@
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 @@
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<ast::BreakStatement>())),
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 @@
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 5c5c726..01da96c 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 @@
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, {}});
}