This patch fixes the CorrelatedValuePropagation pass to keep prof branch_weights metadata of SwitchInst consistent.
It makes use of SwitchInstProfUpdateWrapper introduced in D62122.
A new test is added.
Details
- Reviewers
nikic reames davide - Commits
- rGa3e16719c46a: Resubmit "[CorrelatedValuePropagation] Fix prof branch_weights metadata…
rL362583: Resubmit "[CorrelatedValuePropagation] Fix prof branch_weights metadata…
rG53f2f3286572: [CorrelatedValuePropagation] Fix prof branch_weights metadata handling for…
rL361808: [CorrelatedValuePropagation] Fix prof branch_weights metadata handling for…
Diff Detail
Event Timeline
llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp | ||
---|---|---|
398 | I think that something can go wrong here... Consider a case where we have a switch with branch weights, then we remove the first case (so that Changed=true in SwitchInstProfBranchWeightsWrapper), then we find that the second case is always true, such that this constant folding call will erase the switch, leaving behind a dangling reference in SwitchInstProfBranchWeightsWrapper, which will be accessed when the destructor runs at the end of the function. |
llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp | ||
---|---|---|
398 | Good catch! |
- renamed SwitchInstProfBranchWeightsWrapper to SwitchInstProfUpdateWrapper
- explicitly narrowed scope of the SwitchInstProfUpdateWrapper object so it does not overlap with ConstantFoldTerminator()
- added a test case where switch turns into conditional branch
This looks ok, but I wonder if it might make sense to have an explicit update() method for cases (like this) where we need to control the point where the SwitchInst is updated. Something like:
void update() { if (Changed) SI.setMetadata(LLVMContext::MD_prof, buildProfBranchWeightsMD()); Changed = false; } ~SwitchInstProfUpdateWrapper() { update(); }
I feel like this might be more obvious than extra scopes to control the destruction point.
I considered this way and found it error prone. The wrapper stays alive after ConstantFoldTerminator() and developer may accidentally reuse it but the stored weights might be unsync with the underlying SwitchInst's weights changed by ConstantFoldTerminator().
LGTM
llvm/test/Transforms/CorrelatedValuePropagation/profmd.ll | ||
---|---|---|
50 | These check lines should probably be positioned one block higher? |
FYI, we're seeing a crash in llvm::SwitchInstProfUpdateWrapper::getProfBranchWeights() following this patch.
I'm trying to get a testcase available.
My guess would be that this is due to the assumption of valid branch_weights inside https://github.com/llvm-mirror/llvm/blob/2015c9266833ebae0e42a641252b2b120ef0f77a/lib/IR/Instructions.cpp#L3908, which is not a guarantee we have at this point.
Providing an obviously incorrect branch_weights for one of the added test cases is enough to cause an assertion failure:
define i32 @crash(i32 %s) { entry: %cmp = icmp sgt i32 %s, 0 br i1 %cmp, label %positive, label %out positive: switch i32 %s, label %out [ i32 1, label %next i32 -1, label %next i32 -2, label %next ], !prof !{!"branch_weights"} ; not enough elements out: %p = phi i32 [ -1, %entry ], [ 1, %positive ] ret i32 %p next: %q = phi i32 [ 0, %positive ], [ 0, %positive ], [ 0, %positive ] ret i32 %q }
Thank you very much for the revert, the analysis and the test.
I'm going make the wrapper class safe by introducing invalid sticky state.
I think that something can go wrong here... Consider a case where we have a switch with branch weights, then we remove the first case (so that Changed=true in SwitchInstProfBranchWeightsWrapper), then we find that the second case is always true, such that this constant folding call will erase the switch, leaving behind a dangling reference in SwitchInstProfBranchWeightsWrapper, which will be accessed when the destructor runs at the end of the function.