Handle empty struct declarations with best effort.
This "feature" is a bit icky as we have no useful representation of it, so never emit code which has anything to do with empty structs.
This commit is contained in:
Родитель
52a33bf2a5
Коммит
8538b4c9c0
|
@ -0,0 +1,8 @@
|
|||
void vert_main()
|
||||
{
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
vert_main();
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
#include <metal_stdlib>
|
||||
#include <simd/simd.h>
|
||||
|
||||
using namespace metal;
|
||||
|
||||
vertex void main0()
|
||||
{
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
#version 450
|
||||
|
||||
void main()
|
||||
{
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
; SPIR-V
|
||||
; Version: 1.1
|
||||
; Generator: Google rspirv; 0
|
||||
; Bound: 17
|
||||
; Schema: 0
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Vertex %2 "main"
|
||||
OpExecutionMode %2 OriginUpperLeft
|
||||
OpName %Test "Test"
|
||||
OpName %t "t"
|
||||
OpName %retvar "retvar"
|
||||
OpName %main "main"
|
||||
OpName %retvar_0 "retvar"
|
||||
%void = OpTypeVoid
|
||||
%6 = OpTypeFunction %void
|
||||
%Test = OpTypeStruct
|
||||
%_ptr_Function_Test = OpTypePointer Function %Test
|
||||
%_ptr_Function_void = OpTypePointer Function %void
|
||||
%2 = OpFunction %void None %6
|
||||
%7 = OpLabel
|
||||
%t = OpVariable %_ptr_Function_Test Function
|
||||
%retvar = OpVariable %_ptr_Function_void Function
|
||||
OpBranch %4
|
||||
%4 = OpLabel
|
||||
%13 = OpCompositeConstruct %Test
|
||||
OpStore %t %13
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
%main = OpFunction %void None %6
|
||||
%15 = OpLabel
|
||||
%retvar_0 = OpVariable %_ptr_Function_void Function
|
||||
OpBranch %14
|
||||
%14 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
|
@ -0,0 +1,37 @@
|
|||
; SPIR-V
|
||||
; Version: 1.1
|
||||
; Generator: Google rspirv; 0
|
||||
; Bound: 17
|
||||
; Schema: 0
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Vertex %2 "main"
|
||||
OpExecutionMode %2 OriginUpperLeft
|
||||
OpName %Test "Test"
|
||||
OpName %t "t"
|
||||
OpName %retvar "retvar"
|
||||
OpName %main "main"
|
||||
OpName %retvar_0 "retvar"
|
||||
%void = OpTypeVoid
|
||||
%6 = OpTypeFunction %void
|
||||
%Test = OpTypeStruct
|
||||
%_ptr_Function_Test = OpTypePointer Function %Test
|
||||
%_ptr_Function_void = OpTypePointer Function %void
|
||||
%2 = OpFunction %void None %6
|
||||
%7 = OpLabel
|
||||
%t = OpVariable %_ptr_Function_Test Function
|
||||
%retvar = OpVariable %_ptr_Function_void Function
|
||||
OpBranch %4
|
||||
%4 = OpLabel
|
||||
%13 = OpCompositeConstruct %Test
|
||||
OpStore %t %13
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
%main = OpFunction %void None %6
|
||||
%15 = OpLabel
|
||||
%retvar_0 = OpVariable %_ptr_Function_void Function
|
||||
OpBranch %14
|
||||
%14 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
|
@ -0,0 +1,37 @@
|
|||
; SPIR-V
|
||||
; Version: 1.1
|
||||
; Generator: Google rspirv; 0
|
||||
; Bound: 17
|
||||
; Schema: 0
|
||||
OpCapability Shader
|
||||
%1 = OpExtInstImport "GLSL.std.450"
|
||||
OpMemoryModel Logical GLSL450
|
||||
OpEntryPoint Vertex %2 "main"
|
||||
OpExecutionMode %2 OriginUpperLeft
|
||||
OpName %Test "Test"
|
||||
OpName %t "t"
|
||||
OpName %retvar "retvar"
|
||||
OpName %main "main"
|
||||
OpName %retvar_0 "retvar"
|
||||
%void = OpTypeVoid
|
||||
%6 = OpTypeFunction %void
|
||||
%Test = OpTypeStruct
|
||||
%_ptr_Function_Test = OpTypePointer Function %Test
|
||||
%_ptr_Function_void = OpTypePointer Function %void
|
||||
%2 = OpFunction %void None %6
|
||||
%7 = OpLabel
|
||||
%t = OpVariable %_ptr_Function_Test Function
|
||||
%retvar = OpVariable %_ptr_Function_void Function
|
||||
OpBranch %4
|
||||
%4 = OpLabel
|
||||
%13 = OpCompositeConstruct %Test
|
||||
OpStore %t %13
|
||||
OpReturn
|
||||
OpFunctionEnd
|
||||
%main = OpFunction %void None %6
|
||||
%15 = OpLabel
|
||||
%retvar_0 = OpVariable %_ptr_Function_void Function
|
||||
OpBranch %14
|
||||
%14 = OpLabel
|
||||
OpReturn
|
||||
OpFunctionEnd
|
|
@ -4781,16 +4781,20 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
|
|||
}
|
||||
else
|
||||
{
|
||||
auto lhs = to_expression(ops[0]);
|
||||
auto rhs = to_expression(ops[1]);
|
||||
// Statements to OpStore may be empty if it is a struct with zero members. Just forward the store to /dev/null.
|
||||
if (!rhs.empty())
|
||||
{
|
||||
auto lhs = to_expression(ops[0]);
|
||||
|
||||
// Tries to optimize assignments like "<lhs> = <lhs> op expr".
|
||||
// While this is purely cosmetic, this is important for legacy ESSL where loop
|
||||
// variable increments must be in either i++ or i += const-expr.
|
||||
// Without this, we end up with i = i + 1, which is correct GLSL, but not correct GLES 2.0.
|
||||
if (!optimize_read_modify_write(lhs, rhs))
|
||||
statement(lhs, " = ", rhs, ";");
|
||||
register_write(ops[0]);
|
||||
// Tries to optimize assignments like "<lhs> = <lhs> op expr".
|
||||
// While this is purely cosmetic, this is important for legacy ESSL where loop
|
||||
// variable increments must be in either i++ or i += const-expr.
|
||||
// Without this, we end up with i = i + 1, which is correct GLSL, but not correct GLES 2.0.
|
||||
if (!optimize_read_modify_write(lhs, rhs))
|
||||
statement(lhs, " = ", rhs, ";");
|
||||
register_write(ops[0]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -4908,16 +4912,28 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
|
|||
const auto *elems = &ops[2];
|
||||
length -= 2;
|
||||
|
||||
if (!length)
|
||||
SPIRV_CROSS_THROW("Invalid input to OpCompositeConstruct.");
|
||||
|
||||
bool forward = true;
|
||||
for (uint32_t i = 0; i < length; i++)
|
||||
forward = forward && should_forward(elems[i]);
|
||||
|
||||
auto &in_type = expression_type(elems[0]);
|
||||
auto &out_type = get<SPIRType>(result_type);
|
||||
|
||||
if (!length)
|
||||
{
|
||||
if (out_type.basetype == SPIRType::Struct)
|
||||
{
|
||||
// It is technically allowed to make a blank struct,
|
||||
// but we cannot make a meaningful expression out of it in high level languages,
|
||||
// so make it a blank expression.
|
||||
emit_op(result_type, id, "", forward);
|
||||
break;
|
||||
}
|
||||
else
|
||||
SPIRV_CROSS_THROW("Invalid input to OpCompositeConstruct.");
|
||||
}
|
||||
|
||||
auto &in_type = expression_type(elems[0]);
|
||||
|
||||
// Only splat if we have vector constructors.
|
||||
// Arrays and structs must be initialized properly in full.
|
||||
bool composite = !out_type.array.empty() || out_type.basetype == SPIRType::Struct;
|
||||
|
@ -6880,12 +6896,15 @@ void CompilerGLSL::emit_function(SPIRFunction &func, uint64_t return_flags)
|
|||
// Don't declare variable until first use to declutter the GLSL output quite a lot.
|
||||
// If we don't touch the variable before first branch,
|
||||
// declare it then since we need variable declaration to be in top scope.
|
||||
var.deferred_declaration = true;
|
||||
// Never declare empty structs. They have no meaningful representation.
|
||||
auto &type = get<SPIRType>(var.basetype);
|
||||
bool empty_struct = type.basetype == SPIRType::Struct && type.member_types.empty();
|
||||
var.deferred_declaration = !empty_struct;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// HACK: SPIRV likes to use samplers and images as local variables, but GLSL does not allow this.
|
||||
// HACK: SPIR-V in older glslang output likes to use samplers and images as local variables, but GLSL does not allow this.
|
||||
// For these types (non-lvalue), we enforce forwarding through a shadowed variable.
|
||||
// This means that when we OpStore to these variables, we just write in the expression ID directly.
|
||||
// This breaks any kind of branching, since the variable must be statically assigned.
|
||||
|
|
Загрузка…
Ссылка в новой задаче