Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[InstCombine] Fold switch(zext/sext(X)) into switch(X) #76988

Merged
merged 2 commits into from
Jan 5, 2024

Conversation

dtcxzyw
Copy link
Member

@dtcxzyw dtcxzyw commented Jan 4, 2024

This patch folds switch(zext/sext(X)) into switch(X).
The original motivation of this patch is to optimize a pattern found in cvc5. For example:

  %bf.load.i = load i16, ptr %d_kind.i, align 8
  %bf.clear.i = and i16 %bf.load.i, 1023
  %bf.cast.i = zext nneg i16 %bf.clear.i to i32
  switch i32 %bf.cast.i, label %if.else [
    i32 335, label %if.then
    i32 303, label %if.then
  ]

if.then:                                          ; preds = %entry, %entry
  %d_children.i.i = getelementptr inbounds %"class.cvc5::internal::expr::NodeValue", ptr %0, i64 0, i32 3
  %cmp.i.i.i.i.i = icmp eq i16 %bf.clear.i, 1023
  %cond.i.i.i.i.i = select i1 %cmp.i.i.i.i.i, i32 -1, i32 %bf.cast.i

%cmp.i.i.i.i.i always evaluates to false because %bf.clear.i can only be 335 or 303.
Folding switch i32 %bf.cast.i to switch i16 %bf.clear.i will help CVP to handle this case.
See also #76928 (comment).

Compile-time impact: http://llvm-compile-time-tracker.com/compare.php?from=7954c57124b495fbdc73674d71f2e366e4afe522&to=502b13ed34e561d995ae1f724cf06d20008bd86f&stat=instructions:u

stage1-O3 stage1-ReleaseThinLTO stage1-ReleaseLTO-g stage1-O0-g stage2-O3 stage2-O0-g stage2-clang
+0.03% +0.06% +0.07% +0.00% -0.02% -0.03% +0.02%

@llvmbot
Copy link
Collaborator

llvmbot commented Jan 4, 2024

@llvm/pr-subscribers-llvm-transforms

Author: Yingwei Zheng (dtcxzyw)

Changes

This patch folds switch(zext/sext(X)) into switch(X).
The original motivation of this patch is to optimize a pattern found in cvc5. For example:

  %bf.load.i = load i16, ptr %d_kind.i, align 8
  %bf.clear.i = and i16 %bf.load.i, 1023
  %bf.cast.i = zext nneg i16 %bf.clear.i to i32
  switch i32 %bf.cast.i, label %if.else [
    i32 335, label %if.then
    i32 303, label %if.then
  ]

if.then:                                          ; preds = %entry, %entry
  %d_children.i.i = getelementptr inbounds %"class.cvc5::internal::expr::NodeValue", ptr %0, i64 0, i32 3
  %cmp.i.i.i.i.i = icmp eq i16 %bf.clear.i, 1023
  %cond.i.i.i.i.i = select i1 %cmp.i.i.i.i.i, i32 -1, i32 %bf.cast.i

%cmp.i.i.i.i.i always evaluates to false because %bf.clear.i can only be 335 or 303.
Folding switch i32 %bf.cast.i to switch i16 %bf.clear.i will help CVP to handle this case.
See also #76928 (comment).


Full diff: https://github.com/llvm/llvm-project/pull/76988.diff

4 Files Affected:

  • (modified) llvm/lib/Transforms/Utils/SimplifyCFG.cpp (+34)
  • (modified) llvm/test/Transforms/SimplifyCFG/suppress-zero-branch-weights.ll (+5-5)
  • (modified) llvm/test/Transforms/SimplifyCFG/switch-masked-bits.ll (+5-5)
  • (added) llvm/test/Transforms/SimplifyCFG/switch-simplify-cond.ll (+159)
diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
index 61d891d65346bd..399153b442f936 100644
--- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
@@ -7009,6 +7009,37 @@ static bool simplifySwitchOfPowersOfTwo(SwitchInst *SI, IRBuilder<> &Builder,
   return true;
 }
 
+// Fold switch(zext/sext(X)) into switch(X) if possible.
+static bool simplifySwitchCondition(SwitchInst *SI) {
+  Value *X;
+  if (match(SI->getCondition(), m_ZExtOrSExt(m_Value(X)))) {
+    SwitchInst *NewSI = SwitchInst::Create(X, SI->getDefaultDest(),
+                                           SI->getNumCases(), SI->getParent());
+    SwitchInstProfUpdateWrapper SIW(*SI);
+    SwitchInstProfUpdateWrapper NewSIW(*NewSI);
+    NewSI->setDebugLoc(SI->getDebugLoc());
+    NewSIW.setSuccessorWeight(0, SIW.getSuccessorWeight(0));
+
+    Type *SrcTy = X->getType();
+    unsigned SrcBW = SrcTy->getScalarSizeInBits();
+    for (auto &Case : SI->cases()) {
+      const APInt &CaseVal = Case.getCaseValue()->getValue();
+      assert(
+          (isa<ZExtInst>(SI->getCondition()) ? CaseVal.isIntN(SrcBW)
+                                             : CaseVal.isSignedIntN(SrcBW)) &&
+          "Unreachable cases should be eliminated by eliminateDeadSwitchCases");
+      APInt TruncVal = CaseVal.trunc(SrcBW);
+      NewSIW.addCase(cast<ConstantInt>(ConstantInt::get(SrcTy, TruncVal)),
+                     Case.getCaseSuccessor(),
+                     SIW.getSuccessorWeight(Case.getSuccessorIndex()));
+    }
+    SI->eraseFromParent();
+    return true;
+  }
+
+  return false;
+}
+
 bool SimplifyCFGOpt::simplifySwitch(SwitchInst *SI, IRBuilder<> &Builder) {
   BasicBlock *BB = SI->getParent();
 
@@ -7041,6 +7072,9 @@ bool SimplifyCFGOpt::simplifySwitch(SwitchInst *SI, IRBuilder<> &Builder) {
   if (eliminateDeadSwitchCases(SI, DTU, Options.AC, DL))
     return requestResimplify();
 
+  if (simplifySwitchCondition(SI))
+    return requestResimplify();
+
   if (trySwitchToSelect(SI, Builder, DTU, DL, TTI))
     return requestResimplify();
 
diff --git a/llvm/test/Transforms/SimplifyCFG/suppress-zero-branch-weights.ll b/llvm/test/Transforms/SimplifyCFG/suppress-zero-branch-weights.ll
index fd30b6352f7d41..2355f3987b8924 100644
--- a/llvm/test/Transforms/SimplifyCFG/suppress-zero-branch-weights.ll
+++ b/llvm/test/Transforms/SimplifyCFG/suppress-zero-branch-weights.ll
@@ -11,11 +11,11 @@ define i1 @repeated_signbits(i8 %condition) {
 ; CHECK-LABEL: @repeated_signbits(
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    [[SEXT:%.*]] = sext i8 [[CONDITION:%.*]] to i32
-; CHECK-NEXT:    switch i32 [[SEXT]], label [[DEFAULT:%.*]] [
-; CHECK-NEXT:    i32 0, label [[COMMON_RET:%.*]]
-; CHECK-NEXT:    i32 127, label [[COMMON_RET]]
-; CHECK-NEXT:    i32 -128, label [[COMMON_RET]]
-; CHECK-NEXT:    i32 -1, label [[COMMON_RET]]
+; CHECK-NEXT:    switch i8 [[CONDITION]], label [[DEFAULT:%.*]] [
+; CHECK-NEXT:      i8 0, label [[COMMON_RET:%.*]]
+; CHECK-NEXT:      i8 127, label [[COMMON_RET]]
+; CHECK-NEXT:      i8 -128, label [[COMMON_RET]]
+; CHECK-NEXT:      i8 -1, label [[COMMON_RET]]
 ; CHECK-NEXT:    ]
 ; CHECK:       common.ret:
 ; CHECK-NEXT:    [[COMMON_RET_OP:%.*]] = phi i1 [ false, [[DEFAULT]] ], [ true, [[ENTRY:%.*]] ], [ true, [[ENTRY]] ], [ true, [[ENTRY]] ], [ true, [[ENTRY]] ]
diff --git a/llvm/test/Transforms/SimplifyCFG/switch-masked-bits.ll b/llvm/test/Transforms/SimplifyCFG/switch-masked-bits.ll
index f66240e9f4f7d4..0a0523aeb08ede 100644
--- a/llvm/test/Transforms/SimplifyCFG/switch-masked-bits.ll
+++ b/llvm/test/Transforms/SimplifyCFG/switch-masked-bits.ll
@@ -50,11 +50,11 @@ define i1 @repeated_signbits(i8 %condition) {
 ; CHECK-LABEL: @repeated_signbits(
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    [[SEXT:%.*]] = sext i8 [[CONDITION:%.*]] to i32
-; CHECK-NEXT:    switch i32 [[SEXT]], label [[DEFAULT:%.*]] [
-; CHECK-NEXT:    i32 0, label [[COMMON_RET:%.*]]
-; CHECK-NEXT:    i32 127, label [[COMMON_RET]]
-; CHECK-NEXT:    i32 -128, label [[COMMON_RET]]
-; CHECK-NEXT:    i32 -1, label [[COMMON_RET]]
+; CHECK-NEXT:    switch i8 [[CONDITION]], label [[DEFAULT:%.*]] [
+; CHECK-NEXT:      i8 0, label [[COMMON_RET:%.*]]
+; CHECK-NEXT:      i8 127, label [[COMMON_RET]]
+; CHECK-NEXT:      i8 -128, label [[COMMON_RET]]
+; CHECK-NEXT:      i8 -1, label [[COMMON_RET]]
 ; CHECK-NEXT:    ]
 ; CHECK:       common.ret:
 ; CHECK-NEXT:    [[COMMON_RET_OP:%.*]] = phi i1 [ false, [[DEFAULT]] ], [ true, [[ENTRY:%.*]] ], [ true, [[ENTRY]] ], [ true, [[ENTRY]] ], [ true, [[ENTRY]] ]
diff --git a/llvm/test/Transforms/SimplifyCFG/switch-simplify-cond.ll b/llvm/test/Transforms/SimplifyCFG/switch-simplify-cond.ll
new file mode 100644
index 00000000000000..b0172d83fdbf03
--- /dev/null
+++ b/llvm/test/Transforms/SimplifyCFG/switch-simplify-cond.ll
@@ -0,0 +1,159 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4
+; RUN: opt %s -passes=simplifycfg -simplifycfg-require-and-preserve-domtree=1 -S | FileCheck %s
+
+define i1 @test_switch_with_zext(i16 %a, i1 %b, i1 %c) {
+; CHECK-LABEL: define i1 @test_switch_with_zext(
+; CHECK-SAME: i16 [[A:%.*]], i1 [[B:%.*]], i1 [[C:%.*]]) {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[A_EXT:%.*]] = zext i16 [[A]] to i32
+; CHECK-NEXT:    switch i16 [[A]], label [[SW_DEFAULT:%.*]] [
+; CHECK-NEXT:      i16 37, label [[COMMON_RET:%.*]]
+; CHECK-NEXT:      i16 38, label [[COMMON_RET]]
+; CHECK-NEXT:      i16 39, label [[COMMON_RET]]
+; CHECK-NEXT:    ]
+; CHECK:       common.ret:
+; CHECK-NEXT:    [[COMMON_RET_OP:%.*]] = phi i1 [ [[C]], [[SW_DEFAULT]] ], [ [[B]], [[ENTRY:%.*]] ], [ [[B]], [[ENTRY]] ], [ [[B]], [[ENTRY]] ]
+; CHECK-NEXT:    ret i1 [[COMMON_RET_OP]]
+; CHECK:       sw.default:
+; CHECK-NEXT:    br label [[COMMON_RET]]
+;
+entry:
+  %a.ext = zext i16 %a to i32
+  switch i32 %a.ext, label %sw.default [
+  i32 37, label %sw.bb
+  i32 38, label %sw.bb
+  i32 39, label %sw.bb
+  ]
+
+sw.bb:
+  ret i1 %b
+sw.default:
+  ret i1 %c
+}
+
+define i1 @test_switch_with_sext(i16 %a, i1 %b, i1 %c) {
+; CHECK-LABEL: define i1 @test_switch_with_sext(
+; CHECK-SAME: i16 [[A:%.*]], i1 [[B:%.*]], i1 [[C:%.*]]) {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[A_EXT:%.*]] = sext i16 [[A]] to i32
+; CHECK-NEXT:    switch i16 [[A]], label [[SW_DEFAULT:%.*]] [
+; CHECK-NEXT:      i16 37, label [[COMMON_RET:%.*]]
+; CHECK-NEXT:      i16 38, label [[COMMON_RET]]
+; CHECK-NEXT:      i16 39, label [[COMMON_RET]]
+; CHECK-NEXT:    ]
+; CHECK:       common.ret:
+; CHECK-NEXT:    [[COMMON_RET_OP:%.*]] = phi i1 [ [[C]], [[SW_DEFAULT]] ], [ [[B]], [[ENTRY:%.*]] ], [ [[B]], [[ENTRY]] ], [ [[B]], [[ENTRY]] ]
+; CHECK-NEXT:    ret i1 [[COMMON_RET_OP]]
+; CHECK:       sw.default:
+; CHECK-NEXT:    br label [[COMMON_RET]]
+;
+entry:
+  %a.ext = sext i16 %a to i32
+  switch i32 %a.ext, label %sw.default [
+  i32 37, label %sw.bb
+  i32 38, label %sw.bb
+  i32 39, label %sw.bb
+  ]
+
+sw.bb:
+  ret i1 %b
+sw.default:
+  ret i1 %c
+}
+
+define i1 @test_switch_with_zext_unreachable_case(i16 %a, i1 %b, i1 %c) {
+; CHECK-LABEL: define i1 @test_switch_with_zext_unreachable_case(
+; CHECK-SAME: i16 [[A:%.*]], i1 [[B:%.*]], i1 [[C:%.*]]) {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[A_EXT:%.*]] = zext i16 [[A]] to i32
+; CHECK-NEXT:    switch i16 [[A]], label [[SW_DEFAULT:%.*]] [
+; CHECK-NEXT:      i16 37, label [[COMMON_RET:%.*]]
+; CHECK-NEXT:      i16 38, label [[COMMON_RET]]
+; CHECK-NEXT:      i16 39, label [[COMMON_RET]]
+; CHECK-NEXT:    ]
+; CHECK:       common.ret:
+; CHECK-NEXT:    [[COMMON_RET_OP:%.*]] = phi i1 [ [[C]], [[SW_DEFAULT]] ], [ [[B]], [[ENTRY:%.*]] ], [ [[B]], [[ENTRY]] ], [ [[B]], [[ENTRY]] ]
+; CHECK-NEXT:    ret i1 [[COMMON_RET_OP]]
+; CHECK:       sw.default:
+; CHECK-NEXT:    br label [[COMMON_RET]]
+;
+entry:
+  %a.ext = zext i16 %a to i32
+  switch i32 %a.ext, label %sw.default [
+  i32 37, label %sw.bb
+  i32 38, label %sw.bb
+  i32 39, label %sw.bb
+  i32 65537, label %sw.bb
+  ]
+
+sw.bb:
+  ret i1 %b
+sw.default:
+  ret i1 %c
+}
+
+define i1 @test_switch_with_sext_unreachable_case(i16 %a, i1 %b, i1 %c) {
+; CHECK-LABEL: define i1 @test_switch_with_sext_unreachable_case(
+; CHECK-SAME: i16 [[A:%.*]], i1 [[B:%.*]], i1 [[C:%.*]]) {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[A_EXT:%.*]] = sext i16 [[A]] to i32
+; CHECK-NEXT:    switch i16 [[A]], label [[SW_DEFAULT:%.*]] [
+; CHECK-NEXT:      i16 37, label [[COMMON_RET:%.*]]
+; CHECK-NEXT:      i16 38, label [[COMMON_RET]]
+; CHECK-NEXT:      i16 39, label [[COMMON_RET]]
+; CHECK-NEXT:    ]
+; CHECK:       common.ret:
+; CHECK-NEXT:    [[COMMON_RET_OP:%.*]] = phi i1 [ [[C]], [[SW_DEFAULT]] ], [ [[B]], [[ENTRY:%.*]] ], [ [[B]], [[ENTRY]] ], [ [[B]], [[ENTRY]] ]
+; CHECK-NEXT:    ret i1 [[COMMON_RET_OP]]
+; CHECK:       sw.default:
+; CHECK-NEXT:    br label [[COMMON_RET]]
+;
+entry:
+  %a.ext = sext i16 %a to i32
+  switch i32 %a.ext, label %sw.default [
+  i32 37, label %sw.bb
+  i32 38, label %sw.bb
+  i32 39, label %sw.bb
+  i32 -65537, label %sw.bb
+  ]
+
+sw.bb:
+  ret i1 %b
+sw.default:
+  ret i1 %c
+}
+
+define i1 @test_switch_with_zext_prof_preserve(i16 %a, i1 %b, i1 %c) {
+; CHECK-LABEL: define i1 @test_switch_with_zext_prof_preserve(
+; CHECK-SAME: i16 [[A:%.*]], i1 [[B:%.*]], i1 [[C:%.*]]) {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[A_EXT:%.*]] = zext i16 [[A]] to i32
+; CHECK-NEXT:    switch i16 [[A]], label [[SW_DEFAULT:%.*]] [
+; CHECK-NEXT:      i16 37, label [[COMMON_RET:%.*]]
+; CHECK-NEXT:      i16 38, label [[COMMON_RET]]
+; CHECK-NEXT:      i16 39, label [[COMMON_RET]]
+; CHECK-NEXT:    ], !prof [[PROF0:![0-9]+]]
+; CHECK:       common.ret:
+; CHECK-NEXT:    [[COMMON_RET_OP:%.*]] = phi i1 [ [[C]], [[SW_DEFAULT]] ], [ [[B]], [[ENTRY:%.*]] ], [ [[B]], [[ENTRY]] ], [ [[B]], [[ENTRY]] ]
+; CHECK-NEXT:    ret i1 [[COMMON_RET_OP]]
+; CHECK:       sw.default:
+; CHECK-NEXT:    br label [[COMMON_RET]]
+;
+entry:
+  %a.ext = zext i16 %a to i32
+  switch i32 %a.ext, label %sw.default [
+  i32 37, label %sw.bb
+  i32 38, label %sw.bb
+  i32 39, label %sw.bb
+  ], !prof !0
+
+sw.bb:
+  ret i1 %b
+sw.default:
+  ret i1 %c
+}
+
+!0 = !{!"branch_weights", i32 8, i32 4, i32 2, i32 1}
+;.
+; CHECK: [[PROF0]] = !{!"branch_weights", i32 8, i32 4, i32 2, i32 1}
+;.

dtcxzyw added a commit to dtcxzyw/llvm-opt-benchmark that referenced this pull request Jan 4, 2024
Copy link
Contributor

@nikic nikic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this in SimplifyCFG? This seems like an extension of the existing switch width fold in InstCombine:

unsigned NewWidth = Known.getBitWidth() - std::max(LeadingKnownZeros, LeadingKnownOnes);

@dtcxzyw
Copy link
Member Author

dtcxzyw commented Jan 4, 2024

Why is this in SimplifyCFG? This seems like an extension of the existing switch width fold in InstCombine:

unsigned NewWidth = Known.getBitWidth() - std::max(LeadingKnownZeros, LeadingKnownOnes);

IIRC, InstCombine cannot change the dominator tree.

See the following case:

 define i1 @test_switch_with_sext_unreachable_case(i16 %a, i1 %b, i1 %c) {
 entry:
   %a.ext = sext i16 %a to i32
   switch i32 %a.ext, label %sw.default [
   i32 37, label %sw.bb
   i32 38, label %sw.bb
   i32 39, label %sw.bb
   i32 -65499, label %sw.bb2 ; (trunc i32 -65499 to i16) = 37
   ]

 sw.bb:
   ret i1 %b
 sw.bb2:
   ret i1 false
 sw.default:
   ret i1 %c
 }

In this case, the edge i32 -65499, label %sw.bb2 should be eliminated.

@nikic
Copy link
Contributor

nikic commented Jan 4, 2024

@dtcxzyw But won't that edge get eliminated by SimplifyCFG anyway?

@dtcxzyw
Copy link
Member Author

dtcxzyw commented Jan 4, 2024

@dtcxzyw But won't that edge get eliminated by SimplifyCFG anyway?

Okay, I have got your point.

@dtcxzyw dtcxzyw changed the title [SimplifyCFG] Fold switch(zext/sext(X)) into switch(X) [InstCombine] Fold switch(zext/sext(X)) into switch(X) Jan 4, 2024
@dtcxzyw
Copy link
Member Author

dtcxzyw commented Jan 4, 2024

Why is this in SimplifyCFG? This seems like an extension of the existing switch width fold in InstCombine:

unsigned NewWidth = Known.getBitWidth() - std::max(LeadingKnownZeros, LeadingKnownOnes);

Done.

dtcxzyw added a commit to dtcxzyw/llvm-opt-benchmark that referenced this pull request Jan 4, 2024
@dtcxzyw
Copy link
Member Author

dtcxzyw commented Jan 5, 2024

Compile-time impact: http://llvm-compile-time-tracker.com/compare.php?from=7954c57124b495fbdc73674d71f2e366e4afe522&to=502b13ed34e561d995ae1f724cf06d20008bd86f&stat=instructions:u

stage1-O3 stage1-ReleaseThinLTO stage1-ReleaseLTO-g stage1-O0-g stage2-O3 stage2-O0-g stage2-clang
+0.03% +0.06% +0.07% +0.00% -0.02% -0.03% +0.02%

Does SimplifyCFG revert this transform?

@nikic
Copy link
Contributor

nikic commented Jan 5, 2024

@dtcxzyw The compile-time increases are probably due to increased code size: http://llvm-compile-time-tracker.com/compare.php?from=7954c57124b495fbdc73674d71f2e366e4afe522&to=502b13ed34e561d995ae1f724cf06d20008bd86f&stat=size-text As long as the code size increase itself is not a regression, this is fine.

Copy link
Contributor

@nikic nikic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM if you're happy with the diffs :)

@dtcxzyw dtcxzyw merged commit 7c3bcc3 into llvm:main Jan 5, 2024
4 checks passed
@dtcxzyw dtcxzyw deleted the perf/switch-sext-zext branch January 5, 2024 20:30
justinfargnoli pushed a commit to justinfargnoli/llvm-project that referenced this pull request Jan 28, 2024
This patch folds `switch(zext/sext(X))` into `switch(X)`.
The original motivation of this patch is to optimize a pattern found in
cvc5. For example:
```
  %bf.load.i = load i16, ptr %d_kind.i, align 8
  %bf.clear.i = and i16 %bf.load.i, 1023
  %bf.cast.i = zext nneg i16 %bf.clear.i to i32
  switch i32 %bf.cast.i, label %if.else [
    i32 335, label %if.then
    i32 303, label %if.then
  ]

if.then:                                          ; preds = %entry, %entry
  %d_children.i.i = getelementptr inbounds %"class.cvc5::internal::expr::NodeValue", ptr %0, i64 0, i32 3
  %cmp.i.i.i.i.i = icmp eq i16 %bf.clear.i, 1023
  %cond.i.i.i.i.i = select i1 %cmp.i.i.i.i.i, i32 -1, i32 %bf.cast.i
```
`%cmp.i.i.i.i.i` always evaluates to false because `%bf.clear.i` can
only be 335 or 303.
Folding `switch i32 %bf.cast.i` to `switch i16 %bf.clear.i` will help
`CVP` to handle this case.
See also
llvm#76928 (comment).

Compile-time impact:
http://llvm-compile-time-tracker.com/compare.php?from=7954c57124b495fbdc73674d71f2e366e4afe522&to=502b13ed34e561d995ae1f724cf06d20008bd86f&stat=instructions:u

|stage1-O3|stage1-ReleaseThinLTO|stage1-ReleaseLTO-g|stage1-O0-g|stage2-O3|stage2-O0-g|stage2-clang|
|--|--|--|--|--|--|--|
|+0.03%|+0.06%|+0.07%|+0.00%|-0.02%|-0.03%|+0.02%|
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants