[NewGVN] After moving an instr to a new class, re-evaluate phi of ops.
After moving an instruction to a new class, its leader could have
changed, which means we might be able to simplify phi of ops involving
it as expression.
Differential D42179
[NewGVN] Re-evaluate phi of ops after moving an instr to new class fhahn on Jan 17 2018, 6:30 AM. Authored by
Details
Diff Detail Event TimelineComment Actions At a glance, i don't believe this is correct. Comment Actions Note also that we mark all operands that are part of the expression as Deps. If the leader of those operands changed, they would already be marked as changed as Users through the addAdditionalUsers part we do. Comment Actions Thanks for the having a look so quickly and thanks for the pointers. I'll have a look there to see why the phi-of-ops is not re-evaluated. In the test case, the following does happen:
Comment Actions What follows is my initial understanding after starting having a look at NewGVN and I am probably missing a couple of things. I would greatly appreciate any thoughts and pointers :) I think the problem is the following: ExpressionToPhiOfOps is used to re-process the phi-of-ops, in case the leader of the symbolic (gvn) expression changed. In the ClassChanged case, we currently re-process any phi-of-ops that where using expression E, as its leader has changed. But by moving I to a new class, the leader of all variable expressions of I might has changed too, e.g. because I was not the leader of the old class. It seems like we are missing this case. So if during phi-of-ops processing, we failed with symbolic (gvn) expression E1(I), and E != E1(I), we do not re-process the phi-of-ops instruction, whereas I think we should re-process all phi-of-ops instructions, which depended on any symbolic expression involving I. "depend" here might be not the best term, I mean the symbolic expression we evaluated in findLeaderForInst.
I think this is a symbolic dependency, rather than an additional use , as it is no operand of the new expressions. Also, it seems like the debug output "New class .... for expression ..." could be misleading in some cases. For example, the code path also gets hit if E is a VariableExpression with an existing class and the value I is just moved to the existing EClass, without the class of E being changed. Comment Actions Yes, that is true, but that case should only occur if we have not created a phi of ops, and need to mark what will happen later.
Yes, but this should be taken care of by the code mentioned, by adding those ops as dependencies on the instruction.
We should not be :)
The phi of ops can only depend on the expressions that exist for the operands, and those expressions change only if the evaluation of the instruction changes. In such a case, the instruction will move classes, and hit the class changed case. It will then mark the operands in the phi of ops as changed, as they are users of that instruction (either additional users, or regular users). If they are symbolically marked, they should get caught by the other mark call in classchanged. Your patch actually just marks the phi of ops expressions as changed *even when all that happened was a leader change, and the class did not change*.
VariableExpressions do not actually have classes on their own, and we'll never store them :) Comment Actions To try to help explain this (and feel free to turn it into a comment in NewGVN), for a phi of ops, let me try to cover the cases. We are trying to transform operations on phis into phis of existing operations. IE add phi(a, b) 5 there are essentially two main cases:
In this case, we mark, symbolically, what expression we were looking for that was missing. If the expression appears, we should re-evaluate the phi of ops. Now, maybe you can think of a case i've missed here. Awesome. I don't claim the invariants are perfect, and it definitely requires a lot of thought to get right, so it's entirely possible i'm wrong :) The code we have is attempting to maintain these invariants. It may be worth writing a phi of ops invariant verifier and see what shakes out. I certainly don't claim this code is perfect, i just want us to push it in the direction of understanding the invariants we need to maintain, maintaining those invariants and verifying we are doing that. I usually try to think through it a bit, then give up and write something to just make the contract we are trying to keep explicit and verify it. Comment Actions Thank you very much for providing such a detailed response, that's really helpful and I really appreciate it :) I'll try to add some additional checks for invariants to pin down where something went wrong. I think either of the following conditions should hold just before the end of the if (ClassChanged || LeaderChanged) { block, for all pairs (E, I) in ExpressionToPhiOfOps:
In other words, if the leader for expression E changes, I should get re-processed. Does that make sense?
It is sufficient to only have the additional markPhiOfOpsChanged(createVariableOrConstant(I)) if ClassChange, but I agree it is quite heavy handed and not complete. Comment Actions
Something stronger should also hold I think: if the leader of any operand of E changes, I should get re-processed. Comment Actions I had a look at how performSymbolicEvaluation adds additional users in case it managed to find existing values that could be used to simplify the value we evaluate. In findLeaderForInst, we evaluate a temporary instruction (based on an original instruction OI). If we find an existing value VE to simplify this temporary instruction, we currently do not track that OI (which the temporary is based on) depends on VE, as checkSimplificationResults only adds additional dependencies for non temporary instructions. But if VE moves classes, the symbolic evaluation could change and thus we might find a suitable leader, but we do not detect that currently. I am probably missing more again, but from your responses I *think* that in that case we should have recorded an additional dependency for OI, to cover that case. It would be great if you could let me know if that makes sense. (The invariant checks I have still need some cleanup...) Comment Actions This approach is definitely wrong. I think I know where we miss the precise dependency in that case and will submit a different patch for it Comment Actions Thanks for all the feedback. Abandoning this change now. rL330334 covers one case where we were missing dependencies. There is at least one other case remaining I think and I will try to post a patch for that soonish. Comment Actions Okay. There is definitely at least 1 cause of value numbers changing after |