This is an archive of the discontinued LLVM Phabricator instance.

[NewGVN] Add test with assume dominating an ICmp. NFC
AbandonedPublic

Authored by gandhi21299 on Jul 2 2023, 1:38 PM.

Diff Detail

Event Timeline

gandhi21299 created this revision.Jul 2 2023, 1:38 PM
gandhi21299 requested review of this revision.Jul 2 2023, 1:38 PM
Herald added a project: Restricted Project. · View Herald TranscriptJul 2 2023, 1:38 PM
nikic added a comment.Jul 2 2023, 1:40 PM

After @arsenm's change, InstSimplify should no longer work with instructions without parent. Can you explain how we end up working on an assume without parent in NewGVN? It's not really obvious to me.

After @arsenm's change, InstSimplify should no longer work with instructions without parent. Can you explain how we end up working on an assume without parent in NewGVN? It's not really obvious to me.

I traced back the calls and they start from NewGVN::ExprResult NewGVN::performSymbolicEvaluation(Value *V, SmallPtrSetImpl<Value *> &Visited) const . I tried inserting the getParent() check in various places in NewGVN but it causes 5 LIT tests to fail for generating a few more basic blocks.

nikic added a reviewer: fhahn.Jul 2 2023, 2:28 PM

I believe this is related to the "phi of op" feature in NewGVN: https://github.com/llvm/llvm-project/blob/6954cb54252b50df95eea05c513e739b3ad2c8a0/llvm/lib/Transforms/Scalar/NewGVN.cpp#L2767 These cloned instructions won't have a parent.

I'm not entirely sure what to do here. I don't think that this fix is sufficient: If we need support for instructions without parent for NewGVN, then we need to revert @arsenm's change entirely, not just this part. Alternatively we need a different way to handle this on the NewGVN side. It may be possible to insert the instructions, as long as we are sure to later remove them again. I'm not sure if this would cause problems with NewGVNs design though, which is not supposed to do IR modifications during the analysis phase.

fhahn added a comment.Jul 3 2023, 5:56 AM

I believe this is related to the "phi of op" feature in NewGVN: https://github.com/llvm/llvm-project/blob/6954cb54252b50df95eea05c513e739b3ad2c8a0/llvm/lib/Transforms/Scalar/NewGVN.cpp#L2767 These cloned instructions won't have a parent.

I'm not entirely sure what to do here. I don't think that this fix is sufficient: If we need support for instructions without parent for NewGVN, then we need to revert @arsenm's change entirely, not just this part. Alternatively we need a different way to handle this on the NewGVN side. It may be possible to insert the instructions, as long as we are sure to later remove them again. I'm not sure if this would cause problems with NewGVNs design though, which is not supposed to do IR modifications during the analysis phase.

NewGVN makes use of instructions without parents in multiple places; I'm surprised that there isn't more fallout from this. I am not sure if inserting the instructions in the existing IR would work well, but inserting them in a temporary block may work as workaround.

nikic added a comment.Jul 7 2023, 1:59 AM

I believe this is related to the "phi of op" feature in NewGVN: https://github.com/llvm/llvm-project/blob/6954cb54252b50df95eea05c513e739b3ad2c8a0/llvm/lib/Transforms/Scalar/NewGVN.cpp#L2767 These cloned instructions won't have a parent.

I'm not entirely sure what to do here. I don't think that this fix is sufficient: If we need support for instructions without parent for NewGVN, then we need to revert @arsenm's change entirely, not just this part. Alternatively we need a different way to handle this on the NewGVN side. It may be possible to insert the instructions, as long as we are sure to later remove them again. I'm not sure if this would cause problems with NewGVNs design though, which is not supposed to do IR modifications during the analysis phase.

NewGVN makes use of instructions without parents in multiple places; I'm surprised that there isn't more fallout from this.

This probably went unnoticed because we only assert that the instruction is inserted in the primary simplifyInstruction() entry point, but not the helpers for individual instruction types.

I am not sure if inserting the instructions in the existing IR would work well, but inserting them in a temporary block may work as workaround.

This seems like it might result in incorrect folds based on dominance relationships, especially is the temporary block is not connected to the CFG.

arsenm added a comment.Jul 7 2023, 6:43 AM

The problems I ran into were from missing the parent context function. If we had the context function passed in separately from the instruction, I think it would matter less if they were attached to a block

Inserting the cloned instruction ValueOp after I at https://github.com/llvm/llvm-project/blob/6954cb54252b50df95eea05c513e739b3ad2c8a0/llvm/lib/Transforms/Scalar/NewGVN.cpp#L2767 incorrectly deduces values in tests involving PHI of ops.

Allen added a subscriber: Allen.Jul 26 2023, 12:59 AM

Perhaps we could add this case as a check to OpIsSafeForPHIOfOps. While walking the operands we could check if they are used in an assume until we hit a dominator. Not sure this makes complete sense, but we already do something similar to prevent InstSimplify from code walking through non-dominating phis.

@kmitropoulou noted that the PHI of ops transformation in the test is completely valid. This test might be a nice addition with llvm.assume() intrinsic in the LIT test suite.

gandhi21299 retitled this revision from [InstructionSimplify] Avoid simplifying ICmp without parent to [NewGVN] Add test with assume dominating an ICmp. NFC.Aug 12 2023, 9:30 PM
gandhi21299 edited the summary of this revision. (Show Details)

I don't think doing phi-of-ops on the following is valid :

%f.0 = phi i32 [ undef, %entry ], [ %xor, %if.then ], [ %xor, %if.then2 ]
...
%tobool9.not = icmp eq i32 %f.0, 0

entry:
%tobool9.not = icmp eq i32 undef, 0 -> undef 

if.then:
%tobool9.not = icmp eq i32 %xor, 0 -> false (wrong! No way of knowing this!)

if.then2:
%tobool9.not = icmp eq i32 %xor, 0 -> false ( correct!! From the assume)


%tobool9.not -> phi [undef, false, false] -> false ( wrong because of if.then value)

Alive2 proof: https://alive2.llvm.org/ce/z/V5ANuZ
Am I misunderstanding something?

arsenm added inline comments.Aug 14 2023, 2:22 PM
llvm/test/Transforms/NewGVN/assume-dominating-icmp.ll
5

Do you need the local_unnamed_addr and dso_local?

gandhi21299 abandoned this revision.Aug 14 2023, 2:35 PM

@kmitropoulou will take over with a new revision.

@ManuelJBrito You are right :) I missed this. NewGVN checks if it can simplify icmp eq i32 %xor, 0. For this reason, it calls simplifyICmpInst() from InstructionSimplify.cpp. This function tries to find if the compare is dependent on a llvm.assume() intrinsic. Hence, it calls isValidAssumeForContext() which returns true for both cases! The isValidAssumeForContext() checks if the llvm.assume() dominates the icmp eq i32 %xor, 0. The problem is that icmp eq i32 %xor, 0 does not have a parent. Because of that, dominates() get confused that icmp eq i32 %xor, 0 is part of an unreachable block and it returns true.