This is an alternative to D98391/D98585, playing things more conservatively. If AllowRefinement == false, then we don't use InstSimplify methods at all, and instead explicitly implement some non-refining folds. Most cases are handled by constant folding, and I only had to add two folds to cover our test cases. While this may lose some optimization power, I think it is safer to approach from this direction, given how many issues this has already caused.
Details
Diff Detail
Event Timeline
It is impressive that leaving the few patterns was enough to cover all existing unit tests.
If more patterns are needed, we can factor out the non-refined foldings from SimplifyXXInst as a static function and call it here.
Since ConstantFoldInstOperands can return a refined value as well, I gave a shot and disabled the folding if AllowRefinement = false.
However, it resulted in many unit test failures (implying that it will prevent a lot of optimizations). I couldn't write an input that involves constant folding but results in miscompilation either; so I think it is fine.
LGTM, but it would be good if someone else can double-check the diffs as well.
llvm/lib/Analysis/InstructionSimplify.cpp | ||
---|---|---|
4042 | This might make the result more refined as well, is it? ConstantFoldBinaryInstruction may fold undef/poison into a well-defined value. |
LGTM - but see inline for general question/comment.
llvm/lib/Analysis/InstructionSimplify.cpp | ||
---|---|---|
3935–3936 | I lost track of exactly what we mean by "refinement". The existing example in the code comment below + the test diffs in this patch suggest it is something like: It can be independent of this patch, but we should make "refinement" clearer in the code comments here or in the header file comment where SimplifyWithOpReplaced() is declared. |
Add fold for binop + identity element. This is the only other relevant fold I found in test-suite. Shuffle comments a bit.
llvm/lib/Analysis/InstructionSimplify.cpp | ||
---|---|---|
3935–3936 | Refinement means making a replacement like poison -> 0. This is legal. The select transform in question will take the simplification result (0) and replace it with the original instruction (poison). If the original simplification was a refinement, then this is a de-refinement, which is not legal. We can only make replacements that are valid in both directions, which requires the simplification result to be identical to the input. I believe the select optimization is the only place where we try to do something like this. | |
4042 | There is a TODO For this in the canCreatePoison comment, but it ended up a bit far from the code it affects. I've moved it directly before the constant folding code now, which is hopefully clearer. |
llvm/lib/Analysis/InstructionSimplify.cpp | ||
---|---|---|
4019–4020 | ok, looks good. |
I lost track of exactly what we mean by "refinement". The existing example in the code comment below + the test diffs in this patch suggest it is something like:
"Substitution with another value can't let poison flow where it did not before." ?
Are we getting in trouble with selects only or are there other opcodes with problems?
It can be independent of this patch, but we should make "refinement" clearer in the code comments here or in the header file comment where SimplifyWithOpReplaced() is declared.