diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp index 055e8cadaab76..48a99543d7083 100644 --- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp +++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp @@ -568,9 +568,20 @@ struct ConstantComparesGatherer { /// If the elements in Vals matches the comparisons bool IsEq = false; + // Used to check if the first matched CompValue shall be the Extra check. + bool IgnoreFirstMatch = false; + bool MultipleMatches = false; + /// Construct and compute the result for the comparison instruction Cond ConstantComparesGatherer(Instruction *Cond, const DataLayout &DL) : DL(DL) { gather(Cond); + if (CompValue || !MultipleMatches) + return; + Extra = nullptr; + Vals.clear(); + UsedICmps = 0; + IgnoreFirstMatch = true; + gather(Cond); } ConstantComparesGatherer(const ConstantComparesGatherer &) = delete; @@ -581,10 +592,16 @@ struct ConstantComparesGatherer { /// Try to set the current value used for the comparison, it succeeds only if /// it wasn't set before or if the new value is the same as the old one bool setValueOnce(Value *NewVal) { - if (CompValue && CompValue != NewVal) + if (IgnoreFirstMatch) { + IgnoreFirstMatch = false; return false; + } + if (CompValue && CompValue != NewVal) { + MultipleMatches = true; + return false; + } CompValue = NewVal; - return (CompValue != nullptr); + return true; } /// Try to match Instruction "I" as a comparison against a constant and diff --git a/llvm/test/Transforms/SimplifyCFG/switch_create.ll b/llvm/test/Transforms/SimplifyCFG/switch_create.ll index a1533bdcffb43..a06e64f74b3ac 100644 --- a/llvm/test/Transforms/SimplifyCFG/switch_create.ll +++ b/llvm/test/Transforms/SimplifyCFG/switch_create.ll @@ -1125,3 +1125,70 @@ F: ret void } +define void @extra_cond_is_eq_cmp(i8 %c, i32 %x) { +; CHECK-LABEL: @extra_cond_is_eq_cmp( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[X:%.*]], 32 +; CHECK-NEXT: [[TMP0:%.*]] = freeze i1 [[CMP]] +; CHECK-NEXT: br i1 [[TMP0]], label [[IF_THEN:%.*]], label [[SWITCH_EARLY_TEST:%.*]] +; CHECK: switch.early.test: +; CHECK-NEXT: switch i8 [[C:%.*]], label [[COMMON_RET:%.*]] [ +; CHECK-NEXT: i8 99, label [[IF_THEN]] +; CHECK-NEXT: i8 97, label [[IF_THEN]] +; CHECK-NEXT: ] +; CHECK: common.ret: +; CHECK-NEXT: ret void +; CHECK: if.then: +; CHECK-NEXT: tail call void @foo1() +; CHECK-NEXT: br label [[COMMON_RET]] +; +entry: + %cmp = icmp eq i32 %x, 32 + %cmp4 = icmp eq i8 %c, 97 + %or.cond = or i1 %cmp, %cmp4 + %cmp9 = icmp eq i8 %c, 99 + %or.cond11 = or i1 %or.cond, %cmp9 + br i1 %or.cond11, label %if.then, label %if.end + +if.then: + tail call void @foo1() + ret void + +if.end: + ret void + +} + +define void @extra_cond_is_eq_cmp_c(i8 %c, i32 %x) { +; CHECK-LABEL: @extra_cond_is_eq_cmp_c( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[X:%.*]], 32 +; CHECK-NEXT: [[TMP0:%.*]] = freeze i1 [[CMP]] +; CHECK-NEXT: br i1 [[TMP0]], label [[IF_THEN:%.*]], label [[SWITCH_EARLY_TEST:%.*]] +; CHECK: switch.early.test: +; CHECK-NEXT: switch i8 [[C:%.*]], label [[COMMON_RET:%.*]] [ +; CHECK-NEXT: i8 99, label [[IF_THEN]] +; CHECK-NEXT: i8 97, label [[IF_THEN]] +; CHECK-NEXT: ] +; CHECK: common.ret: +; CHECK-NEXT: ret void +; CHECK: if.then: +; CHECK-NEXT: tail call void @foo1() +; CHECK-NEXT: br label [[COMMON_RET]] +; +entry: + %cmp = icmp eq i32 %x, 32 + %cmp4 = icmp eq i8 %c, 97 + %or.cond = or i1 %cmp4, %cmp + %cmp9 = icmp eq i8 %c, 99 + %or.cond11 = or i1 %or.cond, %cmp9 + br i1 %or.cond11, label %if.then, label %if.end + +if.then: + tail call void @foo1() + ret void + +if.end: + ret void + +}