RFR: 8346664: C2: Optimize mask check with constant offset
Emanuel Peter
epeter at openjdk.org
Fri Jan 17 14:53:02 UTC 2025
On Wed, 8 Jan 2025 13:37:43 GMT, Matthias Ernst <duke at openjdk.org> wrote:
>> src/hotspot/share/opto/mulnode.cpp line 2063:
>>
>>> 2061:
>>> 2062: // Returns a lower bound on the number of trailing zeros in expr.
>>> 2063: static jint AndIL_min_trailing_zeros(const PhaseGVN* phase, const Node* expr, BasicType bt) {
>>
>> Is this method restricted to use in AndIL? Because it looks like it is doing something more generic: trying to figure out a lower bound on the trailing zeros of an expression.
>>
>> If that is the case: Why not put it in `Node::get_trailing_zeros_lower_bound(phase, bt)`, so it can be used elsewhere too?
>
> I would argue that while this might be incidentally reusable outside of the scope of "And" nodes, as long as there is no actual demand to reuse this, I would rather not add it to the rather prominent Node class to avoid api bloat.
>
> Iff the notion of "is known to be a multiple of a certain power of two" is really of general interest, I would expect it to become part of `TypeInteger`.
Sure, just leave it where it is for now. I'm ok with it.
>> test/hotspot/jtreg/compiler/c2/irTests/TestShiftAndMask.java line 221:
>>
>>> 219: }
>>> 220: }
>>> 221:
>>
>> Nice to see that you have some examples here!
>>
>> I think it would be great to have some more though. The divil hides in the details. In the edge cases usually.
>>
>> You currently have patterns like this:
>> `(j + ((i + c1) << c2)) & c3;`
>> What if you generate the constants `c1, c2, c3` randomly:
>> `public static final int C1 = random.nextInt()` (or some other random distribution that makes more sense).
>> Then the compiler will see them as constants (because final), and attempt constant folding.
>>
>> You can then do result verification: You create a method copy that you restrict to the interpreter, and the other copy can be compiled. Then you test the method with all sorts of random inputs for `i, j`, and verify the results of the two methods (compiled vs interpreted).
>>
>> Maybe you can add some more patterns as well, just to have a better test coverage.
>>
>> Does that make sense?
>
> I believe I understand the intent, and I've now randomized all constant masks / shifts / consts in this file. But just to make sure: IIUC the tests are only compiled once per invocation, there is no way I can tell the framework to "C2 compile this x times with different random constants". I.e. I can `make test` this a hundred times locally, but I cannot create large coverage via the framework, right?
>
> Also not quite sure I understand the verification proposal. How would that be different from the current comparisons `if (result != expected simplified form)` ? Now if the framework supported an automatic comparison of compiled vs interpreted invocation, that would be nice.
Yeah, creating large coverage with a single run under the IR framework is not currently possible I think.
Generally, there are other tricks to get "changing constants", see what I did with `setConstant` and `int_con` in this test:
`test/hotspot/jtreg/compiler/loopopts/superword/TestAlignVectorFuzzer.java`
But the tests are rerun a lot anyway, so that is not super necessary.
I am working on a Template framework that makes using random constants much easier, and also generating multiple methods where only the constants differ. That should make things a little easier.
I suppose that works: `if (result != expected simplified form)`
Though only for cases where we have a valid simplification. If you also want to test the cases that have a very similar pattern, but should not accidentally wrongly optimize, then you would have to do the compiled/interpreted comparison.
-------------
PR Review Comment: https://git.openjdk.org/jdk/pull/22856#discussion_r1907431017
PR Review Comment: https://git.openjdk.org/jdk/pull/22856#discussion_r1907428608
More information about the hotspot-compiler-dev
mailing list