-
Notifications
You must be signed in to change notification settings - Fork 18k
cmd/compile: prove pass disabled on int32/int64 #29964
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
Comments
I think this is probably because we extend indexes to int width before we do the bounds check. The code in ssa.go for OINDEX does:
The extra cast probably makes the prove pass give up, because it can't go from We could do the bounds check before the extension. That would fix this problem, probably. I'm not sure what else it would do. Probably it would be fine, it was just easier when first implementing ssa to only deal with one index type during bounds check generation. We do need |
If the only problem here is the prove pass's handling of integer extensions, that's #26292, which has had a CL semi-ready for a while. |
Thanks @mvdan. The pending CL 122695 does not eliminate this bounds check, for what that's worth. |
@randall77, I am not sure I follow completely, but
It should be able to go in two steps, from Is the problem that the prove pass does not explore a "two-step" option |
I believe it's because it doesn't know about the second step at all. That is, it doesn't know anything about sign extensions. |
When testing the negative branch of the offending bounds check, prove asserts that In the int32 case, the inequality being asserted on the negative branch of the bounds check is instead Relevant SSA blocks for
I've found what seems to me like an unobtrusive change that fixes this issue, though it is pretty specific to this case. I'm not sure how complicated a more general solution would be, I have to think about it more. When the bounds check assertion is first produced by addBranchRestrictions(), the value.Op can be checked for an extension, and the underlying value passed-through. After a quick test, this change seems to also rely on the pending CL 122695 referenced above. I have to play with it a bit more to find out exactly why that is. |
Oops, I'd failed previously to account for the sign extension at the first bounds check, where prove needs to learn that CL is forthcoming. |
@randall77, please let me know if moving the |
@zdjones That's a possibility. I don't think it is easy, though. If we did that we'd need to compare, say, a 16-bit index with a 64-bit length. Those instructions don't exist on most (any?) processors. For 32-bit archs, |
I guess we could introduce those mixed-length comparisons in the machine-independent code, then lower them to an extend+compare pair. |
It sounds like that might significantly increase the number of ops and generic rules. |
The patch I've got working sounds far simpler. I'll try to mail it today or tomorrow. |
Change https://golang.org/cl/174309 mentions this issue: |
Change https://golang.org/cl/174704 mentions this issue: |
CL is ready to go in for 1.14. |
Array accesses with index types smaller than the machine word size may involve a sign or zero extension of the index value before bounds checking. Currently, this defeats prove because the facts about the original index value don't flow through the sign/zero extension. This CL fixes this by looking back through value-preserving sign/zero extensions when adding facts via Update and, where appropriate, applying the same facts using the pre-extension value. This fix is enhanced by also looking back through value-preserving extensions within ft.isNonNegative to infer whether the extended value is known to be non-negative. Without this additional isNonNegative enhancement, this logic is rendered significantly less effective by the limitation discussed in the next paragraph. In Update, the application of facts to pre-extension values is limited to cases where the domain of the new fact is consistent with the type of the pre-extension value. There may be cases where this cross-domain passing of facts is valid, but distinguishing them from the invalid cases is difficult for me to reason about and to implement. Assessing which cases to allow requires details about the context and inferences behind the fact being applied which are not available within Update. Additional difficulty arises from the fact that the SSA does not curently differentiate extensions added by the compiler for indexing operations, extensions added by the compiler for implicit conversions, or explicit extensions from the source. Examples of some cases that would need to be filtered correctly for cross-domain facts: (1) A uint8 is zero-extended to int for indexing (a value-preserving zeroExt). When, if ever, can signed domain facts learned about the int be applied to the uint8? (2) An int8 is sign-extended to int16 (value-preserving) for an equality comparison. Equality comparison facts are currently always learned in both the signed and unsigned domains. When, if ever, can the unsigned facts learned about the int16, from the int16 != int16 comparison, be applied to the original int8? This is an alternative to CL 122695 and CL 174309. Compared to CL 122695, this CL differs in that the facts added about the pre-extension value will pass through the Update method, where additional inferences are processed (e.g. fence-post implications, see golang#29964). CL 174309 is limited to bounds checks, so is narrower in application, and makes the code harder to read. Fixes golang#26292. Fixes golang#29964. Removes 238 bounds checks from std/cmd. Change-Id: I1f87c32ee672bfb8be397b27eab7a4c2f304893f
DO NOT SUBMIT Potential alternative/complement to CL 122695 and CL 174309 Fixes golang#26292. Fixes golang#29964. Removes 221 bounds checks from std/cmd, 64 of which are not common to CL 122695. Change-Id: I1f87c32ee672bfb8be397b27eab7a4c2f304893f
Array accesses with index types smaller than the machine word size may involve a sign or zero extension of the index value before bounds checking. Currently, this defeats prove because the facts about the original index value don't flow through the sign/zero extension. This CL fixes this by looking back through value-preserving sign/zero extensions when adding facts via Update and, where appropriate, applying the same facts using the pre-extension value. This fix is enhanced by also looking back through value-preserving extensions within ft.isNonNegative to infer whether the extended value is known to be non-negative. Without this additional isNonNegative enhancement, this logic is rendered significantly less effective by the limitation discussed in the next paragraph. In Update, the application of facts to pre-extension values is limited to cases where the domain of the new fact is consistent with the type of the pre-extension value. There may be cases where this cross-domain passing of facts is valid, but distinguishing them from the invalid cases is difficult for me to reason about and to implement. Assessing which cases to allow requires details about the context and inferences behind the fact being applied which are not available within Update. Additional difficulty arises from the fact that the SSA does not curently differentiate extensions added by the compiler for indexing operations, extensions added by the compiler for implicit conversions, or explicit extensions from the source. Examples of some cases that would need to be filtered correctly for cross-domain facts: (1) A uint8 is zero-extended to int for indexing (a value-preserving zeroExt). When, if ever, can signed domain facts learned about the int be applied to the uint8? (2) An int8 is sign-extended to int16 (value-preserving) for an equality comparison. Equality comparison facts are currently always learned in both the signed and unsigned domains. When, if ever, can the unsigned facts learned about the int16, from the int16 != int16 comparison, be applied to the original int8? This is an alternative to CL 122695 and CL 174309. Compared to CL 122695, this CL differs in that the facts added about the pre-extension value will pass through the Update method, where additional inferences are processed (e.g. fence-post implications, see golang#29964). CL 174309 is limited to bounds checks, so is narrower in application, and makes the code harder to read. Fixes golang#26292. Fixes golang#29964. Fixes golang#15074 Removes 238 bounds checks from std/cmd. Change-Id: I1f87c32ee672bfb8be397b27eab7a4c2f304893f Reviewed-on: https://go-review.googlesource.com/c/go/+/174704 Run-TryBot: Zach Jones <zachj1@gmail.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Giovanni Bajo <rasky@develer.com>
Array accesses with index types smaller than the machine word size may involve a sign or zero extension of the index value before bounds checking. Currently, this defeats prove because the facts about the original index value don't flow through the sign/zero extension. This CL fixes this by looking back through value-preserving sign/zero extensions when adding facts via Update and, where appropriate, applying the same facts using the pre-extension value. This fix is enhanced by also looking back through value-preserving extensions within ft.isNonNegative to infer whether the extended value is known to be non-negative. Without this additional isNonNegative enhancement, this logic is rendered significantly less effective by the limitation discussed in the next paragraph. In Update, the application of facts to pre-extension values is limited to cases where the domain of the new fact is consistent with the type of the pre-extension value. There may be cases where this cross-domain passing of facts is valid, but distinguishing them from the invalid cases is difficult for me to reason about and to implement. Assessing which cases to allow requires details about the context and inferences behind the fact being applied which are not available within Update. Additional difficulty arises from the fact that the SSA does not curently differentiate extensions added by the compiler for indexing operations, extensions added by the compiler for implicit conversions, or explicit extensions from the source. Examples of some cases that would need to be filtered correctly for cross-domain facts: (1) A uint8 is zero-extended to int for indexing (a value-preserving zeroExt). When, if ever, can signed domain facts learned about the int be applied to the uint8? (2) An int8 is sign-extended to int16 (value-preserving) for an equality comparison. Equality comparison facts are currently always learned in both the signed and unsigned domains. When, if ever, can the unsigned facts learned about the int16, from the int16 != int16 comparison, be applied to the original int8? This is an alternative to CL 122695 and CL 174309. Compared to CL 122695, this CL differs in that the facts added about the pre-extension value will pass through the Update method, where additional inferences are processed (e.g. fence-post implications, see golang#29964). CL 174309 is limited to bounds checks, so is narrower in application, and makes the code harder to read. Fixes golang#26292. Fixes golang#29964. Fixes golang#15074 Removes 238 bounds checks from std/cmd. Change-Id: I1f87c32ee672bfb8be397b27eab7a4c2f304893f Reviewed-on: https://go-review.googlesource.com/c/go/+/174704 Run-TryBot: Zach Jones <zachj1@gmail.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Giovanni Bajo <rasky@develer.com>
Consider this program:
The bounds check for x[j-1] can be eliminated: at that point, x[j] did not panic, so j < len(x), and the if statement has also tested j > 0, so 0 <= j-1 < len(x).
The compiler does eliminate this check:
But if I change j to be int32 then the check is not eliminated:
Is this necessary? /cc @aclements
The text was updated successfully, but these errors were encountered: