Skip to content

Handle a gap while matching SIL patterns for hoisting array bound checks #65573

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

Merged
merged 1 commit into from
May 10, 2023

Conversation

meg-gupta
Copy link
Contributor

Enables hoisting bounds checks from simple loops like :
for i in 0...4 { ...a[i]... }

@meg-gupta
Copy link
Contributor Author

@swift-ci test

return nullptr;
}

AsArg = dyn_cast<SILArgument>(Builtin->getArguments()[0]);
Copy link
Contributor

Choose a reason for hiding this comment

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

Don't you need to check if the second argument is a loop-invariant constant?
And handle that in isZeroCount and hoistCheckToPreheader?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I thought it was okay because InductionAnalysis bails out for values that are not integer constant 1 ? https://github.com/apple/swift/blob/dd813af0a7670f420d30aa95326863fbb772463a/lib/SILOptimizer/LoopTransforms/ArrayBoundsCheckOpts.cpp#L650

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'll write some tests for this case.

Copy link
Contributor

@eeckstein eeckstein May 3, 2023

Choose a reason for hiding this comment

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

I see, the dyn_cast<SILArgument> makes sure that the add-builtin is matching the increment of the induction variable. Can you add a comment which makes that clear?

Alternatively, you can replace that argument check with a constant-check of the second argument (as I suggested). Then the optimization could also handle loops like

for i in 0..<10 {
  a[i + c] // c is a constant
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@eeckstein I'll add the increment by other constants in a different PR. There are other unhandled patterns as well. Eg: Local array patterns

@meg-gupta
Copy link
Contributor Author

@swift-ci test

@meg-gupta
Copy link
Contributor Author

@swift-ci Please Apple Silicon benchmark

return %t : $()
}

// RANGECHECK-LABEL: sil @hoist_new_ind_pattern2 :
Copy link
Contributor

Choose a reason for hiding this comment

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

Could you add the pseudo-code for hoist_new_ind_pattern2 so we can see what's being tested and add comments on why incrementing by two prevents bounds check elimination?

// {
// index = index + index
// ...a[index]...
// }
Copy link
Contributor

Choose a reason for hiding this comment

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

Could you add a comment on why bounds check hoisting fails for hoist_new_ind_pattern3?

}

auto *Builtin = dyn_cast<BuiltinInst>(TupleExtract->getOperand());
if (!Builtin || Builtin->getBuiltinKind() != BuiltinValueKind::SAddOver) {
Copy link
Contributor

Choose a reason for hiding this comment

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

It isn't clear to me whether the meaning of getLinearFunction changes depending on whether the bounds check is on the preincremented or postincremented induction variable. I think that needs to be specified. I suggest testing the boundary conditions to be sure there is no off-by-one bug.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, there is a off-by-one bug. So far, the AccessFunction was the identity function. But with your change it can add the offset of the increment. You need to add that info to AccessFunction.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks! I'll fix this

Copy link
Contributor

Choose a reason for hiding this comment

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

Can you also add a check in your tests for this?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@eeckstein I added check lines with the bounds check now

}

auto *Builtin = dyn_cast<BuiltinInst>(TupleExtract->getOperand());
if (!Builtin || Builtin->getBuiltinKind() != BuiltinValueKind::SAddOver) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, there is a off-by-one bug. So far, the AccessFunction was the identity function. But with your change it can add the offset of the increment. You need to add that info to AccessFunction.

return nullptr;
}

AsArg = dyn_cast<SILArgument>(Builtin->getArguments()[0]);
Copy link
Contributor

@eeckstein eeckstein May 3, 2023

Choose a reason for hiding this comment

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

I see, the dyn_cast<SILArgument> makes sure that the add-builtin is matching the increment of the induction variable. Can you add a comment which makes that clear?

Alternatively, you can replace that argument check with a constant-check of the second argument (as I suggested). Then the optimization could also handle loops like

for i in 0..<10 {
  a[i + c] // c is a constant
}

@meg-gupta
Copy link
Contributor Author

@swift-ci test

// RANGECHECK: [[ZERO:%.*]] = integer_literal $Builtin.Int32, 0
// RANGECHECK: [[INTZERO:%.*]] = struct $Int32 ([[ZERO]] : $Builtin.Int32)
// RANGECHECK: [[FOUR:%.*]] = integer_literal $Builtin.Int32, 4
// RANGECHECK: [[A1:%.*]] = apply [[CB]]([[INTZERO]], [[TRUE]], %0) : $@convention(method) (Int32, Bool, @owned ArrayInt) -> _DependenceToken
Copy link
Contributor

Choose a reason for hiding this comment

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

Wait, shouldn't this be 1? The constant increment must also be added to the lower-bound range check value.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, you are right. I added the fix. Thank you

@meg-gupta
Copy link
Contributor Author

@swift-ci test

Copy link
Contributor

@eeckstein eeckstein left a comment

Choose a reason for hiding this comment

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

lgtm!

@meg-gupta meg-gupta merged commit 6c299ad into swiftlang:main May 10, 2023
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.

3 participants