-
Notifications
You must be signed in to change notification settings - Fork 6.2k
8315066: Add unsigned bounds and known bits to TypeInt/Long #15440
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
Conversation
|
👋 Welcome back qamai! A progress list of the required criteria for merging this PR into |
|
@merykitty The following label will be automatically applied to this pull request:
When this pull request is ready to be reviewed, an "RFR" email will be sent to the corresponding mailing list. If you would like to change these labels, use the /label pull request command. |
|
Regarding duality, I don't really understand the concept of duality used in the type system, from the usage of |
|
The details regarding the transformation in each node:
|
|
@TobiHartmann Thanks a lot for taking a look at this patch. Regarding your questions:
Thanks a lot, |
To be clear, there exists a fairly trivial representation for this particular problem, that to map a value set and the corresponding dual set However, this is pretty backward as I come up with the maps from the meet operation and it simply moves the complexity and burden of correctness from Another problem is that currently the same jdk/src/hotspot/share/opto/ifnode.cpp Line 1012 in 775e22a
Although they may have the same representation, the dual set corresponding to the point Ideally, we can have different types for an integer value set and its corresponding dual set. This is because a value set and a dual set are fundamentally different things and trying to cramp them into one representation space is not mathematically sound. The tradeoff however is that a fairly significant changes to the This is my understanding of the |
Okay, thanks for the details! Let's leave it as is then.
I closed JDK-8311597 as duplicate.
Okay, I leave it to @rose00 to decide if JDK-8001436 should be closed as duplicate then.
Thanks for summarizing. Right, I agree that in this case it's much cleaner to special case the dual types but I don't think that would apply in general to all the types (for example, |
|
@TobiHartmann I have tried your suggestion, it turns out that the interdependence between constraints makes it difficult to tolerate ambiguity in type presentations. Without knowing whether the context is a dual type or not, it is really hard to normalise the constraints, verify them and normalise the widen parameter. What do you think? Thanks. |
|
Thanks for checking, @merykitty. Fair enough, I'm fine with leaving it as-is then. Let's see what other reviewers think. |
|
May someone take a look at this patch, please? |
|
@merykitty this pull request can not be integrated into git checkout improvevalue
git fetch https://git.openjdk.org/jdk.git master
git merge FETCH_HEAD
# resolve conflicts and follow the instructions given by git merge
git commit -m "Merge master"
git push |
|
@merykitty This pull request has been inactive for more than 4 weeks and will be automatically closed if another 4 weeks passes without any activity. To avoid this, simply add a new comment to the pull request. Feel free to ask for assistance if you need help with progressing this pull request towards integration! |
|
May someone give their opinion on this PR, please? Thanks a lot. |
|
@merykitty I've been seeing this PR for a while. I can't promise high priority here, but this looks interesting. It is also a scarily big changeset 😅 A first remark: I would love to see more tests. For example: have some expressions that have certain bits random, and others masked on or off. Then you can have all sorts of ifs with bit checks, that lead to some special if-else code patterns. With an IR rule you can then see if this if gets folded, by checking if the true-block and/or false-block are still present. What do you think? |
|
@eme64 Thanks a lot for looking into this. Do you have any potential patterns in mind? I can come up with random patterns but they seem arbitrary and are most likely to be covered by other IR tests already. |
Yes, it definitely is. If this is deemed a good idea then I would probably split it into patches which deal with different nodes and submit them separately. What do you think? |
|
As you might expect (from an examination of JDK-8001436) I’m very excited to see this work going forward. A very long time ago I worked out tight, cheap estimates for bitwise effects of arithmetic operations, and arithmetic effects for bitwise operators. (BTW, did you know that ‘x^y = x+y-2*(x&y)’? That’s the sort of identity we are working with here.) The overall point is that, if you know both arithmetic and bitwise ranges for operands, you can infer tight arithmetic and bitwise ranges for all common operators. I see you’ve gone farther than I did, adding unsigned ranges as well, and more ops (popc). Excellent, excellent. I have a request, though, and it is the same request as with your work on division strength reduction. The inference rules need to be factored out and separately g-tested. I see equations like this in the middle of the C2 code in this PR: It is hard to demonstrate that this is correct. It cannot be unit-tested separately when it appears like this in the midst of IR transforms. We have had many subtle bugs before from “math inclusions” like this in the middle of the IR optimizer. I believe that formula is PROBABLY correct, because I deeply respect your mathematical ability, but that is not good enough. If someone accidentally changes it (or needs to change it for some maintenance reason), we might not have a math savant handy to re-verify it. We need an executable test to give us confidence. In addition, I personally dislike doing pencil-and-paper proofs of code snippets I have to extract manually from wherever it is to do their work. I would much prefer to see the relevant algorithms factored out in their own source files (if they are subtle, as these are). I like to reason from clean formulas, not from formulas that I had to tear away from their duty stations in the optimizer. I think we need a separate file (header and source) for this set of algorithms. Something like rangeInference.[ch]pp. The API points would take one or two inputs, each represented as a full bundle of range data (hi/lo/uh/ul/zs/os). The would also take an operator name (not one API point per operator, please, but maybe one for unaries and one for binaries). And pass 64-bit ints plus length indicators, rather than doing it more than once for different primitive sizes. For naming the operators I suggest either opto node names (Mul not MulL), or (a non-opto-centric choice) the operator names from the Panama Vector API (JEP 460 at last sighting). The API point would symbolically execute the named op over the given symbolic (ranged) arguments, returning a new set of ranged (by C++ references I assume, or maybe a “little struct” for range tuples). The switch-over-op at the heart of it would be carefully written for clarity, to prove (once and for all) that we know what we are talking about. The gtest would work like my BitTypes demo program, exercising all of the operations through a systematic set of concrete input values and (then) ranges containing those values. We would make sure that (a) the concrete result never “escapes” the predicted range (for any of a series of representative containing ranges). And also, when possible, (b) that the predicted range is “tight” in some good way, probably that the concrete result meets each of its inclusive bounds (for each range data point), for at least one set of concrete inputs. I think this kind of testing work is necessary to ensure that our system can be understood and maintained by more than a few people on the planet. And (although I came up with some of the formulas) I’d personally prefer it that way as well. It would be nice to know that if someone bumps an operator or drops a parenthesis, a unit test will catch the bug, rather than either a PhD student re-analyzing the code, or (more likely) a bug that shows up long after system regression tests. The benefits of these optimizations are, basically, that we can push around many more inferences about bitwise operations and unsigned comparisons, beyond what the original C2 design envisioned for inferences about (signed) arithmetic operations. This in turn will give us CC_NE (a nice thing, finally). Moreover, it will help us infer the low-order bits of loop indexes, something useful for proving alignment (in Panama at least). If applied to the lanes of vector types, it will give us a much more robust set of information about what’s going on in vectorized code. So I’m all for it! But, with unit tests, please… |
|
@rose00 I really appreciate your careful analysis of this patch and your detailed explanations and brilliant suggestions. This patch serves more like a prototype since I have realized that it can be divided into separate patches each of which will do the change on some nodes. The first one I have submitted separately from this patch will implement the capabilities in Thanks a lot for your tremendous support on both this and the other patches. |
|
❗ This change is not yet ready to be integrated. |
|
@merykitty This pull request has been inactive for more than 8 weeks and will be automatically closed if another 8 weeks passes without any activity. To avoid this, simply add a new comment to the pull request. Feel free to ask for assistance if you need help with progressing this pull request towards integration! |
|
@merykitty This pull request has been inactive for more than 16 weeks and will now be automatically closed. If you would like to continue working on this pull request in the future, feel free to reopen it! This can be done using the |
Hi,
This patch adds unsigned bounds and known bits constraints to
TypeIntandTypeLong. This opens more transformation opportunities in an elegant manner as well as helps avoid some ad-hoc rules in Hotspot. The new constraints are applied to identity and value calls of the common nodes (Add, Sub, L/R/URShift, And, Or, Xor, bit counting, Cmp, Bool, ConvI2L/L2I), the detailed ideas for each node will be presented below.In general, a
TypeInt/Longrepresents a set of valuesxthat satisfies:x s>= lo && x s<= hi && x u>= ulo && x u<= uhi && (x & zeros) == 0 && (~x & ones) == 0. These constraints are not independent, e.g. an int that lies in [0, 3] in signed domain must also lie in [0, 3] in unsigned domain and have all bits but the last 2 being unset. As a result, we must normalize the constraints (tighten the constraints so that they are optimal) before constructing aTypeInt/Longinstance.Please kindly review, thanks very much.
Testing
Progress
Warning
Issue
Reviewing
Using
gitCheckout this PR locally:
$ git fetch https://git.openjdk.org/jdk.git pull/15440/head:pull/15440$ git checkout pull/15440Update a local copy of the PR:
$ git checkout pull/15440$ git pull https://git.openjdk.org/jdk.git pull/15440/headUsing Skara CLI tools
Checkout this PR locally:
$ git pr checkout 15440View PR using the GUI difftool:
$ git pr show -t 15440Using diff file
Download this PR as a diff file:
https://git.openjdk.org/jdk/pull/15440.diff
Webrev
Link to Webrev Comment