Skip to content

Commit

Permalink
Implement while loops for SPIR-V
Browse files Browse the repository at this point in the history
  • Loading branch information
RobDangerous committed Aug 20, 2024
1 parent 066bb7f commit cd1d166
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 5 deletions.
53 changes: 52 additions & 1 deletion Sources/backends/spirv.c
Original file line number Diff line number Diff line change
Expand Up @@ -144,10 +144,12 @@ typedef enum spirv_opcode {
SPIRV_OPCODE_MEMBER_DECORATE = 72,
SPIRV_OPCODE_COMPOSITE_CONSTRUCT = 80,
SPIRV_OPCODE_F_ORD_LESS_THAN = 184,
SPIRV_OPCODE_LOOP_MERGE = 246,
SPIRV_OPCODE_SELECTION_MERGE = 247,
SPIRV_OPCODE_LABEL = 248,
SPIRV_OPCODE_BRANCH = 249,
SPIRV_OPCODE_BRANCH_CONDITIONAL = 250,
SPIRV_OPCODE_RETURN = 253,
SPIRV_OPCODE_LABEL = 248
} spirv_opcode;

static type_id find_access_type(int *indices, int indices_size, type_id base_type) {
Expand Down Expand Up @@ -216,6 +218,8 @@ typedef enum storage_class { STORAGE_CLASS_INPUT = 1, STORAGE_CLASS_OUTPUT = 3,

typedef enum selection_control { SELECTION_CONTROL_NONE = 0, SELCTION_CONTROL_FLATTEN = 1, SELECTION_CONTROL_DONT_FLATTEN = 2 } selection_control;

typedef enum loop_control { LOOP_CONTROL_NONE = 0, LOOP_CONTROL_UNROLL = 1, LOOP_CONTROL_DONT_UNROLL = 2 } loop_control;

typedef enum function_control { FUNCTION_CONTROL_NONE } function_control;

typedef enum execution_mode { EXECUTION_MODE_ORIGIN_UPPER_LEFT = 7 } execution_mode;
Expand Down Expand Up @@ -579,6 +583,16 @@ static void write_op_label_preallocated(instructions_buffer *instructions, spirv
write_instruction(instructions, WORD_COUNT(operands), SPIRV_OPCODE_LABEL, operands);
}

static void write_op_branch(instructions_buffer *instructions, spirv_id target) {
uint32_t operands[] = {target.id};
write_instruction(instructions, WORD_COUNT(operands), SPIRV_OPCODE_BRANCH, operands);
}

static void write_op_loop_merge(instructions_buffer *instructions, spirv_id merge_block, spirv_id continue_target, loop_control control) {
uint32_t operands[] = {merge_block.id, continue_target.id, (uint32_t)control};
write_instruction(instructions, WORD_COUNT(operands), SPIRV_OPCODE_LOOP_MERGE, operands);
}

static void write_op_return(instructions_buffer *instructions) {
write_simple_instruction(instructions, SPIRV_OPCODE_RETURN);
}
Expand Down Expand Up @@ -951,6 +965,43 @@ static void write_function(instructions_buffer *instructions, function *f, spirv

break;
}
case OPCODE_WHILE_START: {
spirv_id while_start_label = convert_kong_index_to_spirv_id(o->op_while_start.start_id);
spirv_id while_continue_label = convert_kong_index_to_spirv_id(o->op_while_start.continue_id);
spirv_id while_end_label = convert_kong_index_to_spirv_id(o->op_while_start.end_id);

write_op_branch(instructions, while_start_label);
write_op_label_preallocated(instructions, while_start_label);

write_op_loop_merge(instructions, while_end_label, while_continue_label, LOOP_CONTROL_NONE);

spirv_id loop_start_id = allocate_index();
write_op_branch(instructions, loop_start_id);
write_op_label_preallocated(instructions, loop_start_id);
break;
}
case OPCODE_WHILE_CONDITION: {
spirv_id while_end_label = convert_kong_index_to_spirv_id(o->op_while.end_id);

spirv_id pass = allocate_index();

write_op_branch_conditional(instructions, convert_kong_index_to_spirv_id(o->op_while.condition.index), pass, while_end_label);

write_op_label_preallocated(instructions, pass);
break;
}
case OPCODE_WHILE_END: {
spirv_id while_start_label = convert_kong_index_to_spirv_id(o->op_while_end.start_id);
spirv_id while_continue_label = convert_kong_index_to_spirv_id(o->op_while_end.continue_id);
spirv_id while_end_label = convert_kong_index_to_spirv_id(o->op_while_end.end_id);

write_op_branch(instructions, while_continue_label);
write_op_label_preallocated(instructions, while_continue_label);

write_op_branch(instructions, while_start_label);
write_op_label_preallocated(instructions, while_end_label);
break;
}
case OPCODE_BLOCK_START:
case OPCODE_BLOCK_END: {
write_op_label_preallocated(instructions, convert_kong_index_to_spirv_id(o->op_block.id));
Expand Down
36 changes: 32 additions & 4 deletions Sources/compiler.c
Original file line number Diff line number Diff line change
Expand Up @@ -654,10 +654,20 @@ static block_ids emit_statement(opcodes *code, block *parent, statement *stateme
break;
}
case STATEMENT_WHILE: {
uint64_t start_id = next_variable_id;
++next_variable_id;
uint64_t continue_id = next_variable_id;
++next_variable_id;
uint64_t end_id = next_variable_id;
++next_variable_id;

{
opcode o;
o.type = OPCODE_WHILE_START;
o.size = OP_SIZE(o, op_nothing);
o.op_while_start.start_id = start_id;
o.op_while_start.continue_id = continue_id;
o.op_while_start.end_id = end_id;
o.size = OP_SIZE(o, op_while_start);
emit_op(code, &o);
}

Expand All @@ -669,6 +679,7 @@ static block_ids emit_statement(opcodes *code, block *parent, statement *stateme
variable v = emit_expression(code, parent, statement->whiley.test);

o.op_while.condition = v;
o.op_while.end_id = end_id;

emit_op(code, &o);
}
Expand All @@ -678,17 +689,30 @@ static block_ids emit_statement(opcodes *code, block *parent, statement *stateme
{
opcode o;
o.type = OPCODE_WHILE_END;
o.size = OP_SIZE(o, op_nothing);
o.op_while_end.start_id = start_id;
o.op_while_end.continue_id = continue_id;
o.op_while_end.end_id = end_id;
o.size = OP_SIZE(o, op_while_end);
emit_op(code, &o);
}

break;
}
case STATEMENT_DO_WHILE: {
uint64_t start_id = next_variable_id;
++next_variable_id;
uint64_t continue_id = next_variable_id;
++next_variable_id;
uint64_t end_id = next_variable_id;
++next_variable_id;

{
opcode o;
o.type = OPCODE_WHILE_START;
o.size = OP_SIZE(o, op_nothing);
o.op_while_start.start_id = start_id;
o.op_while_start.continue_id = continue_id;
o.op_while_start.end_id = end_id;
o.size = OP_SIZE(o, op_while_start);
emit_op(code, &o);
}

Expand All @@ -702,14 +726,18 @@ static block_ids emit_statement(opcodes *code, block *parent, statement *stateme
variable v = emit_expression(code, parent, statement->whiley.test);

o.op_while.condition = v;
o.op_while.end_id = end_id;

emit_op(code, &o);
}

{
opcode o;
o.type = OPCODE_WHILE_END;
o.size = OP_SIZE(o, op_nothing);
o.op_while_end.start_id = start_id;
o.op_while_end.continue_id = continue_id;
o.op_while_end.end_id = end_id;
o.size = OP_SIZE(o, op_while_end);
emit_op(code, &o);
}

Expand Down
11 changes: 11 additions & 0 deletions Sources/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,19 @@ typedef struct opcode {
uint64_t start_id;
uint64_t end_id;
} op_if;
struct {
uint64_t start_id;
uint64_t continue_id;
uint64_t end_id;
} op_while_start;
struct {
uint64_t start_id;
uint64_t continue_id;
uint64_t end_id;
} op_while_end;
struct {
variable condition;
uint64_t end_id;
} op_while;
struct {
uint64_t id;
Expand Down

0 comments on commit cd1d166

Please sign in to comment.