[spirv-reader] Support return, return-value

Bug: tint:3
Change-Id: Iaaf6ace739ac30e7f9f0bd4ddcef209ab1b71ed8
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/22480
Reviewed-by: dan sinclair <dsinclair@google.com>
This commit is contained in:
David Neto 2020-06-02 16:48:27 +00:00 committed by dan sinclair
parent d8613596e2
commit cb48e79fa5
3 changed files with 268 additions and 4 deletions

View File

@ -32,6 +32,7 @@
#include "src/ast/if_statement.h"
#include "src/ast/loop_statement.h"
#include "src/ast/member_accessor_expression.h"
#include "src/ast/return_statement.h"
#include "src/ast/scalar_constructor_expression.h"
#include "src/ast/storage_class.h"
#include "src/ast/switch_statement.h"
@ -1753,9 +1754,23 @@ bool FunctionEmitter::EmitContinuingStart(const Construct* construct) {
return success();
}
bool FunctionEmitter::EmitNormalTerminator(const BlockInfo&) {
// TODO(dneto): emit fallthrough, break, continue, return, kill
return true;
bool FunctionEmitter::EmitNormalTerminator(const BlockInfo& block_info) {
const auto& terminator = *(block_info.basic_block->terminator());
switch (terminator.opcode()) {
case SpvOpReturn:
AddStatement(std::make_unique<ast::ReturnStatement>());
return true;
case SpvOpReturnValue: {
auto value = MakeExpression(terminator.GetSingleWordInOperand(0));
AddStatement(
std::make_unique<ast::ReturnStatement>(std::move(value.expr)));
}
return true;
default:
break;
}
// TODO(dneto): emit fallthrough, break, continue, kill
return success();
}
bool FunctionEmitter::EmitStatementsInBasicBlock(const BlockInfo& block_info,

View File

@ -62,6 +62,8 @@ std::string CommonTypes() {
%uint = OpTypeInt 32 0
%selector = OpConstant %uint 42
%uintfn = OpTypeFunction %uint
%uint_0 = OpConstant %uint 0
%uint_1 = OpConstant %uint 1
%uint_2 = OpConstant %uint 2
@ -6771,6 +6773,7 @@ Else{
{
}
}
Return{}
)"));
}
@ -6820,6 +6823,7 @@ Assignment{
Identifier{var}
ScalarConstructor{999}
}
Return{}
)"));
}
@ -6869,6 +6873,7 @@ Assignment{
Identifier{var}
ScalarConstructor{999}
}
Return{}
)"));
}
@ -6926,6 +6931,7 @@ Assignment{
Identifier{var}
ScalarConstructor{999}
}
Return{}
)"));
}
@ -6994,6 +7000,7 @@ Assignment{
Identifier{var}
ScalarConstructor{999}
}
Return{}
)"));
}
@ -7052,6 +7059,7 @@ Assignment{
Identifier{var}
ScalarConstructor{999}
}
Return{}
)"));
}
@ -7110,6 +7118,7 @@ Assignment{
Identifier{var}
ScalarConstructor{999}
}
Return{}
)"));
}
@ -7223,6 +7232,7 @@ Assignment{
Identifier{var}
ScalarConstructor{999}
}
Return{}
)"));
}
@ -7264,6 +7274,7 @@ Assignment{
Identifier{var}
ScalarConstructor{999}
}
Return{}
)"));
}
@ -7305,6 +7316,7 @@ Assignment{
Identifier{var}
ScalarConstructor{999}
}
Return{}
)"));
}
@ -7345,6 +7357,7 @@ Assignment{
Identifier{var}
ScalarConstructor{999}
}
Return{}
)"));
}
@ -7385,6 +7398,7 @@ Assignment{
Identifier{var}
ScalarConstructor{999}
}
Return{}
)"));
}
@ -7443,6 +7457,7 @@ Assignment{
Identifier{var}
ScalarConstructor{999}
}
Return{}
)")) << ToString(fe.ast_body());
}
@ -7509,6 +7524,7 @@ Assignment{
Identifier{var}
ScalarConstructor{999}
}
Return{}
)")) << ToString(fe.ast_body());
}
@ -7595,6 +7611,7 @@ Assignment{
Identifier{var}
ScalarConstructor{999}
}
Return{}
)")) << ToString(fe.ast_body());
}
@ -7626,6 +7643,224 @@ TEST_F(SpvParserTest, DISABLED_EmitBody_Loop_BodyConditionallyBreaks) {
// TODO(dneto): Needs "break" support
}
TEST_F(SpvParserTest, EmitBody_Return_TopLevel) {
auto* p = parser(test::Assemble(CommonTypes() + R"(
%100 = OpFunction %void None %voidfn
%10 = OpLabel
OpReturn
OpFunctionEnd
)"));
ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
FunctionEmitter fe(p, *spirv_function(100));
EXPECT_TRUE(fe.EmitBody()) << p->error();
EXPECT_THAT(ToString(fe.ast_body()), Eq(R"(Return{}
)")) << ToString(fe.ast_body());
}
TEST_F(SpvParserTest, EmitBody_Return_InsideIf) {
auto* p = parser(test::Assemble(CommonTypes() + R"(
%100 = OpFunction %void None %voidfn
%10 = OpLabel
OpSelectionMerge %99 None
OpBranchConditional %cond %20 %99
%20 = OpLabel
OpReturn
%99 = OpLabel
OpReturn
OpFunctionEnd
)"));
ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
FunctionEmitter fe(p, *spirv_function(100));
EXPECT_TRUE(fe.EmitBody()) << p->error();
EXPECT_THAT(ToString(fe.ast_body()), Eq(R"(If{
(
ScalarConstructor{false}
)
{
Return{}
}
}
Else{
{
}
}
Return{}
)")) << ToString(fe.ast_body());
}
TEST_F(SpvParserTest, EmitBody_Return_InsideLoop) {
auto* p = parser(test::Assemble(CommonTypes() + R"(
%100 = OpFunction %void None %voidfn
%10 = OpLabel
OpBranch %20
%20 = OpLabel
OpLoopMerge %99 %80 None
OpBranchConditional %cond %30 %30
%30 = OpLabel
OpReturn
%80 = OpLabel
OpBranch %20
%99 = OpLabel
OpReturn
OpFunctionEnd
)"));
ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
FunctionEmitter fe(p, *spirv_function(100));
EXPECT_TRUE(fe.EmitBody()) << p->error();
EXPECT_THAT(ToString(fe.ast_body()), Eq(R"(Loop{
Return{}
}
Return{}
)")) << ToString(fe.ast_body());
}
TEST_F(SpvParserTest, EmitBody_ReturnValue_TopLevel) {
auto* p = parser(test::Assemble(CommonTypes() + R"(
%200 = OpFunction %uint None %uintfn
%210 = OpLabel
OpReturnValue %uint_2
OpFunctionEnd
%100 = OpFunction %void None %voidfn
%10 = OpLabel
%11 = OpFunctionCall %uint %200
OpReturn
OpFunctionEnd
)"));
ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
FunctionEmitter fe(p, *spirv_function(200));
EXPECT_TRUE(fe.EmitBody()) << p->error();
EXPECT_THAT(ToString(fe.ast_body()), Eq(R"(Return{
{
ScalarConstructor{2}
}
}
)")) << ToString(fe.ast_body());
}
TEST_F(SpvParserTest, EmitBody_ReturnValue_InsideIf) {
auto* p = parser(test::Assemble(CommonTypes() + R"(
%200 = OpFunction %uint None %uintfn
%210 = OpLabel
OpSelectionMerge %299 None
OpBranchConditional %cond %220 %299
%220 = OpLabel
OpReturnValue %uint_2
%299 = OpLabel
OpReturnValue %uint_3
OpFunctionEnd
%100 = OpFunction %void None %voidfn
%10 = OpLabel
%11 = OpFunctionCall %uint %200
OpReturn
OpFunctionEnd
)"));
ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
FunctionEmitter fe(p, *spirv_function(200));
EXPECT_TRUE(fe.EmitBody()) << p->error();
EXPECT_THAT(ToString(fe.ast_body()), Eq(R"(If{
(
ScalarConstructor{false}
)
{
Return{
{
ScalarConstructor{2}
}
}
}
}
Else{
{
}
}
Return{
{
ScalarConstructor{3}
}
}
)")) << ToString(fe.ast_body());
}
TEST_F(SpvParserTest, EmitBody_ReturnValue_Loop) {
auto* p = parser(test::Assemble(CommonTypes() + R"(
%200 = OpFunction %void None %voidfn
%210 = OpLabel
OpBranch %220
%220 = OpLabel
OpLoopMerge %299 %280 None
OpBranchConditional %cond %230 %230
%230 = OpLabel
OpReturnValue %uint_2
%280 = OpLabel
OpBranch %220
%299 = OpLabel
OpReturnValue %uint_3
OpFunctionEnd
%100 = OpFunction %void None %voidfn
%10 = OpLabel
%11 = OpFunctionCall %uint %200
OpReturn
OpFunctionEnd
)"));
ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
FunctionEmitter fe(p, *spirv_function(200));
EXPECT_TRUE(fe.EmitBody()) << p->error();
EXPECT_THAT(ToString(fe.ast_body()), Eq(R"(Loop{
Return{
{
ScalarConstructor{2}
}
}
}
Return{
{
ScalarConstructor{3}
}
}
)")) << ToString(fe.ast_body());
}
} // namespace
} // namespace spirv
} // namespace reader

View File

@ -107,18 +107,24 @@ TEST_F(SpvParserTest, EmitFunctions_CalleePrecedesCaller) {
EXPECT_TRUE(p->BuildAndParseInternalModule());
EXPECT_TRUE(p->error().empty());
const auto module_ast = p->module().to_str();
// TODO(dneto): This will need to be updated when function calls are
// supported. Otherwise, use more general matching instead of substring
// equality.
EXPECT_THAT(module_ast, HasSubstr(R"(
Function leaf -> __void
()
{
Return{}
}
Function branch -> __void
()
{
Return{}
}
Function root -> __void
()
{
Return{}
})"));
}
@ -138,7 +144,13 @@ TEST_F(SpvParserTest, EmitFunctions_NonVoidResultType) {
Function ret_float -> __f32
()
{
})"));
Return{
{
ScalarConstructor{0.000000}
}
}
})"))
<< module_ast;
}
TEST_F(SpvParserTest, EmitFunctions_MixedParamTypes) {
@ -177,6 +189,7 @@ TEST_F(SpvParserTest, EmitFunctions_MixedParamTypes) {
}
)
{
Return{}
})"));
}
@ -215,6 +228,7 @@ TEST_F(SpvParserTest, EmitFunctions_GenerateParamNames) {
}
)
{
Return{}
})"));
}