Re: [Mesa-dev] [PATCH 1/2] nir: update nir_lower_returns to only predicate instructions when needed
Ok... Different set of comments. Now, with less bogosity! On Mon, Dec 19, 2016 at 8:18 PM, Timothy Arceri < timothy.arc...@collabora.com> wrote: > Unless an if statement contains nested returns we can simply add > any following instructions to the branch without the return. > > V2: fix handling if_nested_return value when there is a sibling if/loop > that doesn't contain a return. (Spotted by Ken) > --- > src/compiler/nir/nir_lower_returns.c | 37 ++ > -- > 1 file changed, 31 insertions(+), 6 deletions(-) > > diff --git a/src/compiler/nir/nir_lower_returns.c > b/src/compiler/nir/nir_lower_returns.c > index cf49d5b..5eec984 100644 > --- a/src/compiler/nir/nir_lower_returns.c > +++ b/src/compiler/nir/nir_lower_returns.c > @@ -30,6 +30,8 @@ struct lower_returns_state { > struct exec_list *cf_list; > nir_loop *loop; > nir_variable *return_flag; > + /* Are there other return statments nested in the current if */ > + bool if_nested_return; > Can we rename this to has_predicated_return or has_return_in_if? I would prefer has_predicated_return. Also, we should add a comment: This indicates that we have a return which is predicated on some form of control-flow. Since whether or not the return happens can only be determined dynamically at run-time, everything that occurs afterwards needs to be predicated on the return flag variable. > }; > > static bool lower_returns_in_cf_list(struct exec_list *cf_list, > @@ -82,8 +84,10 @@ lower_returns_in_loop(nir_loop *loop, struct > lower_returns_state *state) > * flag set to true. We need to predicate everything following the > loop > * on the return flag. > */ > - if (progress) > + if (progress) { >predicate_following(>cf_node, state); > + state->if_nested_return = true; > + } > > return progress; > } > @@ -91,10 +95,13 @@ lower_returns_in_loop(nir_loop *loop, struct > lower_returns_state *state) > static bool > lower_returns_in_if(nir_if *if_stmt, struct lower_returns_state *state) > { > - bool progress; > + bool progress, then_progress; > > - progress = lower_returns_in_cf_list(_stmt->then_list, state); > - progress = lower_returns_in_cf_list(_stmt->else_list, state) || > progress; > + bool if_nested_return = state->if_nested_return; > + state->if_nested_return = false; > + > + then_progress = lower_returns_in_cf_list(_stmt->then_list, state); > + progress = lower_returns_in_cf_list(_stmt->else_list, state) || > then_progress; > I don't think this is what you want. We really want two separate then_progress and else_progress booleans. > > /* If either of the recursive calls made progress, then there were > * returns inside of the body of the if. If we're in a loop, then > these > @@ -106,8 +113,25 @@ lower_returns_in_if(nir_if *if_stmt, struct > lower_returns_state *state) > * after a return, we need to predicate everything following on the > * return flag. > */ > - if (progress && !state->loop) > - predicate_following(_stmt->cf_node, state); > + if (progress && !state->loop) { > + if (state->if_nested_return) { > + predicate_following(_stmt->cf_node, state); > + } else { > + /* If there are no nested returns we can just add the > instructions to > + * the end of the branch that doesn't have the return. > + */ > + nir_cf_list list; > + nir_cf_extract(, nir_after_cf_node(_stmt->cf_node), > +nir_after_cf_list(state->cf_list)); > + > + if (then_progress) > +nir_cf_reinsert(, nir_after_cf_list(_stmt-> > else_list)); > + else > +nir_cf_reinsert(, nir_after_cf_list(_stmt-> > then_list)); > What if both make progress? In that case, we should probbly just delete the "after" code. This can happen with shaders coming in from SPIR-V since this pass is run *before* dead_cf. > + } > + } > + > + state->if_nested_return = progress || if_nested_return; > > return progress; > } > @@ -221,6 +245,7 @@ nir_lower_returns_impl(nir_function_impl *impl) > state.cf_list = >body; > state.loop = NULL; > state.return_flag = NULL; > + state.if_nested_return = false; > nir_builder_init(, impl); > > bool progress = lower_returns_in_cf_list(>body, ); > -- > 2.9.3 > > ___ > mesa-dev mailing list > mesa-dev@lists.freedesktop.org > https://lists.freedesktop.org/mailman/listinfo/mesa-dev > ___ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev
Re: [Mesa-dev] [PATCH 1/2] nir: update nir_lower_returns to only predicate instructions when needed
On Tue, 2016-12-20 at 09:44 -0800, Jason Ekstrand wrote: > On Mon, Dec 19, 2016 at 8:18 PM, Timothy Arceribora.com> wrote: > > Unless an if statement contains nested returns we can simply add > > any following instructions to the branch without the return. > > > > V2: fix handling if_nested_return value when there is a sibling > > if/loop > > that doesn't contain a return. (Spotted by Ken) > > --- > > src/compiler/nir/nir_lower_returns.c | 37 > > ++-- > > 1 file changed, 31 insertions(+), 6 deletions(-) > > > > diff --git a/src/compiler/nir/nir_lower_returns.c > > b/src/compiler/nir/nir_lower_returns.c > > index cf49d5b..5eec984 100644 > > --- a/src/compiler/nir/nir_lower_returns.c > > +++ b/src/compiler/nir/nir_lower_returns.c > > @@ -30,6 +30,8 @@ struct lower_returns_state { > > struct exec_list *cf_list; > > nir_loop *loop; > > nir_variable *return_flag; > > + /* Are there other return statments nested in the current if */ > > + bool if_nested_return; > > }; > > > > static bool lower_returns_in_cf_list(struct exec_list *cf_list, > > @@ -82,8 +84,10 @@ lower_returns_in_loop(nir_loop *loop, struct > > lower_returns_state *state) > > * flag set to true. We need to predicate everything following > > the loop > > * on the return flag. > > */ > > - if (progress) > > + if (progress) { > > predicate_following(>cf_node, state); > > + state->if_nested_return = true; > > + } > > > > return progress; > > } > > @@ -91,10 +95,13 @@ lower_returns_in_loop(nir_loop *loop, struct > > lower_returns_state *state) > > static bool > > lower_returns_in_if(nir_if *if_stmt, struct lower_returns_state > > *state) > > { > > - bool progress; > > + bool progress, then_progress; > > > > - progress = lower_returns_in_cf_list(_stmt->then_list, > > state); > > - progress = lower_returns_in_cf_list(_stmt->else_list, state) > > || progress; > > + bool if_nested_return = state->if_nested_return; > > + state->if_nested_return = false; > > + > > + then_progress = lower_returns_in_cf_list(_stmt->then_list, > > state); > > + progress = lower_returns_in_cf_list(_stmt->else_list, state) > > || then_progress; > > I don't really get why we need this if_nested_return thing. Why > can't we just have two progress booleans called then_progress and > else_progress and just do > > if (then_progress && else_progress) { > predicate_following > } else if (!then_progress && !else_progress) { > return false; > } else { > /* Put it in one side or the other based on progress */ > } > > That seems way simpler. Way simpler yes but it doesn't do what we need it to :) Ken had the same suggestion yesterday. The problem is it won't handle a case like this: if () { if () { return; } else { // If we exit from here we need to predicate the code following // the outer if, we cant just stick it in the else block. } } else { } ... code following outer if ... > > > /* If either of the recursive calls made progress, then there > > were > > * returns inside of the body of the if. If we're in a loop, > > then these > > @@ -106,8 +113,25 @@ lower_returns_in_if(nir_if *if_stmt, struct > > lower_returns_state *state) > > * after a return, we need to predicate everything following on > > the > > * return flag. > > */ > > - if (progress && !state->loop) > > - predicate_following(_stmt->cf_node, state); > > + if (progress && !state->loop) { > > + if (state->if_nested_return) { > > + predicate_following(_stmt->cf_node, state); > > + } else { > > + /* If there are no nested returns we can just add the > > instructions to > > + * the end of the branch that doesn't have the return. > > + */ > > + nir_cf_list list; > > + nir_cf_extract(, nir_after_cf_node(_stmt- > > >cf_node), > > + nir_after_cf_list(state->cf_list)); > > + > > + if (then_progress) > > + nir_cf_reinsert(, nir_after_cf_list(_stmt- > > >else_list)); > > + else > > + nir_cf_reinsert(, nir_after_cf_list(_stmt- > > >then_list)); > > + } > > + } > > + > > + state->if_nested_return = progress || if_nested_return; > > > > return progress; > > } > > @@ -221,6 +245,7 @@ nir_lower_returns_impl(nir_function_impl *impl) > > state.cf_list = >body; > > state.loop = NULL; > > state.return_flag = NULL; > > + state.if_nested_return = false; > > nir_builder_init(, impl); > > > > bool progress = lower_returns_in_cf_list(>body, ); > > -- > > 2.9.3 > > > > ___ > > mesa-dev mailing list > > mesa-dev@lists.freedesktop.org > > https://lists.freedesktop.org/mailman/listinfo/mesa-dev > > > > ___ > mesa-dev mailing list > mesa-dev@lists.freedesktop.org >
Re: [Mesa-dev] [PATCH 1/2] nir: update nir_lower_returns to only predicate instructions when needed
On Mon, Dec 19, 2016 at 8:18 PM, Timothy Arceri < timothy.arc...@collabora.com> wrote: > Unless an if statement contains nested returns we can simply add > any following instructions to the branch without the return. > > V2: fix handling if_nested_return value when there is a sibling if/loop > that doesn't contain a return. (Spotted by Ken) > --- > src/compiler/nir/nir_lower_returns.c | 37 ++ > -- > 1 file changed, 31 insertions(+), 6 deletions(-) > > diff --git a/src/compiler/nir/nir_lower_returns.c > b/src/compiler/nir/nir_lower_returns.c > index cf49d5b..5eec984 100644 > --- a/src/compiler/nir/nir_lower_returns.c > +++ b/src/compiler/nir/nir_lower_returns.c > @@ -30,6 +30,8 @@ struct lower_returns_state { > struct exec_list *cf_list; > nir_loop *loop; > nir_variable *return_flag; > + /* Are there other return statments nested in the current if */ > + bool if_nested_return; > }; > > static bool lower_returns_in_cf_list(struct exec_list *cf_list, > @@ -82,8 +84,10 @@ lower_returns_in_loop(nir_loop *loop, struct > lower_returns_state *state) > * flag set to true. We need to predicate everything following the > loop > * on the return flag. > */ > - if (progress) > + if (progress) { >predicate_following(>cf_node, state); > + state->if_nested_return = true; > + } > > return progress; > } > @@ -91,10 +95,13 @@ lower_returns_in_loop(nir_loop *loop, struct > lower_returns_state *state) > static bool > lower_returns_in_if(nir_if *if_stmt, struct lower_returns_state *state) > { > - bool progress; > + bool progress, then_progress; > > - progress = lower_returns_in_cf_list(_stmt->then_list, state); > - progress = lower_returns_in_cf_list(_stmt->else_list, state) || > progress; > + bool if_nested_return = state->if_nested_return; > + state->if_nested_return = false; > + > + then_progress = lower_returns_in_cf_list(_stmt->then_list, state); > + progress = lower_returns_in_cf_list(_stmt->else_list, state) || > then_progress; > I don't really get why we need this if_nested_return thing. Why can't we just have two progress booleans called then_progress and else_progress and just do if (then_progress && else_progress) { predicate_following } else if (!then_progress && !else_progress) { return false; } else { /* Put it in one side or the other based on progress */ } That seems way simpler. > > /* If either of the recursive calls made progress, then there were > * returns inside of the body of the if. If we're in a loop, then > these > @@ -106,8 +113,25 @@ lower_returns_in_if(nir_if *if_stmt, struct > lower_returns_state *state) > * after a return, we need to predicate everything following on the > * return flag. > */ > - if (progress && !state->loop) > - predicate_following(_stmt->cf_node, state); > + if (progress && !state->loop) { > + if (state->if_nested_return) { > + predicate_following(_stmt->cf_node, state); > + } else { > + /* If there are no nested returns we can just add the > instructions to > + * the end of the branch that doesn't have the return. > + */ > + nir_cf_list list; > + nir_cf_extract(, nir_after_cf_node(_stmt->cf_node), > +nir_after_cf_list(state->cf_list)); > + > + if (then_progress) > +nir_cf_reinsert(, nir_after_cf_list(_stmt-> > else_list)); > + else > +nir_cf_reinsert(, nir_after_cf_list(_stmt-> > then_list)); > + } > + } > + > + state->if_nested_return = progress || if_nested_return; > > return progress; > } > @@ -221,6 +245,7 @@ nir_lower_returns_impl(nir_function_impl *impl) > state.cf_list = >body; > state.loop = NULL; > state.return_flag = NULL; > + state.if_nested_return = false; > nir_builder_init(, impl); > > bool progress = lower_returns_in_cf_list(>body, ); > -- > 2.9.3 > > ___ > mesa-dev mailing list > mesa-dev@lists.freedesktop.org > https://lists.freedesktop.org/mailman/listinfo/mesa-dev > ___ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev
[Mesa-dev] [PATCH 1/2] nir: update nir_lower_returns to only predicate instructions when needed
Unless an if statement contains nested returns we can simply add any following instructions to the branch without the return. V2: fix handling if_nested_return value when there is a sibling if/loop that doesn't contain a return. (Spotted by Ken) --- src/compiler/nir/nir_lower_returns.c | 37 ++-- 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/src/compiler/nir/nir_lower_returns.c b/src/compiler/nir/nir_lower_returns.c index cf49d5b..5eec984 100644 --- a/src/compiler/nir/nir_lower_returns.c +++ b/src/compiler/nir/nir_lower_returns.c @@ -30,6 +30,8 @@ struct lower_returns_state { struct exec_list *cf_list; nir_loop *loop; nir_variable *return_flag; + /* Are there other return statments nested in the current if */ + bool if_nested_return; }; static bool lower_returns_in_cf_list(struct exec_list *cf_list, @@ -82,8 +84,10 @@ lower_returns_in_loop(nir_loop *loop, struct lower_returns_state *state) * flag set to true. We need to predicate everything following the loop * on the return flag. */ - if (progress) + if (progress) { predicate_following(>cf_node, state); + state->if_nested_return = true; + } return progress; } @@ -91,10 +95,13 @@ lower_returns_in_loop(nir_loop *loop, struct lower_returns_state *state) static bool lower_returns_in_if(nir_if *if_stmt, struct lower_returns_state *state) { - bool progress; + bool progress, then_progress; - progress = lower_returns_in_cf_list(_stmt->then_list, state); - progress = lower_returns_in_cf_list(_stmt->else_list, state) || progress; + bool if_nested_return = state->if_nested_return; + state->if_nested_return = false; + + then_progress = lower_returns_in_cf_list(_stmt->then_list, state); + progress = lower_returns_in_cf_list(_stmt->else_list, state) || then_progress; /* If either of the recursive calls made progress, then there were * returns inside of the body of the if. If we're in a loop, then these @@ -106,8 +113,25 @@ lower_returns_in_if(nir_if *if_stmt, struct lower_returns_state *state) * after a return, we need to predicate everything following on the * return flag. */ - if (progress && !state->loop) - predicate_following(_stmt->cf_node, state); + if (progress && !state->loop) { + if (state->if_nested_return) { + predicate_following(_stmt->cf_node, state); + } else { + /* If there are no nested returns we can just add the instructions to + * the end of the branch that doesn't have the return. + */ + nir_cf_list list; + nir_cf_extract(, nir_after_cf_node(_stmt->cf_node), +nir_after_cf_list(state->cf_list)); + + if (then_progress) +nir_cf_reinsert(, nir_after_cf_list(_stmt->else_list)); + else +nir_cf_reinsert(, nir_after_cf_list(_stmt->then_list)); + } + } + + state->if_nested_return = progress || if_nested_return; return progress; } @@ -221,6 +245,7 @@ nir_lower_returns_impl(nir_function_impl *impl) state.cf_list = >body; state.loop = NULL; state.return_flag = NULL; + state.if_nested_return = false; nir_builder_init(, impl); bool progress = lower_returns_in_cf_list(>body, ); -- 2.9.3 ___ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev
Re: [Mesa-dev] [PATCH 1/2] nir: update nir_lower_returns to only predicate instructions when needed
On Fri, 2016-12-09 at 16:49 +1100, Timothy Arceri wrote: > Unless an if statement contains nested returns we can simply add > any following instructions to the branch without the return. > --- > src/compiler/nir/nir_lower_returns.c | 36 > ++-- > 1 file changed, 30 insertions(+), 6 deletions(-) > > diff --git a/src/compiler/nir/nir_lower_returns.c > b/src/compiler/nir/nir_lower_returns.c > index 8dbea6e..73782a1 100644 > --- a/src/compiler/nir/nir_lower_returns.c > +++ b/src/compiler/nir/nir_lower_returns.c > @@ -30,6 +30,8 @@ struct lower_returns_state { > struct exec_list *cf_list; > nir_loop *loop; > nir_variable *return_flag; > + /* Are there other return statments nested in the current if */ > + bool if_nested_return; > }; > > static bool lower_returns_in_cf_list(struct exec_list *cf_list, > @@ -82,8 +84,10 @@ lower_returns_in_loop(nir_loop *loop, struct > lower_returns_state *state) > * flag set to true. We need to predicate everything following > the loop > * on the return flag. > */ > - if (progress) > + if (progress) { > predicate_following(>cf_node, state); > + state->if_nested_return = true; > + } > > return progress; > } > @@ -91,10 +95,12 @@ lower_returns_in_loop(nir_loop *loop, struct > lower_returns_state *state) > static bool > lower_returns_in_if(nir_if *if_stmt, struct lower_returns_state > *state) > { > - bool progress; > + bool progress, then_progress; > > - progress = lower_returns_in_cf_list(_stmt->then_list, state); > - progress = lower_returns_in_cf_list(_stmt->else_list, state) > || progress; > + state->if_nested_return = false; > + > + then_progress = lower_returns_in_cf_list(_stmt->then_list, > state); > + progress = lower_returns_in_cf_list(_stmt->else_list, state) > || then_progress; > > /* If either of the recursive calls made progress, then there > were > * returns inside of the body of the if. If we're in a loop, > then these > @@ -106,8 +112,26 @@ lower_returns_in_if(nir_if *if_stmt, struct > lower_returns_state *state) > * after a return, we need to predicate everything following on > the > * return flag. > */ > - if (progress && !state->loop) > - predicate_following(_stmt->cf_node, state); > + if (progress && !state->loop) { > + if (state->if_nested_return) { > + predicate_following(_stmt->cf_node, state); > + } else { > + /* If there are no nested returns we can just add the > instructions to > + * the end of the branch that doesn't have the return. > + */ > + nir_cf_list list; > + nir_cf_extract(, nir_after_cf_node(_stmt->cf_node), > +nir_after_cf_list(state->cf_list)); > + assert(!exec_list_is_empty()); I've removed this assert() locally there is no need to assert if the list is empty nir_cf_reinsert() will simply return is thats the case. > + if (then_progress) > +nir_cf_reinsert(, nir_after_cf_list(_stmt- > >else_list)); > + else > +nir_cf_reinsert(, nir_after_cf_list(_stmt- > >then_list)); > + } > + } > + > + if (progress) > + state->if_nested_return = true; > > return progress; > } ___ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev
[Mesa-dev] [PATCH 1/2] nir: update nir_lower_returns to only predicate instructions when needed
Unless an if statement contains nested returns we can simply add any following instructions to the branch without the return. --- src/compiler/nir/nir_lower_returns.c | 36 ++-- 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/src/compiler/nir/nir_lower_returns.c b/src/compiler/nir/nir_lower_returns.c index 8dbea6e..73782a1 100644 --- a/src/compiler/nir/nir_lower_returns.c +++ b/src/compiler/nir/nir_lower_returns.c @@ -30,6 +30,8 @@ struct lower_returns_state { struct exec_list *cf_list; nir_loop *loop; nir_variable *return_flag; + /* Are there other return statments nested in the current if */ + bool if_nested_return; }; static bool lower_returns_in_cf_list(struct exec_list *cf_list, @@ -82,8 +84,10 @@ lower_returns_in_loop(nir_loop *loop, struct lower_returns_state *state) * flag set to true. We need to predicate everything following the loop * on the return flag. */ - if (progress) + if (progress) { predicate_following(>cf_node, state); + state->if_nested_return = true; + } return progress; } @@ -91,10 +95,12 @@ lower_returns_in_loop(nir_loop *loop, struct lower_returns_state *state) static bool lower_returns_in_if(nir_if *if_stmt, struct lower_returns_state *state) { - bool progress; + bool progress, then_progress; - progress = lower_returns_in_cf_list(_stmt->then_list, state); - progress = lower_returns_in_cf_list(_stmt->else_list, state) || progress; + state->if_nested_return = false; + + then_progress = lower_returns_in_cf_list(_stmt->then_list, state); + progress = lower_returns_in_cf_list(_stmt->else_list, state) || then_progress; /* If either of the recursive calls made progress, then there were * returns inside of the body of the if. If we're in a loop, then these @@ -106,8 +112,26 @@ lower_returns_in_if(nir_if *if_stmt, struct lower_returns_state *state) * after a return, we need to predicate everything following on the * return flag. */ - if (progress && !state->loop) - predicate_following(_stmt->cf_node, state); + if (progress && !state->loop) { + if (state->if_nested_return) { + predicate_following(_stmt->cf_node, state); + } else { + /* If there are no nested returns we can just add the instructions to + * the end of the branch that doesn't have the return. + */ + nir_cf_list list; + nir_cf_extract(, nir_after_cf_node(_stmt->cf_node), +nir_after_cf_list(state->cf_list)); + assert(!exec_list_is_empty()); + if (then_progress) +nir_cf_reinsert(, nir_after_cf_list(_stmt->else_list)); + else +nir_cf_reinsert(, nir_after_cf_list(_stmt->then_list)); + } + } + + if (progress) + state->if_nested_return = true; return progress; } -- 2.7.4 ___ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev