diff --git a/llvm/include/llvm/Analysis/InlineModelFeatureMaps.h b/llvm/include/llvm/Analysis/InlineModelFeatureMaps.h index ca9bb7244d669..d62ec9ce49119 100644 --- a/llvm/include/llvm/Analysis/InlineModelFeatureMaps.h +++ b/llvm/include/llvm/Analysis/InlineModelFeatureMaps.h @@ -39,6 +39,8 @@ namespace llvm { M(int64_t, {1}, jump_table_penalty, "Accumulation of costs for jump tables") \ M(int64_t, {1}, case_cluster_penalty, \ "Accumulation of costs for case clusters") \ + M(int64_t, {1}, switch_default_dest_penalty, \ + "Accumulation of costs for switch default destination") \ M(int64_t, {1}, switch_penalty, \ "Accumulation of costs for switch statements") \ M(int64_t, {1}, unsimplified_common_instructions, \ diff --git a/llvm/include/llvm/IR/Instructions.h b/llvm/include/llvm/IR/Instructions.h index 4b5a4423b7689..1db4ff2f09bca 100644 --- a/llvm/include/llvm/IR/Instructions.h +++ b/llvm/include/llvm/IR/Instructions.h @@ -49,6 +49,7 @@ class DataLayout; class StringRef; class Type; class Value; +class UnreachableInst; //===----------------------------------------------------------------------===// // AllocaInst Class @@ -3505,6 +3506,12 @@ class SwitchInst : public Instruction { return cast(getOperand(1)); } + /// Returns true if the default branch must result in immediate undefined + /// behavior, false otherwise. + bool defaultDestUndefined() const { + return isa(getDefaultDest()->getFirstNonPHIOrDbg()); + } + void setDefaultDest(BasicBlock *DefaultCase) { setOperand(1, reinterpret_cast(DefaultCase)); } diff --git a/llvm/lib/Analysis/InlineCost.cpp b/llvm/lib/Analysis/InlineCost.cpp index 1fa7badaa4fa0..dc6878039f6a6 100644 --- a/llvm/lib/Analysis/InlineCost.cpp +++ b/llvm/lib/Analysis/InlineCost.cpp @@ -336,8 +336,8 @@ class CallAnalyzer : public InstVisitor { /// Called at the end of processing a switch instruction, with the given /// number of case clusters. - virtual void onFinalizeSwitch(unsigned JumpTableSize, - unsigned NumCaseCluster) {} + virtual void onFinalizeSwitch(unsigned JumpTableSize, unsigned NumCaseCluster, + bool DefaultDestUndefined) {} /// Called to account for any other instruction not specifically accounted /// for. @@ -699,15 +699,16 @@ class InlineCostCallAnalyzer final : public CallAnalyzer { CallPenalty)); } - void onFinalizeSwitch(unsigned JumpTableSize, - unsigned NumCaseCluster) override { + void onFinalizeSwitch(unsigned JumpTableSize, unsigned NumCaseCluster, + bool DefaultDestUndefined) override { + if (!DefaultDestUndefined) + addCost(2 * InstrCost); // If suitable for a jump table, consider the cost for the table size and // branch to destination. // Maximum valid cost increased in this function. if (JumpTableSize) { int64_t JTCost = static_cast(JumpTableSize) * InstrCost + 4 * InstrCost; - addCost(JTCost); return; } @@ -1153,6 +1154,7 @@ class InlineCostFeaturesAnalyzer final : public CallAnalyzer { // heuristics in the ML inliner. static constexpr int JTCostMultiplier = 4; static constexpr int CaseClusterCostMultiplier = 2; + static constexpr int SwitchDefaultDestCostMultiplier = 2; static constexpr int SwitchCostMultiplier = 2; // FIXME: These are taken from the heuristic-based cost visitor: we should @@ -1231,8 +1233,11 @@ class InlineCostFeaturesAnalyzer final : public CallAnalyzer { } } - void onFinalizeSwitch(unsigned JumpTableSize, - unsigned NumCaseCluster) override { + void onFinalizeSwitch(unsigned JumpTableSize, unsigned NumCaseCluster, + bool DefaultDestUndefined) override { + if (!DefaultDestUndefined) + increment(InlineCostFeatureIndex::switch_default_dest_penalty, + SwitchDefaultDestCostMultiplier * InstrCost); if (JumpTableSize) { int64_t JTCost = static_cast(JumpTableSize) * InstrCost + @@ -2461,7 +2466,7 @@ bool CallAnalyzer::visitSwitchInst(SwitchInst &SI) { unsigned NumCaseCluster = TTI.getEstimatedNumberOfCaseClusters(SI, JumpTableSize, PSI, BFI); - onFinalizeSwitch(JumpTableSize, NumCaseCluster); + onFinalizeSwitch(JumpTableSize, NumCaseCluster, SI.defaultDestUndefined()); return false; } diff --git a/llvm/test/Transforms/Inline/inline-switch-default-2.ll b/llvm/test/Transforms/Inline/inline-switch-default-2.ll new file mode 100644 index 0000000000000..8d3e24c798df8 --- /dev/null +++ b/llvm/test/Transforms/Inline/inline-switch-default-2.ll @@ -0,0 +1,317 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4 +; RUN: opt %s -S -passes=inline -inline-threshold=21 | FileCheck %s + +; Check for scenarios without TTI. + +define i64 @foo1(i64 %a) { +; LOOKUPTABLE-LABEL: define i64 @foo1( +; LOOKUPTABLE-SAME: i64 [[TMP0:%.*]]) { +; LOOKUPTABLE-NEXT: switch i64 [[TMP0]], label [[DEFAULT_BRANCH_I:%.*]] [ +; LOOKUPTABLE-NEXT: i64 0, label [[BRANCH_0_I:%.*]] +; LOOKUPTABLE-NEXT: i64 2, label [[BRANCH_2_I:%.*]] +; LOOKUPTABLE-NEXT: i64 4, label [[BRANCH_4_I:%.*]] +; LOOKUPTABLE-NEXT: i64 6, label [[BRANCH_6_I:%.*]] +; LOOKUPTABLE-NEXT: ] +; LOOKUPTABLE: branch_0.i: +; LOOKUPTABLE-NEXT: br label [[BAR1_EXIT:%.*]] +; LOOKUPTABLE: branch_2.i: +; LOOKUPTABLE-NEXT: br label [[BAR1_EXIT]] +; LOOKUPTABLE: branch_4.i: +; LOOKUPTABLE-NEXT: br label [[BAR1_EXIT]] +; LOOKUPTABLE: branch_6.i: +; LOOKUPTABLE-NEXT: br label [[BAR1_EXIT]] +; LOOKUPTABLE: default_branch.i: +; LOOKUPTABLE-NEXT: br label [[BAR1_EXIT]] +; LOOKUPTABLE: bar1.exit: +; LOOKUPTABLE-NEXT: [[TMP2:%.*]] = phi i64 [ 5, [[BRANCH_0_I]] ], [ 9, [[BRANCH_2_I]] ], [ 2, [[BRANCH_4_I]] ], [ 7, [[BRANCH_6_I]] ], [ 3, [[DEFAULT_BRANCH_I]] ] +; LOOKUPTABLE-NEXT: ret i64 [[TMP2]] +; +; SWITCH-LABEL: define i64 @foo1( +; SWITCH-SAME: i64 [[TMP0:%.*]]) { +; SWITCH-NEXT: switch i64 [[TMP0]], label [[DEFAULT_BRANCH_I:%.*]] [ +; SWITCH-NEXT: i64 0, label [[BRANCH_0_I:%.*]] +; SWITCH-NEXT: i64 2, label [[BRANCH_2_I:%.*]] +; SWITCH-NEXT: i64 4, label [[BRANCH_4_I:%.*]] +; SWITCH-NEXT: i64 6, label [[BRANCH_6_I:%.*]] +; SWITCH-NEXT: ] +; SWITCH: branch_0.i: +; SWITCH-NEXT: br label [[BAR1_EXIT:%.*]] +; SWITCH: branch_2.i: +; SWITCH-NEXT: br label [[BAR1_EXIT]] +; SWITCH: branch_4.i: +; SWITCH-NEXT: br label [[BAR1_EXIT]] +; SWITCH: branch_6.i: +; SWITCH-NEXT: br label [[BAR1_EXIT]] +; SWITCH: default_branch.i: +; SWITCH-NEXT: br label [[BAR1_EXIT]] +; SWITCH: bar1.exit: +; SWITCH-NEXT: [[TMP2:%.*]] = phi i64 [ 5, [[BRANCH_0_I]] ], [ 9, [[BRANCH_2_I]] ], [ 2, [[BRANCH_4_I]] ], [ 7, [[BRANCH_6_I]] ], [ 3, [[DEFAULT_BRANCH_I]] ] +; SWITCH-NEXT: ret i64 [[TMP2]] +; +; CHECK-LABEL: define i64 @foo1( +; CHECK-SAME: i64 [[A:%.*]]) { +; CHECK-NEXT: [[B:%.*]] = call i64 @bar1(i64 [[A]]) +; CHECK-NEXT: ret i64 [[B]] +; + %b = call i64 @bar1(i64 %a) + ret i64 %b +} + +define i64 @foo2(i64 %a) { +; LOOKUPTABLE-LABEL: define i64 @foo2( +; LOOKUPTABLE-SAME: i64 [[TMP0:%.*]]) { +; LOOKUPTABLE-NEXT: switch i64 [[TMP0]], label [[UNREACHABLEDEFAULT_I:%.*]] [ +; LOOKUPTABLE-NEXT: i64 0, label [[BRANCH_0_I:%.*]] +; LOOKUPTABLE-NEXT: i64 2, label [[BRANCH_2_I:%.*]] +; LOOKUPTABLE-NEXT: i64 4, label [[BRANCH_4_I:%.*]] +; LOOKUPTABLE-NEXT: i64 6, label [[BRANCH_6_I:%.*]] +; LOOKUPTABLE-NEXT: ] +; LOOKUPTABLE: branch_0.i: +; LOOKUPTABLE-NEXT: br label [[BAR2_EXIT:%.*]] +; LOOKUPTABLE: branch_2.i: +; LOOKUPTABLE-NEXT: br label [[BAR2_EXIT]] +; LOOKUPTABLE: branch_4.i: +; LOOKUPTABLE-NEXT: br label [[BAR2_EXIT]] +; LOOKUPTABLE: branch_6.i: +; LOOKUPTABLE-NEXT: br label [[BAR2_EXIT]] +; LOOKUPTABLE: unreachabledefault.i: +; LOOKUPTABLE-NEXT: unreachable +; LOOKUPTABLE: bar2.exit: +; LOOKUPTABLE-NEXT: [[TMP2:%.*]] = phi i64 [ 5, [[BRANCH_0_I]] ], [ 9, [[BRANCH_2_I]] ], [ 2, [[BRANCH_4_I]] ], [ 7, [[BRANCH_6_I]] ] +; LOOKUPTABLE-NEXT: ret i64 [[TMP2]] +; +; SWITCH-LABEL: define i64 @foo2( +; SWITCH-SAME: i64 [[TMP0:%.*]]) { +; SWITCH-NEXT: switch i64 [[TMP0]], label [[UNREACHABLEDEFAULT_I:%.*]] [ +; SWITCH-NEXT: i64 0, label [[BRANCH_0_I:%.*]] +; SWITCH-NEXT: i64 2, label [[BRANCH_2_I:%.*]] +; SWITCH-NEXT: i64 4, label [[BRANCH_4_I:%.*]] +; SWITCH-NEXT: i64 6, label [[BRANCH_6_I:%.*]] +; SWITCH-NEXT: ] +; SWITCH: branch_0.i: +; SWITCH-NEXT: br label [[BAR2_EXIT:%.*]] +; SWITCH: branch_2.i: +; SWITCH-NEXT: br label [[BAR2_EXIT]] +; SWITCH: branch_4.i: +; SWITCH-NEXT: br label [[BAR2_EXIT]] +; SWITCH: branch_6.i: +; SWITCH-NEXT: br label [[BAR2_EXIT]] +; SWITCH: unreachabledefault.i: +; SWITCH-NEXT: unreachable +; SWITCH: bar2.exit: +; SWITCH-NEXT: [[TMP2:%.*]] = phi i64 [ 5, [[BRANCH_0_I]] ], [ 9, [[BRANCH_2_I]] ], [ 2, [[BRANCH_4_I]] ], [ 7, [[BRANCH_6_I]] ] +; SWITCH-NEXT: ret i64 [[TMP2]] +; +; CHECK-LABEL: define i64 @foo2( +; CHECK-SAME: i64 [[A:%.*]]) { +; CHECK-NEXT: switch i64 [[A]], label [[UNREACHABLEDEFAULT_I:%.*]] [ +; CHECK-NEXT: i64 0, label [[BRANCH_0_I:%.*]] +; CHECK-NEXT: i64 2, label [[BRANCH_2_I:%.*]] +; CHECK-NEXT: i64 4, label [[BRANCH_4_I:%.*]] +; CHECK-NEXT: i64 6, label [[BRANCH_6_I:%.*]] +; CHECK-NEXT: ] +; CHECK: branch_0.i: +; CHECK-NEXT: br label [[BAR2_EXIT:%.*]] +; CHECK: branch_2.i: +; CHECK-NEXT: br label [[BAR2_EXIT]] +; CHECK: branch_4.i: +; CHECK-NEXT: br label [[BAR2_EXIT]] +; CHECK: branch_6.i: +; CHECK-NEXT: br label [[BAR2_EXIT]] +; CHECK: unreachabledefault.i: +; CHECK-NEXT: unreachable +; CHECK: bar2.exit: +; CHECK-NEXT: [[B_I:%.*]] = phi i64 [ 5, [[BRANCH_0_I]] ], [ 9, [[BRANCH_2_I]] ], [ 2, [[BRANCH_4_I]] ], [ 7, [[BRANCH_6_I]] ] +; CHECK-NEXT: ret i64 [[B_I]] +; + %b = call i64 @bar2(i64 %a) + ret i64 %b +} + +define i64 @bar1(i64 %a) { +; LOOKUPTABLE-LABEL: define i64 @bar1( +; LOOKUPTABLE-SAME: i64 [[TMP0:%.*]]) { +; LOOKUPTABLE-NEXT: switch i64 [[TMP0]], label [[DEFAULT_BRANCH:%.*]] [ +; LOOKUPTABLE-NEXT: i64 0, label [[BRANCH_0:%.*]] +; LOOKUPTABLE-NEXT: i64 2, label [[BRANCH_2:%.*]] +; LOOKUPTABLE-NEXT: i64 4, label [[BRANCH_4:%.*]] +; LOOKUPTABLE-NEXT: i64 6, label [[BRANCH_6:%.*]] +; LOOKUPTABLE-NEXT: ] +; LOOKUPTABLE: branch_0: +; LOOKUPTABLE-NEXT: br label [[EXIT:%.*]] +; LOOKUPTABLE: branch_2: +; LOOKUPTABLE-NEXT: br label [[EXIT]] +; LOOKUPTABLE: branch_4: +; LOOKUPTABLE-NEXT: br label [[EXIT]] +; LOOKUPTABLE: branch_6: +; LOOKUPTABLE-NEXT: br label [[EXIT]] +; LOOKUPTABLE: default_branch: +; LOOKUPTABLE-NEXT: br label [[EXIT]] +; LOOKUPTABLE: exit: +; LOOKUPTABLE-NEXT: [[TMP2:%.*]] = phi i64 [ 5, [[BRANCH_0]] ], [ 9, [[BRANCH_2]] ], [ 2, [[BRANCH_4]] ], [ 7, [[BRANCH_6]] ], [ 3, [[DEFAULT_BRANCH]] ] +; LOOKUPTABLE-NEXT: ret i64 [[TMP2]] +; +; SWITCH-LABEL: define i64 @bar1( +; SWITCH-SAME: i64 [[TMP0:%.*]]) { +; SWITCH-NEXT: switch i64 [[TMP0]], label [[DEFAULT_BRANCH:%.*]] [ +; SWITCH-NEXT: i64 0, label [[BRANCH_0:%.*]] +; SWITCH-NEXT: i64 2, label [[BRANCH_2:%.*]] +; SWITCH-NEXT: i64 4, label [[BRANCH_4:%.*]] +; SWITCH-NEXT: i64 6, label [[BRANCH_6:%.*]] +; SWITCH-NEXT: ] +; SWITCH: branch_0: +; SWITCH-NEXT: br label [[EXIT:%.*]] +; SWITCH: branch_2: +; SWITCH-NEXT: br label [[EXIT]] +; SWITCH: branch_4: +; SWITCH-NEXT: br label [[EXIT]] +; SWITCH: branch_6: +; SWITCH-NEXT: br label [[EXIT]] +; SWITCH: default_branch: +; SWITCH-NEXT: br label [[EXIT]] +; SWITCH: exit: +; SWITCH-NEXT: [[TMP2:%.*]] = phi i64 [ 5, [[BRANCH_0]] ], [ 9, [[BRANCH_2]] ], [ 2, [[BRANCH_4]] ], [ 7, [[BRANCH_6]] ], [ 3, [[DEFAULT_BRANCH]] ] +; SWITCH-NEXT: ret i64 [[TMP2]] +; +; CHECK-LABEL: define i64 @bar1( +; CHECK-SAME: i64 [[A:%.*]]) { +; CHECK-NEXT: switch i64 [[A]], label [[DEFAULT_BRANCH:%.*]] [ +; CHECK-NEXT: i64 0, label [[BRANCH_0:%.*]] +; CHECK-NEXT: i64 2, label [[BRANCH_2:%.*]] +; CHECK-NEXT: i64 4, label [[BRANCH_4:%.*]] +; CHECK-NEXT: i64 6, label [[BRANCH_6:%.*]] +; CHECK-NEXT: ] +; CHECK: branch_0: +; CHECK-NEXT: br label [[EXIT:%.*]] +; CHECK: branch_2: +; CHECK-NEXT: br label [[EXIT]] +; CHECK: branch_4: +; CHECK-NEXT: br label [[EXIT]] +; CHECK: branch_6: +; CHECK-NEXT: br label [[EXIT]] +; CHECK: default_branch: +; CHECK-NEXT: br label [[EXIT]] +; CHECK: exit: +; CHECK-NEXT: [[B:%.*]] = phi i64 [ 5, [[BRANCH_0]] ], [ 9, [[BRANCH_2]] ], [ 2, [[BRANCH_4]] ], [ 7, [[BRANCH_6]] ], [ 3, [[DEFAULT_BRANCH]] ] +; CHECK-NEXT: ret i64 [[B]] +; + switch i64 %a, label %default_branch [ + i64 0, label %branch_0 + i64 2, label %branch_2 + i64 4, label %branch_4 + i64 6, label %branch_6 + ] + +branch_0: + br label %exit + +branch_2: + br label %exit + +branch_4: + br label %exit + +branch_6: + br label %exit + +default_branch: + br label %exit + +exit: + %b = phi i64 [ 5, %branch_0 ], [ 9, %branch_2 ], [ 2, %branch_4 ], [ 7, %branch_6 ], [ 3, %default_branch ] + ret i64 %b +} + +define i64 @bar2(i64 %a) { +; LOOKUPTABLE-LABEL: define i64 @bar2( +; LOOKUPTABLE-SAME: i64 [[TMP0:%.*]]) { +; LOOKUPTABLE-NEXT: switch i64 [[TMP0]], label [[UNREACHABLEDEFAULT:%.*]] [ +; LOOKUPTABLE-NEXT: i64 0, label [[BRANCH_0:%.*]] +; LOOKUPTABLE-NEXT: i64 2, label [[BRANCH_2:%.*]] +; LOOKUPTABLE-NEXT: i64 4, label [[BRANCH_4:%.*]] +; LOOKUPTABLE-NEXT: i64 6, label [[BRANCH_6:%.*]] +; LOOKUPTABLE-NEXT: ] +; LOOKUPTABLE: branch_0: +; LOOKUPTABLE-NEXT: br label [[EXIT:%.*]] +; LOOKUPTABLE: branch_2: +; LOOKUPTABLE-NEXT: br label [[EXIT]] +; LOOKUPTABLE: branch_4: +; LOOKUPTABLE-NEXT: br label [[EXIT]] +; LOOKUPTABLE: branch_6: +; LOOKUPTABLE-NEXT: br label [[EXIT]] +; LOOKUPTABLE: unreachabledefault: +; LOOKUPTABLE-NEXT: unreachable +; LOOKUPTABLE: exit: +; LOOKUPTABLE-NEXT: [[TMP2:%.*]] = phi i64 [ 5, [[BRANCH_0]] ], [ 9, [[BRANCH_2]] ], [ 2, [[BRANCH_4]] ], [ 7, [[BRANCH_6]] ] +; LOOKUPTABLE-NEXT: ret i64 [[TMP2]] +; +; SWITCH-LABEL: define i64 @bar2( +; SWITCH-SAME: i64 [[TMP0:%.*]]) { +; SWITCH-NEXT: switch i64 [[TMP0]], label [[UNREACHABLEDEFAULT:%.*]] [ +; SWITCH-NEXT: i64 0, label [[BRANCH_0:%.*]] +; SWITCH-NEXT: i64 2, label [[BRANCH_2:%.*]] +; SWITCH-NEXT: i64 4, label [[BRANCH_4:%.*]] +; SWITCH-NEXT: i64 6, label [[BRANCH_6:%.*]] +; SWITCH-NEXT: ] +; SWITCH: branch_0: +; SWITCH-NEXT: br label [[EXIT:%.*]] +; SWITCH: branch_2: +; SWITCH-NEXT: br label [[EXIT]] +; SWITCH: branch_4: +; SWITCH-NEXT: br label [[EXIT]] +; SWITCH: branch_6: +; SWITCH-NEXT: br label [[EXIT]] +; SWITCH: unreachabledefault: +; SWITCH-NEXT: unreachable +; SWITCH: exit: +; SWITCH-NEXT: [[TMP2:%.*]] = phi i64 [ 5, [[BRANCH_0]] ], [ 9, [[BRANCH_2]] ], [ 2, [[BRANCH_4]] ], [ 7, [[BRANCH_6]] ] +; SWITCH-NEXT: ret i64 [[TMP2]] +; +; CHECK-LABEL: define i64 @bar2( +; CHECK-SAME: i64 [[A:%.*]]) { +; CHECK-NEXT: switch i64 [[A]], label [[UNREACHABLEDEFAULT:%.*]] [ +; CHECK-NEXT: i64 0, label [[BRANCH_0:%.*]] +; CHECK-NEXT: i64 2, label [[BRANCH_2:%.*]] +; CHECK-NEXT: i64 4, label [[BRANCH_4:%.*]] +; CHECK-NEXT: i64 6, label [[BRANCH_6:%.*]] +; CHECK-NEXT: ] +; CHECK: branch_0: +; CHECK-NEXT: br label [[EXIT:%.*]] +; CHECK: branch_2: +; CHECK-NEXT: br label [[EXIT]] +; CHECK: branch_4: +; CHECK-NEXT: br label [[EXIT]] +; CHECK: branch_6: +; CHECK-NEXT: br label [[EXIT]] +; CHECK: unreachabledefault: +; CHECK-NEXT: unreachable +; CHECK: exit: +; CHECK-NEXT: [[B:%.*]] = phi i64 [ 5, [[BRANCH_0]] ], [ 9, [[BRANCH_2]] ], [ 2, [[BRANCH_4]] ], [ 7, [[BRANCH_6]] ] +; CHECK-NEXT: ret i64 [[B]] +; + switch i64 %a, label %unreachabledefault [ + i64 0, label %branch_0 + i64 2, label %branch_2 + i64 4, label %branch_4 + i64 6, label %branch_6 + ] + +branch_0: + br label %exit + +branch_2: + br label %exit + +branch_4: + br label %exit + +branch_6: + br label %exit + +unreachabledefault: + unreachable + +exit: + %b = phi i64 [ 5, %branch_0 ], [ 9, %branch_2 ], [ 2, %branch_4 ], [ 7, %branch_6 ] + ret i64 %b +} diff --git a/llvm/test/Transforms/Inline/inline-switch-default.ll b/llvm/test/Transforms/Inline/inline-switch-default.ll new file mode 100644 index 0000000000000..44f1304e82dff --- /dev/null +++ b/llvm/test/Transforms/Inline/inline-switch-default.ll @@ -0,0 +1,216 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4 +; RUN: opt %s -S -passes=inline -inline-threshold=26 -min-jump-table-entries=4 | FileCheck %s -check-prefix=LOOKUPTABLE +; RUN: opt %s -S -passes=inline -inline-threshold=21 -min-jump-table-entries=5 | FileCheck %s -check-prefix=SWITCH + +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +; The `bar1` should not be inlined since there is a default branch. + +define i64 @foo1(i64 %a) { +; LOOKUPTABLE-LABEL: define i64 @foo1( +; LOOKUPTABLE-SAME: i64 [[A:%.*]]) { +; LOOKUPTABLE-NEXT: [[B:%.*]] = call i64 @bar1(i64 [[A]]) +; LOOKUPTABLE-NEXT: ret i64 [[B]] +; +; SWITCH-LABEL: define i64 @foo1( +; SWITCH-SAME: i64 [[A:%.*]]) { +; SWITCH-NEXT: [[B:%.*]] = call i64 @bar1(i64 [[A]]) +; SWITCH-NEXT: ret i64 [[B]] +; + %b = call i64 @bar1(i64 %a) + ret i64 %b +} + +define i64 @foo2(i64 %a) { +; LOOKUPTABLE-LABEL: define i64 @foo2( +; LOOKUPTABLE-SAME: i64 [[A:%.*]]) { +; LOOKUPTABLE-NEXT: switch i64 [[A]], label [[UNREACHABLEDEFAULT_I:%.*]] [ +; LOOKUPTABLE-NEXT: i64 0, label [[BRANCH_0_I:%.*]] +; LOOKUPTABLE-NEXT: i64 2, label [[BRANCH_2_I:%.*]] +; LOOKUPTABLE-NEXT: i64 4, label [[BRANCH_4_I:%.*]] +; LOOKUPTABLE-NEXT: i64 6, label [[BRANCH_6_I:%.*]] +; LOOKUPTABLE-NEXT: ] +; LOOKUPTABLE: branch_0.i: +; LOOKUPTABLE-NEXT: br label [[BAR2_EXIT:%.*]] +; LOOKUPTABLE: branch_2.i: +; LOOKUPTABLE-NEXT: br label [[BAR2_EXIT]] +; LOOKUPTABLE: branch_4.i: +; LOOKUPTABLE-NEXT: br label [[BAR2_EXIT]] +; LOOKUPTABLE: branch_6.i: +; LOOKUPTABLE-NEXT: br label [[BAR2_EXIT]] +; LOOKUPTABLE: unreachabledefault.i: +; LOOKUPTABLE-NEXT: unreachable +; LOOKUPTABLE: bar2.exit: +; LOOKUPTABLE-NEXT: [[B_I:%.*]] = phi i64 [ 5, [[BRANCH_0_I]] ], [ 9, [[BRANCH_2_I]] ], [ 2, [[BRANCH_4_I]] ], [ 7, [[BRANCH_6_I]] ] +; LOOKUPTABLE-NEXT: ret i64 [[B_I]] +; +; SWITCH-LABEL: define i64 @foo2( +; SWITCH-SAME: i64 [[A:%.*]]) { +; SWITCH-NEXT: switch i64 [[A]], label [[UNREACHABLEDEFAULT_I:%.*]] [ +; SWITCH-NEXT: i64 0, label [[BRANCH_0_I:%.*]] +; SWITCH-NEXT: i64 2, label [[BRANCH_2_I:%.*]] +; SWITCH-NEXT: i64 4, label [[BRANCH_4_I:%.*]] +; SWITCH-NEXT: i64 6, label [[BRANCH_6_I:%.*]] +; SWITCH-NEXT: ] +; SWITCH: branch_0.i: +; SWITCH-NEXT: br label [[BAR2_EXIT:%.*]] +; SWITCH: branch_2.i: +; SWITCH-NEXT: br label [[BAR2_EXIT]] +; SWITCH: branch_4.i: +; SWITCH-NEXT: br label [[BAR2_EXIT]] +; SWITCH: branch_6.i: +; SWITCH-NEXT: br label [[BAR2_EXIT]] +; SWITCH: unreachabledefault.i: +; SWITCH-NEXT: unreachable +; SWITCH: bar2.exit: +; SWITCH-NEXT: [[B_I:%.*]] = phi i64 [ 5, [[BRANCH_0_I]] ], [ 9, [[BRANCH_2_I]] ], [ 2, [[BRANCH_4_I]] ], [ 7, [[BRANCH_6_I]] ] +; SWITCH-NEXT: ret i64 [[B_I]] +; + %b = call i64 @bar2(i64 %a) + ret i64 %b +} + +define i64 @bar1(i64 %a) { +; LOOKUPTABLE-LABEL: define i64 @bar1( +; LOOKUPTABLE-SAME: i64 [[A:%.*]]) { +; LOOKUPTABLE-NEXT: switch i64 [[A]], label [[DEFAULT_BRANCH:%.*]] [ +; LOOKUPTABLE-NEXT: i64 0, label [[BRANCH_0:%.*]] +; LOOKUPTABLE-NEXT: i64 2, label [[BRANCH_2:%.*]] +; LOOKUPTABLE-NEXT: i64 4, label [[BRANCH_4:%.*]] +; LOOKUPTABLE-NEXT: i64 6, label [[BRANCH_6:%.*]] +; LOOKUPTABLE-NEXT: ] +; LOOKUPTABLE: branch_0: +; LOOKUPTABLE-NEXT: br label [[EXIT:%.*]] +; LOOKUPTABLE: branch_2: +; LOOKUPTABLE-NEXT: br label [[EXIT]] +; LOOKUPTABLE: branch_4: +; LOOKUPTABLE-NEXT: br label [[EXIT]] +; LOOKUPTABLE: branch_6: +; LOOKUPTABLE-NEXT: br label [[EXIT]] +; LOOKUPTABLE: default_branch: +; LOOKUPTABLE-NEXT: br label [[EXIT]] +; LOOKUPTABLE: exit: +; LOOKUPTABLE-NEXT: [[B:%.*]] = phi i64 [ 5, [[BRANCH_0]] ], [ 9, [[BRANCH_2]] ], [ 2, [[BRANCH_4]] ], [ 7, [[BRANCH_6]] ], [ 3, [[DEFAULT_BRANCH]] ] +; LOOKUPTABLE-NEXT: ret i64 [[B]] +; +; SWITCH-LABEL: define i64 @bar1( +; SWITCH-SAME: i64 [[A:%.*]]) { +; SWITCH-NEXT: switch i64 [[A]], label [[DEFAULT_BRANCH:%.*]] [ +; SWITCH-NEXT: i64 0, label [[BRANCH_0:%.*]] +; SWITCH-NEXT: i64 2, label [[BRANCH_2:%.*]] +; SWITCH-NEXT: i64 4, label [[BRANCH_4:%.*]] +; SWITCH-NEXT: i64 6, label [[BRANCH_6:%.*]] +; SWITCH-NEXT: ] +; SWITCH: branch_0: +; SWITCH-NEXT: br label [[EXIT:%.*]] +; SWITCH: branch_2: +; SWITCH-NEXT: br label [[EXIT]] +; SWITCH: branch_4: +; SWITCH-NEXT: br label [[EXIT]] +; SWITCH: branch_6: +; SWITCH-NEXT: br label [[EXIT]] +; SWITCH: default_branch: +; SWITCH-NEXT: br label [[EXIT]] +; SWITCH: exit: +; SWITCH-NEXT: [[B:%.*]] = phi i64 [ 5, [[BRANCH_0]] ], [ 9, [[BRANCH_2]] ], [ 2, [[BRANCH_4]] ], [ 7, [[BRANCH_6]] ], [ 3, [[DEFAULT_BRANCH]] ] +; SWITCH-NEXT: ret i64 [[B]] +; + switch i64 %a, label %default_branch [ + i64 0, label %branch_0 + i64 2, label %branch_2 + i64 4, label %branch_4 + i64 6, label %branch_6 + ] + +branch_0: + br label %exit + +branch_2: + br label %exit + +branch_4: + br label %exit + +branch_6: + br label %exit + +default_branch: + br label %exit + +exit: + %b = phi i64 [ 5, %branch_0 ], [ 9, %branch_2 ], [ 2, %branch_4 ], [ 7, %branch_6 ], [ 3, %default_branch ] + ret i64 %b +} + +define i64 @bar2(i64 %a) { +; LOOKUPTABLE-LABEL: define i64 @bar2( +; LOOKUPTABLE-SAME: i64 [[A:%.*]]) { +; LOOKUPTABLE-NEXT: switch i64 [[A]], label [[UNREACHABLEDEFAULT:%.*]] [ +; LOOKUPTABLE-NEXT: i64 0, label [[BRANCH_0:%.*]] +; LOOKUPTABLE-NEXT: i64 2, label [[BRANCH_2:%.*]] +; LOOKUPTABLE-NEXT: i64 4, label [[BRANCH_4:%.*]] +; LOOKUPTABLE-NEXT: i64 6, label [[BRANCH_6:%.*]] +; LOOKUPTABLE-NEXT: ] +; LOOKUPTABLE: branch_0: +; LOOKUPTABLE-NEXT: br label [[EXIT:%.*]] +; LOOKUPTABLE: branch_2: +; LOOKUPTABLE-NEXT: br label [[EXIT]] +; LOOKUPTABLE: branch_4: +; LOOKUPTABLE-NEXT: br label [[EXIT]] +; LOOKUPTABLE: branch_6: +; LOOKUPTABLE-NEXT: br label [[EXIT]] +; LOOKUPTABLE: unreachabledefault: +; LOOKUPTABLE-NEXT: unreachable +; LOOKUPTABLE: exit: +; LOOKUPTABLE-NEXT: [[B:%.*]] = phi i64 [ 5, [[BRANCH_0]] ], [ 9, [[BRANCH_2]] ], [ 2, [[BRANCH_4]] ], [ 7, [[BRANCH_6]] ] +; LOOKUPTABLE-NEXT: ret i64 [[B]] +; +; SWITCH-LABEL: define i64 @bar2( +; SWITCH-SAME: i64 [[A:%.*]]) { +; SWITCH-NEXT: switch i64 [[A]], label [[UNREACHABLEDEFAULT:%.*]] [ +; SWITCH-NEXT: i64 0, label [[BRANCH_0:%.*]] +; SWITCH-NEXT: i64 2, label [[BRANCH_2:%.*]] +; SWITCH-NEXT: i64 4, label [[BRANCH_4:%.*]] +; SWITCH-NEXT: i64 6, label [[BRANCH_6:%.*]] +; SWITCH-NEXT: ] +; SWITCH: branch_0: +; SWITCH-NEXT: br label [[EXIT:%.*]] +; SWITCH: branch_2: +; SWITCH-NEXT: br label [[EXIT]] +; SWITCH: branch_4: +; SWITCH-NEXT: br label [[EXIT]] +; SWITCH: branch_6: +; SWITCH-NEXT: br label [[EXIT]] +; SWITCH: unreachabledefault: +; SWITCH-NEXT: unreachable +; SWITCH: exit: +; SWITCH-NEXT: [[B:%.*]] = phi i64 [ 5, [[BRANCH_0]] ], [ 9, [[BRANCH_2]] ], [ 2, [[BRANCH_4]] ], [ 7, [[BRANCH_6]] ] +; SWITCH-NEXT: ret i64 [[B]] +; + switch i64 %a, label %unreachabledefault [ + i64 0, label %branch_0 + i64 2, label %branch_2 + i64 4, label %branch_4 + i64 6, label %branch_6 + ] + +branch_0: + br label %exit + +branch_2: + br label %exit + +branch_4: + br label %exit + +branch_6: + br label %exit + +unreachabledefault: + unreachable + +exit: + %b = phi i64 [ 5, %branch_0 ], [ 9, %branch_2 ], [ 2, %branch_4 ], [ 7, %branch_6 ] + ret i64 %b +}