summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKarol Herbst <kherbst@redhat.com>2020-08-11 14:00:26 +0200
committerEric Engestrom <eric@engestrom.ch>2020-09-28 18:23:20 +0200
commit4bff9ca69160ec991200aba4db292a6d88bd548a (patch)
tree728bcbeda08b23f997ce33cc88457585125a96a8
parent9dcc7d4d415715ffdb4d1c14f27b989cba52368d (diff)
spirv: extract switch parsing into its own function
v2 (Jason Ekstrand): - Construct a list of vtn_case objects Signed-off-by: Karol Herbst <kherbst@redhat.com> Reviewed-by: Jason Ekstrand <jason@jlekstrand.net> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/2401> (cherry picked from commit 467b90fcc46efdd5ce64a12937fedf507d0242ec)
-rw-r--r--.pick_status.json2
-rw-r--r--src/compiler/spirv/vtn_cfg.c180
-rw-r--r--src/compiler/spirv/vtn_private.h2
3 files changed, 100 insertions, 84 deletions
diff --git a/.pick_status.json b/.pick_status.json
index b7637ed8f0c..4b56dbf333c 100644
--- a/.pick_status.json
+++ b/.pick_status.json
@@ -13855,7 +13855,7 @@
"description": "spirv: extract switch parsing into its own function",
"nominated": false,
"nomination_type": null,
- "resolution": 4,
+ "resolution": 1,
"master_sha": null,
"because_sha": null
},
diff --git a/src/compiler/spirv/vtn_cfg.c b/src/compiler/spirv/vtn_cfg.c
index 6d19d981965..4a07b35be53 100644
--- a/src/compiler/spirv/vtn_cfg.c
+++ b/src/compiler/spirv/vtn_cfg.c
@@ -608,6 +608,74 @@ vtn_add_cfg_work_item(struct vtn_builder *b,
list_addtail(&work->link, work_list);
}
+/* returns the default block */
+static void
+vtn_parse_switch(struct vtn_builder *b,
+ struct vtn_switch *swtch,
+ const uint32_t *branch,
+ struct list_head *case_list)
+{
+ const uint32_t *branch_end = branch + (branch[0] >> SpvWordCountShift);
+
+ struct vtn_value *sel_val = vtn_untyped_value(b, branch[1]);
+ vtn_fail_if(!sel_val->type ||
+ sel_val->type->base_type != vtn_base_type_scalar,
+ "Selector of OpSwitch must have a type of OpTypeInt");
+
+ nir_alu_type sel_type =
+ nir_get_nir_type_for_glsl_type(sel_val->type->type);
+ vtn_fail_if(nir_alu_type_get_base_type(sel_type) != nir_type_int &&
+ nir_alu_type_get_base_type(sel_type) != nir_type_uint,
+ "Selector of OpSwitch must have a type of OpTypeInt");
+
+ struct hash_table *block_to_case = _mesa_pointer_hash_table_create(b);
+
+ bool is_default = true;
+ const unsigned bitsize = nir_alu_type_get_type_size(sel_type);
+ for (const uint32_t *w = branch + 2; w < branch_end;) {
+ uint64_t literal = 0;
+ if (!is_default) {
+ if (bitsize <= 32) {
+ literal = *(w++);
+ } else {
+ assert(bitsize == 64);
+ literal = vtn_u64_literal(w);
+ w += 2;
+ }
+ }
+ struct vtn_block *case_block = vtn_block(b, *(w++));
+
+ struct hash_entry *case_entry =
+ _mesa_hash_table_search(block_to_case, case_block);
+
+ struct vtn_case *cse;
+ if (case_entry) {
+ cse = case_entry->data;
+ } else {
+ cse = rzalloc(b, struct vtn_case);
+
+ cse->node.type = vtn_cf_node_type_case;
+ cse->node.parent = swtch ? &swtch->node : NULL;
+ cse->block = case_block;
+ list_inithead(&cse->body);
+ util_dynarray_init(&cse->values, b);
+
+ list_addtail(&cse->node.link, case_list);
+ _mesa_hash_table_insert(block_to_case, case_block, cse);
+ }
+
+ if (is_default) {
+ cse->is_default = true;
+ } else {
+ util_dynarray_append(&cse->values, uint64_t, literal);
+ }
+
+ is_default = false;
+ }
+
+ _mesa_hash_table_destroy(block_to_case, NULL);
+}
+
/* Processes a block and returns the next block to process or NULL if we've
* reached the end of the construct.
*/
@@ -812,17 +880,6 @@ vtn_process_block(struct vtn_builder *b,
}
case SpvOpSwitch: {
- struct vtn_value *sel_val = vtn_untyped_value(b, block->branch[1]);
- vtn_fail_if(!sel_val->type ||
- sel_val->type->base_type != vtn_base_type_scalar,
- "Selector of OpSwitch must have a type of OpTypeInt");
-
- nir_alu_type sel_type =
- nir_get_nir_type_for_glsl_type(sel_val->type->type);
- vtn_fail_if(nir_alu_type_get_base_type(sel_type) != nir_type_int &&
- nir_alu_type_get_base_type(sel_type) != nir_type_uint,
- "Selector of OpSwitch must have a type of OpTypeInt");
-
struct vtn_switch *swtch = rzalloc(b, struct vtn_switch);
swtch->node.type = vtn_cf_node_type_switch;
@@ -843,82 +900,39 @@ vtn_process_block(struct vtn_builder *b,
}
/* First, we go through and record all of the cases. */
- const uint32_t *branch_end =
- block->branch + (block->branch[0] >> SpvWordCountShift);
-
- struct hash_table *block_to_case = _mesa_pointer_hash_table_create(b);
-
- bool is_default = true;
- const unsigned bitsize = nir_alu_type_get_type_size(sel_type);
- for (const uint32_t *w = block->branch + 2; w < branch_end;) {
- uint64_t literal = 0;
- if (!is_default) {
- if (bitsize <= 32) {
- literal = *(w++);
- } else {
- assert(bitsize == 64);
- literal = vtn_u64_literal(w);
- w += 2;
- }
- }
- struct vtn_block *case_block = vtn_block(b, *(w++));
-
- struct hash_entry *case_entry =
- _mesa_hash_table_search(block_to_case, case_block);
+ vtn_parse_switch(b, swtch, block->branch, &swtch->cases);
+
+ /* Gather the branch types for the switch */
+ vtn_foreach_cf_node(case_node, &swtch->cases) {
+ struct vtn_case *cse = vtn_cf_node_as_case(case_node);
+
+ cse->type = vtn_handle_branch(b, &swtch->node, cse->block);
+ switch (cse->type) {
+ case vtn_branch_type_none:
+ /* This is a "real" cases which has stuff in it */
+ vtn_fail_if(cse->block->switch_case != NULL,
+ "OpSwitch has a case which is also in another "
+ "OpSwitch construct");
+ cse->block->switch_case = cse;
+ vtn_add_cfg_work_item(b, work_list, &cse->node,
+ &cse->body, cse->block);
+ break;
+
+ case vtn_branch_type_switch_break:
+ case vtn_branch_type_loop_break:
+ case vtn_branch_type_loop_continue:
+ /* Switch breaks as well as loop breaks and continues can be
+ * used to break out of a switch construct or as direct targets
+ * of the OpSwitch.
+ */
+ break;
- struct vtn_case *cse;
- if (case_entry) {
- cse = case_entry->data;
- } else {
- cse = rzalloc(b, struct vtn_case);
-
- cse->node.type = vtn_cf_node_type_case;
- cse->node.parent = &swtch->node;
- list_inithead(&cse->body);
- util_dynarray_init(&cse->values, b);
-
- cse->type = vtn_handle_branch(b, &swtch->node, case_block);
- switch (cse->type) {
- case vtn_branch_type_none:
- /* This is a "real" cases which has stuff in it */
- vtn_fail_if(case_block->switch_case != NULL,
- "OpSwitch has a case which is also in another "
- "OpSwitch construct");
- case_block->switch_case = cse;
- vtn_add_cfg_work_item(b, work_list, &cse->node,
- &cse->body, case_block);
- break;
-
- case vtn_branch_type_switch_break:
- case vtn_branch_type_loop_break:
- case vtn_branch_type_loop_continue:
- /* Switch breaks as well as loop breaks and continues can be
- * used to break out of a switch construct or as direct targets
- * of the OpSwitch.
- */
- break;
-
- default:
- vtn_fail("Target of OpSwitch is not a valid structured exit "
- "from the switch construct.");
- }
-
- list_addtail(&cse->node.link, &swtch->cases);
-
- _mesa_hash_table_insert(block_to_case, case_block, cse);
+ default:
+ vtn_fail("Target of OpSwitch is not a valid structured exit "
+ "from the switch construct.");
}
-
- if (is_default) {
- cse->is_default = true;
- } else {
- util_dynarray_append(&cse->values, uint64_t, literal);
- }
-
- is_default = false;
}
- _mesa_hash_table_destroy(block_to_case, NULL);
-
return swtch->break_block;
}
diff --git a/src/compiler/spirv/vtn_private.h b/src/compiler/spirv/vtn_private.h
index 824a4b9bb32..32d907cdf64 100644
--- a/src/compiler/spirv/vtn_private.h
+++ b/src/compiler/spirv/vtn_private.h
@@ -185,6 +185,8 @@ struct vtn_if {
struct vtn_case {
struct vtn_cf_node node;
+ struct vtn_block *block;
+
enum vtn_branch_type type;
struct list_head body;