On Thu, 24 Oct 2024 02:08:14 GMT, Jasmine Karthikeyan <jkarthike...@openjdk.org> wrote:
>> src/hotspot/share/opto/phaseX.cpp line 2277: >> >>> 2275: >>> 2276: // Try to find an existing version of the same node >>> 2277: Node* existing = _igvn->hash_find_insert(n); >> >> I think it would be easier if you have a switch in `gvn` that says you >> passed the point of doing `Ideal`, moving forward you will probably want to >> have a `IdealLowering` to transform nodes during this phase. `Identity` I >> think is fine since it returns an existing node. > > Ah, do you mean having a method in `Node` that holds the lowering code? I was > originally planning on doing it this way, but I think it would pose some > problems where certain nodes' `Lower()` methods would only be overridden on > certain backends, which would become messy. One of my goals was to keep the > lowering code separate from shared code, so new lowerings could be > implemented by just updating the main `lower_node` function in the backend. > About GVN, I think it makes sense to do it in a separate phase because GVN is > used quite generally whereas lowering is only done once. Since the > `transform_old` function in IGVN is pretty complex as well, I think it's > simpler to just implement `Value()` and GVN separately. Thinking on it more I > think Identity is probably a good idea too, since as you mention it can't > introduce new nodes into the graph. Mainly I wanted to avoid the case where > `Ideal()` could fold a lowered graph back into the original form, causing an > infinite loop. I mean we might want to run another kind of `Ideal` that will replace the normal `Ideal` on a node after its lowering. For example, consider this: vector<int,8> v; u = v.withLane(0, a).withLane(1, b); This will be parsed into: vector<int,8> v; v0 = InsertI(v, 4, a); u = InsertI(v0, 5, b); And can be lowered to: vector<int,8> v; vector<int,4> v1 = VectorExtract(v, 1); v2 = InsertI(v1, 0, a); v0 = VectorInsert(v, 1, v2); vector<int,4> v3 = VectorExtract(v0, 1); v4 = InsertI(v3, 1, b); u = VectorInsert(v0, 1, v4); Which represents this sequence: ymm0; vextracti128 xmm1, ymm0, 1; vpinsrd xmm1, xmm1, a, 0; vinserti128 ymm0, ymm0, xmm1, 1; vextracti128 xmm1, ymm0, 1; vpinsrd xmm1, xmm1, b, 1; vinserti128 ymm0, ymm0, xmm1, 1; As you can imagine this sequence is pretty inefficient, what we really want is: ymm0; vextracti128 xmm1, ymm0, 1; vpinsrd xmm1, xmm1, a, 0; vpinsrd xmm1, xmm1, b, 1; vinserti128 ymm0, ymm0, xmm1, 1; Looking back at the graph, we can `Identity` `v3` into `v2` since it is pretty obvious that we just do an insert and extract from the same place. However, to transform `u = VectorInsert(v0, 1, v4)` into `u = VectorInsert(v, 1, v4)`, we would need an `Ideal`-like transformation to see that we just insert into a location twice and remove the intermediate `VectorInsert`. As a result, in addition to ease of implementation, I think you may extend `PhaseIterGVN` and override its `PhaseGVN::apply_ideal` to return `nullptr` for now, and take advantages of `PhaseIterGVN::optimize` to do the iterative transformation for you. ------------- PR Review Comment: https://git.openjdk.org/jdk/pull/21599#discussion_r1814828100