aboutsummaryrefslogtreecommitdiffstats
path: root/src/compiler/spirv
diff options
context:
space:
mode:
authorJason Ekstrand <[email protected]>2019-01-11 21:36:28 -0600
committerJason Ekstrand <[email protected]>2019-01-12 17:55:49 -0600
commitb938d5fbefe09c67318e88eb869cab016fc6749b (patch)
treed1b0dcddf033d41c8080eeb4b6c07a0867449a89 /src/compiler/spirv
parent821b6861ec7c267599e28d600a833e7a2a79ccd4 (diff)
spirv: Emit switch conditions on-the-fly
Instead of emitting all of the conditions for the cases of a switch statement up-front, emit them on-the-fly as we emit the code for each case. The original justification for this was that we were going to have to build a default case anyway which would need them all. However, we can just trust CSE to clean up the mess in that case. Emitting each condition right before the if statement that uses it reduces register pressure and, in one customer benchmark, reduces spilling and improves performance by about 2x. Reviewed-by: Lionel Landwerlin <[email protected]>
Diffstat (limited to 'src/compiler/spirv')
-rw-r--r--src/compiler/spirv/vtn_cfg.c62
1 files changed, 26 insertions, 36 deletions
diff --git a/src/compiler/spirv/vtn_cfg.c b/src/compiler/spirv/vtn_cfg.c
index aef1b7e18fb..dc57e41feb0 100644
--- a/src/compiler/spirv/vtn_cfg.c
+++ b/src/compiler/spirv/vtn_cfg.c
@@ -852,6 +852,30 @@ vtn_emit_branch(struct vtn_builder *b, enum vtn_branch_type branch_type,
}
}
+static nir_ssa_def *
+vtn_switch_case_condition(struct vtn_builder *b, struct vtn_switch *swtch,
+ nir_ssa_def *sel, struct vtn_case *cse)
+{
+ if (cse->is_default) {
+ nir_ssa_def *any = nir_imm_false(&b->nb);
+ list_for_each_entry(struct vtn_case, other, &swtch->cases, link) {
+ if (other->is_default)
+ continue;
+
+ any = nir_ior(&b->nb, any,
+ vtn_switch_case_condition(b, swtch, sel, other));
+ }
+ return nir_inot(&b->nb, any);
+ } else {
+ nir_ssa_def *cond = nir_imm_false(&b->nb);
+ util_dynarray_foreach(&cse->values, uint64_t, val) {
+ nir_ssa_def *imm = nir_imm_intN_t(&b->nb, *val, sel->bit_size);
+ cond = nir_ior(&b->nb, cond, nir_ieq(&b->nb, sel, imm));
+ }
+ return cond;
+ }
+}
+
static void
vtn_emit_cf_list(struct vtn_builder *b, struct list_head *cf_list,
nir_variable *switch_fall_var, bool *has_switch_break,
@@ -978,46 +1002,13 @@ vtn_emit_cf_list(struct vtn_builder *b, struct list_head *cf_list,
nir_local_variable_create(b->nb.impl, glsl_bool_type(), "fall");
nir_store_var(&b->nb, fall_var, nir_imm_false(&b->nb), 1);
- /* Next, we gather up all of the conditions. We have to do this
- * up-front because we also need to build an "any" condition so
- * that we can use !any for default.
- */
- const int num_cases = list_length(&vtn_switch->cases);
- NIR_VLA(nir_ssa_def *, conditions, num_cases);
-
nir_ssa_def *sel = vtn_ssa_value(b, vtn_switch->selector)->def;
- /* An accumulation of all conditions. Used for the default */
- nir_ssa_def *any = NULL;
-
- int i = 0;
- list_for_each_entry(struct vtn_case, cse, &vtn_switch->cases, link) {
- if (cse->is_default) {
- conditions[i++] = NULL;
- continue;
- }
-
- nir_ssa_def *cond = NULL;
- util_dynarray_foreach(&cse->values, uint64_t, val) {
- nir_ssa_def *imm = nir_imm_intN_t(&b->nb, *val, sel->bit_size);
- nir_ssa_def *is_val = nir_ieq(&b->nb, sel, imm);
-
- cond = cond ? nir_ior(&b->nb, cond, is_val) : is_val;
- }
-
- any = any ? nir_ior(&b->nb, any, cond) : cond;
- conditions[i++] = cond;
- }
- vtn_assert(i == num_cases);
/* Now we can walk the list of cases and actually emit code */
- i = 0;
list_for_each_entry(struct vtn_case, cse, &vtn_switch->cases, link) {
/* Figure out the condition */
- nir_ssa_def *cond = conditions[i++];
- if (cse->is_default) {
- vtn_assert(cond == NULL);
- cond = nir_inot(&b->nb, any);
- }
+ nir_ssa_def *cond =
+ vtn_switch_case_condition(b, vtn_switch, sel, cse);
/* Take fallthrough into account */
cond = nir_ior(&b->nb, cond, nir_load_var(&b->nb, fall_var));
@@ -1030,7 +1021,6 @@ vtn_emit_cf_list(struct vtn_builder *b, struct list_head *cf_list,
nir_pop_if(&b->nb, case_if);
}
- vtn_assert(i == num_cases);
break;
}