diff options
author | Dave Airlie <[email protected]> | 2019-03-08 13:09:05 +1000 |
---|---|---|
committer | Dave Airlie <[email protected]> | 2019-03-29 08:10:50 +1000 |
commit | b779baa9bf95ca259779fa028a7b822bf8a17f46 (patch) | |
tree | 42c347816f9290dc272e52e9bcbd51b9612caae1 | |
parent | 8e0469f62934e2228694948bf5cded8b5462ef3e (diff) |
nir/deref: fix struct wrapper casts. (v3)
llvm/spir-v spits out some struct a { struct b {} }, but it
doesn't deref, it casts (struct a) to (struct b), reconstruct
struct derefs instead of casts for these.
v2: use ssa_def_rewrite uses, rework the type restrictions (Jason)
v3: squish more stuff into one function, drop unused temp (Jason)
Reviewed-by: Jason Ekstrand <[email protected]>
-rw-r--r-- | src/compiler/nir/nir_deref.c | 38 |
1 files changed, 36 insertions, 2 deletions
diff --git a/src/compiler/nir/nir_deref.c b/src/compiler/nir/nir_deref.c index 174c4a3280e..460d3bf4656 100644 --- a/src/compiler/nir/nir_deref.c +++ b/src/compiler/nir/nir_deref.c @@ -697,11 +697,45 @@ opt_remove_cast_cast(nir_deref_instr *cast) return true; } +/** + * Is this casting a struct to a contained struct. + * struct a { struct b field0 }; + * ssa_5 is structa; + * deref_cast (structb *)ssa_5 (function_temp structb); + * converts to + * deref_struct &ssa_5->field0 (function_temp structb); + * This allows subsequent copy propagation to work. + */ +static bool +opt_replace_struct_wrapper_cast(nir_builder *b, nir_deref_instr *cast) +{ + nir_deref_instr *parent = nir_src_as_deref(cast->parent); + if (!parent) + return false; + + if (!glsl_type_is_struct(parent->type)) + return false; + + if (glsl_get_struct_field_offset(parent->type, 0) != 0) + return false; + + if (cast->type != glsl_get_struct_field(parent->type, 0)) + return false; + + nir_deref_instr *replace = nir_build_deref_struct(b, parent, 0); + nir_ssa_def_rewrite_uses(&cast->dest.ssa, nir_src_for_ssa(&replace->dest.ssa)); + nir_deref_instr_remove_if_unused(cast); + return true; +} + static bool -opt_deref_cast(nir_deref_instr *cast) +opt_deref_cast(nir_builder *b, nir_deref_instr *cast) { bool progress; + if (opt_replace_struct_wrapper_cast(b, cast)) + return true; + progress = opt_remove_cast_cast(cast); if (!is_trivial_deref_cast(cast)) return progress; @@ -798,7 +832,7 @@ nir_opt_deref_impl(nir_function_impl *impl) break; case nir_deref_type_cast: - if (opt_deref_cast(deref)) + if (opt_deref_cast(&b, deref)) progress = true; break; |