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.globals, 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.globals, OP_SPEC_CONSTANT_OP, (n_args ? 2+has_result*2+n_args : 0));
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;
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);
}
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)
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;
r_composite_base = iface.declaration;
r_expression_result_id = 0;
+ r_constant_result = false;
}
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)
writer.write(swizzle.components[i]);
end_expression(OP_VECTOR_SHUFFLE);
}
+ r_constant_result = false;
}
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=='~')
Opcode opcode = OP_NOP;
bool swap_operands = false;
+ r_constant_result = false;
+
char oper2 = binary.oper->token[1];
if((oper=='<' || oper=='>') && oper2!=oper)
{
SetForScope<Id> set_assign(assignment_source_id, r_expression_result_id);
assign.left->visit(*this);
+ r_constant_result = false;
}
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);
vector<Id> argument_ids;
argument_ids.reserve(call.arguments.size());
+ bool all_args_const = true;
for(NodeArray<Expression>::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;
}
}
-void SpirVGenerator::visit_constructor(FunctionCall &call, const vector<Id> &argument_ids)
+void SpirVGenerator::visit_constructor(FunctionCall &call, const vector<Id> &argument_ids, bool all_args_const)
{
Id result_type_id = get_id(*call.type);
return;
}
+ SetFlag set_const(constant_expression, constant_expression || all_args_const);
+
BasicTypeDeclaration &elem = *get_element_type(*basic);
BasicTypeDeclaration &basic_arg0 = dynamic_cast<BasicTypeDeclaration &>(*call.arguments[0]->type);
BasicTypeDeclaration &elem_arg0 = *get_element_type(basic_arg0);
}
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 ?
}
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);
}
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)