This is an archive of the discontinued LLVM Phabricator instance.

[SCCP] Replace valuestate.isConstant with helper isConstant
Needs ReviewPublic

Authored by StephenFan on Jun 25 2023, 12:10 AM.

Details

Reviewers
nikic
nlopes
fhahn
Summary

With this patch, simplifyBinOp in visitBinaryInst may return
PoisonValue. So this patch also introduce a poison tag to ValueLattice
to handle poison constant.

Diff Detail

Event Timeline

StephenFan created this revision.Jun 25 2023, 12:10 AM
Herald added a project: Restricted Project. · View Herald TranscriptJun 25 2023, 12:10 AM
Herald added a subscriber: hiraditya. · View Herald Transcript
StephenFan requested review of this revision.Jun 25 2023, 12:10 AM
Herald added a project: Restricted Project. · View Herald TranscriptJun 25 2023, 12:10 AM
nikic added a comment.Jun 25 2023, 4:14 AM

This only makes a difference when the binop returns a poison result, right? I think it's unfortunate that this ends up replacing that with an undef value.

I think it would be good to introduce a new lattice value for poison, which allows us to explicitly represent this and avoid refining poison to undef. Especially in conjunction with D153718, which is kind of weird in we claim no undefs but the result is represented as undef.

This only makes a difference when the binop returns a poison result, right? I think it's unfortunate that this ends up replacing that with an undef value.

Exactly. Replace a poison value with an undef value is not a good idea, because As LangRef says, PoisonValue is stronger than UndefValue, it enables more optimizations. But actually, I really don't understand that, or in other words, I can't find an example to convince myself. Do you @nikic know that or do you mind telling me the answer? :)

I think it would be good to introduce a new lattice value for poison, which allows us to explicitly represent this and avoid refining poison to undef. Especially in conjunction with D153718, which is kind of weird in we claim no undefs but the result is represented as under.

This is a good idea. Or I also had an idea that we don't need the undef enum in ValueLattice, because no matter UndefValue or PoisonValue, they are all constant. And when we visit instructions in SCCPSolver, we should do instructionsimplify for instructions that one of their operands is constant. If we want to judge if a valuelattice is undef, we can just judge like isa<UndefValue>(ConstVal). What's your @nikic opinion?

nikic added a comment.Jun 27 2023, 1:08 AM

This only makes a difference when the binop returns a poison result, right? I think it's unfortunate that this ends up replacing that with an undef value.

Exactly. Replace a poison value with an undef value is not a good idea, because As LangRef says, PoisonValue is stronger than UndefValue, it enables more optimizations. But actually, I really don't understand that, or in other words, I can't find an example to convince myself. Do you @nikic know that or do you mind telling me the answer? :)

For example and i32 %x, poison is poison, but and i32 %x, undef is not undef (it would be folded to i32 0).

I think it would be good to introduce a new lattice value for poison, which allows us to explicitly represent this and avoid refining poison to undef. Especially in conjunction with D153718, which is kind of weird in we claim no undefs but the result is represented as under.

This is a good idea. Or I also had an idea that we don't need the undef enum in ValueLattice, because no matter UndefValue or PoisonValue, they are all constant. And when we visit instructions in SCCPSolver, we should do instructionsimplify for instructions that one of their operands is constant. If we want to judge if a valuelattice is undef, we can just judge like isa<UndefValue>(ConstVal). What's your @nikic opinion?

I think the reason for the separate undef state is to make sure it does not accidentally get treated like a constant. The core problem is that SCCP allows a lattice transition undef -> C (which basically only exists to support phi nodes with undef operands). So if you initially folded some operation using undef as op(undef) = C2 (which makes an implicit choice of undef) and then transition undef -> C, then op(C) = C3 where possibly C2 != C3. This would violate the lattice structure.

StephenFan updated this revision to Diff 536738.Jul 3 2023, 6:13 AM
StephenFan retitled this revision from [SCCP] replace valuestate.isConstant with helper isConstant to [SCCP] Replace valuestate.isConstant with helper isConstant.
StephenFan edited the summary of this revision. (Show Details)

Introduce poison tag to ValueLattice.

This only makes a difference when the binop returns a poison result, right? I think it's unfortunate that this ends up replacing that with an undef value.

Exactly. Replace a poison value with an undef value is not a good idea, because As LangRef says, PoisonValue is stronger than UndefValue, it enables more optimizations. But actually, I really don't understand that, or in other words, I can't find an example to convince myself. Do you @nikic know that or do you mind telling me the answer? :)

For example and i32 %x, poison is poison, but and i32 %x, undef is not undef (it would be folded to i32 0).

Thanks for your detailed explanation!

I think it would be good to introduce a new lattice value for poison, which allows us to explicitly represent this and avoid refining poison to undef. Especially in conjunction with D153718, which is kind of weird in we claim no undefs but the result is represented as under.

This is a good idea. Or I also had an idea that we don't need the undef enum in ValueLattice, because no matter UndefValue or PoisonValue, they are all constant. And when we visit instructions in SCCPSolver, we should do instructionsimplify for instructions that one of their operands is constant. If we want to judge if a valuelattice is undef, we can just judge like isa<UndefValue>(ConstVal). What's your @nikic opinion?

I think the reason for the separate undef state is to make sure it does not accidentally get treated like a constant. The core problem is that SCCP allows a lattice transition undef -> C (which basically only exists to support phi nodes with undef operands). So if you initially folded some operation using undef as op(undef) = C2 (which makes an implicit choice of undef) and then transition undef -> C, then op(C) = C3 where possibly C2 != C3. This would violate the lattice structure.

This is indeed the problem. Maybe we can use SimplifyQuery(DL).getWithoutUndef() as a query wrapper to avoid this situation.

nikic added inline comments.Jul 28 2023, 2:52 AM
llvm/lib/Transforms/Utils/SCCPSolver.cpp
1235

Shouldn't we propagate poison here and in similar cases (by going through the Constant path)?

StephenFan added inline comments.Aug 7 2023, 12:52 AM
llvm/lib/Transforms/Utils/SCCPSolver.cpp
1235

Yes. But currently SCCPSolver::getConstant(ValueLatticeElement) doesn't support get undef or poison constant values. And undef or poison are represented in SCCPSolver just by the enum tags which don't have the type information to construct UndefValue or PoisonValue. To support this, we should record the undef or poison in ConstVal instead of just representing it by tags.

nikic added inline comments.Aug 7 2023, 12:54 AM
llvm/lib/Transforms/Utils/SCCPSolver.cpp
1235

Since recently getConstant() also takes the type, so you can materialize a PoisonValue with the correct type there.