Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add TailStrategy::Predicate #5856

Merged
merged 20 commits into from
Mar 30, 2021
Merged

Add TailStrategy::Predicate #5856

merged 20 commits into from
Mar 30, 2021

Conversation

dsharletg
Copy link
Contributor

This PR adds a new TailStrategy::Predicate. This is very similar to TailStrategy::GuardWithIf, except it uses predicated loops unconditionally, instead of heuristically choosing based on the target.

On some targets, we think using predicated loads/stores is always faster than scalarizing (Hexagon). On these targets, we can just use predicated loads/stores for TailStrategy::GuardWithIf. On these targets, using TailStrategy::Predicate will not change anything.

On most other targets, predicated loads/stores are expensive (emulated with scalar code). In particular, the cost of inserting and extracting the scalars to/from vectors can be high. On these targets, Halide scalarizes the whole body of the loop instead. This is unfortunate in some cases, when the loop is very expensive, it can be worth the added overhead to assemble the scalarized loads/stores into vectors, so we can vectorize the expensive computation. This PR allows programmers to ask for this with the new tail strategy.

@dsharletg dsharletg requested a review from abadams March 26, 2021 02:48
src/IROperator.h Outdated Show resolved Hide resolved
@abadams
Copy link
Member

abadams commented Mar 26, 2021

The existence of a static Call::as_tag that takes an Expr sort of implies that Tags should be their own IR nodes rather than a call type. What do you think the pros/cons of making Tag a separate IRNode are? E.g. would it duplicate a bunch of code from Call handlers and methods?

@dsharletg
Copy link
Contributor Author

I don't know that Call::as_tag implies tags should be their own IR node. I do think that might make sense regardless.

Pros:

  • The IR node could maintain a list of tags, so the ordering of tags shouldn't matter (in this PR, predicate(likely(x)) is different than likely(predicate(x))...).
  • It would be very slightly easier to get at tags (e.as<Tags>() vs. Call::as_tag(e)), but only very slightly.

Cons:

  • New IR has a lot of overhead. Calls are transparent to most mutators, new IR is not.

I think that con is pretty big, and the pros are pretty small. At the very least, we should make that change in a separate PR I think.

if (call && (call->is_intrinsic(Call::likely) ||
call->is_intrinsic(Call::likely_if_innermost) ||
call->is_intrinsic(Call::strict_float))) {
const Call *call = Call::as_tag(c);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if (const Call *call == Call::as_tag(c)) {

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

call is used below :) I made this change at first and had to revert it for that.

src/Schedule.h Outdated Show resolved Hide resolved
@dsharletg dsharletg merged commit 3e59294 into master Mar 30, 2021
@dsharletg dsharletg deleted the dsharletg/predicate-tail branch March 30, 2021 23:26
steven-johnson added a commit that referenced this pull request Mar 31, 2021
Bug injected in #5856: the change in Simplify_Let.cpp was inadvertently stripping `strict_float()` calls that wrapped the RHS of a Let-expr, which can change results nontrivially in some cases. I don't think a new test for this fix is practical -- it would be a little fragile, as it would rely on the specifics of simplification that could change over time.

As a drive-by, also added an explicit rule to Simplify_Call to ensure that strict_float(strict_float(x)) -> strict_float(x) in *all* cases. (The existing rule didn't do this in all cases.)

Also added an assertion to Codegen_LLVM.cpp that no calls of the form strict_float(strict_float(x)) should ever be seen at that point.
steven-johnson added a commit that referenced this pull request Mar 31, 2021
* Don't strip strict_float() from lets

Bug injected in #5856: the change in Simplify_Let.cpp was inadvertently stripping `strict_float()` calls that wrapped the RHS of a Let-expr, which can change results nontrivially in some cases. I don't think a new test for this fix is practical -- it would be a little fragile, as it would rely on the specifics of simplification that could change over time.

As a drive-by, also added an explicit rule to Simplify_Call to ensure that strict_float(strict_float(x)) -> strict_float(x) in *all* cases. (The existing rule didn't do this in all cases.)
@alexreinking alexreinking added this to the v12.0.0 milestone May 19, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants