};
SpirVGenerator::SpirVGenerator():
- stage(0),
- current_function(0),
- writer(content),
- next_id(1),
- r_expression_result_id(0),
- constant_expression(false),
- spec_constant(false),
- reachable(false),
- composite_access(false),
- r_composite_base_id(0),
- r_composite_base(0),
- assignment_source_id(0),
- loop_merge_block_id(0),
- loop_continue_target_id(0)
+ writer(content)
{ }
void SpirVGenerator::apply(Module &module)
r_constant_result = false;
if(composite_access)
{
- r_composite_base = var.declaration;
r_expression_result_id = 0;
+ if(!assignment_source_id)
+ {
+ auto i = variable_load_ids.find(var.declaration);
+ if(i!=variable_load_ids.end())
+ r_expression_result_id = i->second;
+ }
+ if(!r_expression_result_id)
+ r_composite_base = var.declaration;
}
else if(assignment_source_id)
{
throw internal_error("assignment to temporary composite");
else
{
- for(unsigned i: r_composite_chain)
+ for(unsigned &i: r_composite_chain)
for(auto j=constant_ids.begin(); (i>=0x400000 && j!=constant_ids.end()); ++j)
if(j->second==(i&0x3FFFFF))
i = j->first.int_value;
void SpirVGenerator::visit(UnaryExpression &unary)
{
+ if(composite_access)
+ return visit_isolated(unary);
+
unary.expression->visit(*this);
char oper = unary.oper->token[0];
visit_isolated(*binary.right);
return visit_composite(*binary.left, 0x400000|r_expression_result_id, *binary.type);
}
+ else if(composite_access)
+ return visit_isolated(binary);
if(assignment_source_id)
throw internal_error("invalid binary expression in assignment target");
void SpirVGenerator::visit(TernaryExpression &ternary)
{
+ if(composite_access)
+ return visit_isolated(ternary);
if(constant_expression)
{
ternary.condition->visit(*this);
writer.write_op_label(true_label_id);
ternary.true_expr->visit(*this);
Id true_result_id = r_expression_result_id;
+ true_label_id = writer.get_current_block();
writer.write_op(content.function_body, OP_BRANCH, merge_block_id);
writer.write_op_label(false_label_id);
ternary.false_expr->visit(*this);
Id false_result_id = r_expression_result_id;
+ false_label_id = writer.get_current_block();
writer.write_op_label(merge_block_id);
r_expression_result_id = begin_expression(OP_PHI, get_id(*ternary.type), 4);
writer.write_op_decorate(var_id, DECO_BINDING, q.value);
}
}
+ if(!var.name.compare(0, 3, "gl_"))
+ {
+ BuiltinSemantic semantic = get_builtin_semantic(var.name);
+ writer.write_op_decorate(var_id, DECO_BUILTIN, semantic);
+ }
if(init_id && current_function)
{
variable_load_ids[func.parameters[i].get()] = param_id;
}
+ reachable = true;
writer.begin_function_body(next_id++);
SetForScope<FunctionDeclaration *> set_func(current_function, &func);
func.body.visit(*this);
- if(writer.has_current_block())
+ if(writer.get_current_block())
{
if(!reachable)
writer.write_op(content.function_body, OP_UNREACHABLE);
writer.write_op(content.function_body, OP_SELECTION_MERGE, merge_block_id, 0); // Selection control (none)
writer.write_op(content.function_body, OP_BRANCH_CONDITIONAL, r_expression_result_id, true_label_id, false_label_id);
+ std::map<const VariableDeclaration *, Id> saved_load_ids = variable_load_ids;
+
writer.write_op_label(true_label_id);
cond.body.visit(*this);
- if(writer.has_current_block())
+ if(writer.get_current_block())
writer.write_op(content.function_body, OP_BRANCH, merge_block_id);
bool reachable_if_true = reachable;
reachable = true;
if(!cond.else_body.body.empty())
{
+ swap(saved_load_ids, variable_load_ids);
writer.write_op_label(false_label_id);
cond.else_body.visit(*this);
reachable |= reachable_if_true;
if(iter.init_statement)
iter.init_statement->visit(*this);
- variable_load_ids.clear();
+ for(Node *n: AssignmentCollector().apply(iter))
+ if(VariableDeclaration *var = dynamic_cast<VariableDeclaration *>(n))
+ variable_load_ids.erase(var);
Id header_id = next_id++;
Id continue_id = next_id++;