X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Fglsl%2Fspirv.cpp;h=2220dcc1f012c00655fb207e841787b76be09238;hb=2016444ee144ce41f88c48e89c825137ad7e4ec2;hp=799e31d6493aa652064bfe06885760a1b2b65dbd;hpb=cc5483cc709fdf7b6966a3e69dabfcafebaaffa0;p=libs%2Fgl.git diff --git a/source/glsl/spirv.cpp b/source/glsl/spirv.cpp index 799e31d6..2220dcc1 100644 --- a/source/glsl/spirv.cpp +++ b/source/glsl/spirv.cpp @@ -141,7 +141,7 @@ void SpirVGenerator::apply(Module &module) i->content.visit(*this); } - writer.finalize(next_id); + writer.finalize(SPIRV_GENERATOR_MSP, next_id); } SpirVGenerator::StorageClass SpirVGenerator::get_interface_storage(const string &iface, bool block) @@ -394,9 +394,12 @@ SpirVGenerator::Id SpirVGenerator::begin_expression(Opcode opcode, Id type_id, u writer.begin_op(content.function_body, opcode, (n_args ? 1+has_result*2+n_args : 0)); } else if(opcode==OP_COMPOSITE_CONSTRUCT) - writer.begin_op(content.function_body, OP_SPEC_CONSTANT_COMPOSITE, (n_args ? 1+has_result*2+n_args : 0)); + writer.begin_op(content.globals, (spec_constant ? OP_SPEC_CONSTANT_COMPOSITE : OP_CONSTANT_COMPOSITE), + (n_args ? 1+has_result*2+n_args : 0)); + else if(!spec_constant) + throw internal_error("invalid non-specialization constant expression"); else - writer.begin_op(content.function_body, OP_SPEC_CONSTANT_OP, (n_args ? 2+has_result*2+n_args : 0)); + writer.begin_op(content.globals, OP_SPEC_CONSTANT_OP, (n_args ? 2+has_result*2+n_args : 0)); Id result_id = next_id++; if(has_result) @@ -404,7 +407,7 @@ SpirVGenerator::Id SpirVGenerator::begin_expression(Opcode opcode, Id type_id, u writer.write(type_id); writer.write(result_id); } - if(constant_expression && opcode!=OP_COMPOSITE_CONSTRUCT) + if(spec_constant && opcode!=OP_COMPOSITE_CONSTRUCT) writer.write(opcode); return result_id; @@ -413,7 +416,7 @@ SpirVGenerator::Id SpirVGenerator::begin_expression(Opcode opcode, Id type_id, u void SpirVGenerator::end_expression(Opcode opcode) { if(constant_expression) - opcode = (opcode==OP_COMPOSITE_CONSTRUCT ? OP_SPEC_CONSTANT_COMPOSITE : OP_SPEC_CONSTANT_OP); + opcode = (opcode==OP_COMPOSITE_CONSTRUCT ? spec_constant ? OP_SPEC_CONSTANT_COMPOSITE : OP_CONSTANT_COMPOSITE : OP_SPEC_CONSTANT_OP); writer.end_op(opcode); } @@ -455,16 +458,6 @@ SpirVGenerator::Id SpirVGenerator::write_construct(Id type_id, const Id *elem_id return result_id; } -BasicTypeDeclaration &SpirVGenerator::get_element_type(BasicTypeDeclaration &basic) -{ - if(basic.kind==BasicTypeDeclaration::BOOL || basic.kind==BasicTypeDeclaration::INT || basic.kind==BasicTypeDeclaration::FLOAT) - return basic; - else if((basic.kind==BasicTypeDeclaration::VECTOR || basic.kind==BasicTypeDeclaration::MATRIX) && basic.base_type) - return get_element_type(dynamic_cast(*basic.base_type)); - else - throw invalid_argument("SpirVGenerator::get_element_type"); -} - void SpirVGenerator::visit(Block &block) { for(NodeList::iterator i=block.body.begin(); i!=block.body.end(); ++i) @@ -478,6 +471,7 @@ void SpirVGenerator::visit(Literal &literal) r_expression_result_id = write_constant(type_id, get_constant_key(type_id, literal.value).int_value, true); else r_expression_result_id = get_constant_id(type_id, literal.value); + r_constant_result = true; } void SpirVGenerator::visit(VariableReference &var) @@ -488,11 +482,13 @@ void SpirVGenerator::visit(VariableReference &var) throw internal_error("reference to non-constant variable in constant context"); r_expression_result_id = get_id(*var.declaration); + r_constant_result = true; return; } else if(!current_function) throw internal_error("non-constant context outside a function"); + r_constant_result = false; if(composite_access) { r_composite_base = var.declaration; @@ -515,6 +511,7 @@ void SpirVGenerator::visit(InterfaceBlockReference &iface) r_composite_base = iface.declaration; r_expression_result_id = 0; + r_constant_result = false; } void SpirVGenerator::generate_composite_access(TypeDeclaration &result_type) @@ -560,6 +557,7 @@ void SpirVGenerator::generate_composite_access(TypeDeclaration &result_type) writer.write(*i); end_expression(opcode); + r_constant_result = false; if(r_composite_base) { if(assignment_source_id) @@ -653,6 +651,7 @@ void SpirVGenerator::visit(Swizzle &swizzle) writer.write(swizzle.components[i]); end_expression(OP_VECTOR_SHUFFLE); } + r_constant_result = false; } void SpirVGenerator::visit(UnaryExpression &unary) @@ -665,7 +664,7 @@ void SpirVGenerator::visit(UnaryExpression &unary) return; BasicTypeDeclaration &basic = dynamic_cast(*unary.expression->type); - BasicTypeDeclaration &elem = get_element_type(basic); + BasicTypeDeclaration &elem = *get_element_type(basic); if(constant_expression && elem.kind!=BasicTypeDeclaration::BOOL && elem.kind!=BasicTypeDeclaration::INT) /* SPIR-V allows constant operations on floating-point values only for @@ -675,6 +674,7 @@ void SpirVGenerator::visit(UnaryExpression &unary) Id result_type_id = get_id(*unary.type); Opcode opcode = OP_NOP; + r_constant_result = false; if(oper=='!') opcode = OP_LOGICAL_NOT; else if(oper=='~') @@ -747,7 +747,7 @@ void SpirVGenerator::visit(BinaryExpression &binary) BasicTypeDeclaration &basic_left = dynamic_cast(*binary.left->type); BasicTypeDeclaration &basic_right = dynamic_cast(*binary.right->type); // Expression resolver ensures that element types are the same - BasicTypeDeclaration &elem = get_element_type(basic_left); + BasicTypeDeclaration &elem = *get_element_type(basic_left); if(constant_expression && elem.kind!=BasicTypeDeclaration::BOOL && elem.kind!=BasicTypeDeclaration::INT) /* SPIR-V allows constant operations on floating-point values only for @@ -763,6 +763,8 @@ void SpirVGenerator::visit(BinaryExpression &binary) Opcode opcode = OP_NOP; bool swap_operands = false; + r_constant_result = false; + char oper2 = binary.oper->token[1]; if((oper=='<' || oper=='>') && oper2!=oper) { @@ -946,6 +948,7 @@ void SpirVGenerator::visit(Assignment &assign) SetForScope set_assign(assignment_source_id, r_expression_result_id); assign.left->visit(*this); + r_constant_result = false; } void SpirVGenerator::visit(TernaryExpression &ternary) @@ -993,13 +996,13 @@ void SpirVGenerator::visit(TernaryExpression &ternary) writer.write(false_result_id); writer.write(false_label_id); end_expression(OP_PHI); + + r_constant_result = false; } void SpirVGenerator::visit(FunctionCall &call) { - if(constant_expression) - throw internal_error("function call in constant expression"); - else if(assignment_source_id) + if(assignment_source_id) throw internal_error("assignment to function call"); else if(composite_access) return visit_isolated(call); @@ -1008,23 +1011,28 @@ void SpirVGenerator::visit(FunctionCall &call) vector argument_ids; argument_ids.reserve(call.arguments.size()); + bool all_args_const = true; for(NodeArray::const_iterator i=call.arguments.begin(); i!=call.arguments.end(); ++i) { (*i)->visit(*this); argument_ids.push_back(r_expression_result_id); + all_args_const &= r_constant_result; } + if(constant_expression && (!call.constructor || !all_args_const)) + throw internal_error("function call in constant expression"); + Id result_type_id = get_id(*call.type); if(call.constructor) - visit_constructor(call, argument_ids); + visit_constructor(call, argument_ids, all_args_const); else if(call.declaration->source==BUILTIN_SOURCE) { string arg_types; for(NodeArray::const_iterator i=call.arguments.begin(); i!=call.arguments.end(); ++i) if(BasicTypeDeclaration *basic_arg = dynamic_cast((*i)->type)) { - BasicTypeDeclaration &elem_arg = get_element_type(*basic_arg); + BasicTypeDeclaration &elem_arg = *get_element_type(*basic_arg); switch(elem_arg.kind) { case BasicTypeDeclaration::BOOL: arg_types += 'b'; break; @@ -1087,7 +1095,7 @@ void SpirVGenerator::visit(FunctionCall &call) } } -void SpirVGenerator::visit_constructor(FunctionCall &call, const vector &argument_ids) +void SpirVGenerator::visit_constructor(FunctionCall &call, const vector &argument_ids, bool all_args_const) { Id result_type_id = get_id(*call.type); @@ -1101,9 +1109,11 @@ void SpirVGenerator::visit_constructor(FunctionCall &call, const vector &arg return; } - BasicTypeDeclaration &elem = get_element_type(*basic); + SetFlag set_const(constant_expression, constant_expression || all_args_const); + + BasicTypeDeclaration &elem = *get_element_type(*basic); BasicTypeDeclaration &basic_arg0 = dynamic_cast(*call.arguments[0]->type); - BasicTypeDeclaration &elem_arg0 = get_element_type(basic_arg0); + BasicTypeDeclaration &elem_arg0 = *get_element_type(basic_arg0); if(basic->kind==BasicTypeDeclaration::MATRIX) { @@ -1146,6 +1156,9 @@ void SpirVGenerator::visit_constructor(FunctionCall &call, const vector &arg } else if(elem.kind==BasicTypeDeclaration::BOOL) { + if(constant_expression) + throw internal_error("unconverted constant"); + // Conversion to boolean is implemented as comparing against zero. Id number_type_id = get_id(elem_arg0); Id zero_id = (elem_arg0.kind==BasicTypeDeclaration::FLOAT ? @@ -1158,6 +1171,9 @@ void SpirVGenerator::visit_constructor(FunctionCall &call, const vector &arg } else if(elem_arg0.kind==BasicTypeDeclaration::BOOL) { + if(constant_expression) + throw internal_error("unconverted constant"); + /* Conversion from boolean is implemented as selecting from zero or one. */ Id number_type_id = get_id(elem); @@ -1179,6 +1195,9 @@ void SpirVGenerator::visit_constructor(FunctionCall &call, const vector &arg } else { + if(constant_expression) + throw internal_error("unconverted constant"); + // Scalar or vector conversion between types of equal size. Opcode opcode; if(elem.kind==BasicTypeDeclaration::INT && elem_arg0.kind==BasicTypeDeclaration::FLOAT)