Index: llvm/include/llvm/Target/TargetLowering.h =================================================================== --- llvm/include/llvm/Target/TargetLowering.h +++ llvm/include/llvm/Target/TargetLowering.h @@ -1027,10 +1027,18 @@ return MinimumJumpTableEntries; } + /// Return lower limit for number of entries in a jump table. + /// Zero if no limit. + unsigned getMinimumJumpTableSize() const; + /// Return upper limit for number of entries in a jump table. /// Zero if no limit. unsigned getMaximumJumpTableSize() const; + /// Return whether, everything else being equal, more jump tables are + /// preferred. + bool getFewJumpTables() const; + /// If a physical register, this specifies the register that /// llvm.savestack/llvm.restorestack should save and restore. unsigned getStackPointerRegisterToSaveRestore() const { @@ -1361,10 +1369,17 @@ MinimumJumpTableEntries = Val; } + /// Indicate the minimum number of entries in jump tables. + void setMinimumJumpTableSize(unsigned); + /// Indicate the maximum number of entries in jump tables. /// Set to zero to generate unlimited jump tables. void setMaximumJumpTableSize(unsigned); + /// Indicate that, everything else being equal, more jump tables are + /// preferred. + void setFewJumpTables(bool); + /// If set to a physical register, this specifies the register that /// llvm.savestack/llvm.restorestack should save and restore. void setStackPointerRegisterToSaveRestore(unsigned R) { Index: llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp =================================================================== --- llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -8457,10 +8457,14 @@ const bool OptForSize = DefaultMBB->getParent()->getFunction()->optForSize(); const int64_t N = Clusters.size(); + const bool MoreJumpTables = !TLI.getFewJumpTables(); const unsigned MinJumpTableEntries = TLI.getMinimumJumpTableEntries(); + const unsigned MinJumpTableSize = TLI.getMinimumJumpTableSize(); const unsigned MaxJumpTableSize = OptForSize ? UINT_MAX : TLI.getMaximumJumpTableSize() ? TLI.getMaximumJumpTableSize() : UINT_MAX; + assert(MinJumpTableSize <= MaxJumpTableSize && + "min-jump-table cannot be greater than max-jump-table"); if (N < 2 || N < MinJumpTableEntries) return; @@ -8482,9 +8486,9 @@ unsigned JumpTableSize = (Clusters[N - 1].High->getValue() - Clusters[0].Low->getValue()) .getLimitedValue(UINT_MAX - 1) + 1; - if (JumpTableSize <= MaxJumpTableSize && + if (MinJumpTableSize <= JumpTableSize && + JumpTableSize <= MaxJumpTableSize && isDense(Clusters, TotalCases, 0, N - 1, MinDensity)) { - CaseCluster JTCluster; if (buildJumpTable(Clusters, 0, N - 1, SI, DefaultMBB, JTCluster)) { Clusters[0] = JTCluster; @@ -8530,16 +8534,20 @@ JumpTableSize = (Clusters[j].High->getValue() - Clusters[i].Low->getValue()) .getLimitedValue(UINT_MAX - 1) + 1; - if (JumpTableSize <= MaxJumpTableSize && + if (MinJumpTableSize <= JumpTableSize && + JumpTableSize <= MaxJumpTableSize && isDense(Clusters, TotalCases, i, j, MinDensity)) { unsigned NumPartitions = 1 + (j == N - 1 ? 0 : MinPartitions[j + 1]); bool IsTable = j - i + 1 >= MinJumpTableEntries; unsigned Tables = IsTable + (j == N - 1 ? 0 : NumTables[j + 1]); - // If this j leads to fewer partitions, or same number of partitions - // with more lookup tables, it is a better partitioning. + // If this leads to fewer partitions, or to the same number of + // partitions with either more or fewer jump tables, + // it is a better partitioning. if (NumPartitions < MinPartitions[i] || - (NumPartitions == MinPartitions[i] && Tables > NumTables[i])) { + (NumPartitions == MinPartitions[i] && + ((MoreJumpTables && Tables > NumTables[i]) || + (!MoreJumpTables && Tables < NumTables[i])))) { MinPartitions[i] = NumPartitions; LastElement[i] = j; NumTables[i] = Tables; Index: llvm/lib/CodeGen/TargetLoweringBase.cpp =================================================================== --- llvm/lib/CodeGen/TargetLoweringBase.cpp +++ llvm/lib/CodeGen/TargetLoweringBase.cpp @@ -44,6 +44,14 @@ cl::desc("Do not create extra branches to split comparison logic."), cl::Hidden); +static cl::opt FewJumpTables + ("few-jump-tables", cl::init(false), cl::Hidden, + cl::desc("Favor fewer jump tables, with everything else being equal.")); + +static cl::opt MinimumJumpTableSize + ("min-jump-table", cl::init(0), cl::Hidden, + cl::desc("Set minimum number of jump table entries.")); + static cl::opt MaximumJumpTableSize ("max-jump-table", cl::init(0), cl::Hidden, cl::desc("Set maximum number of jump table entries; zero for no limit.")); @@ -1836,6 +1844,14 @@ return nullptr; } +unsigned TargetLoweringBase::getMinimumJumpTableSize() const { + return MinimumJumpTableSize; +} + +void TargetLoweringBase::setMinimumJumpTableSize(unsigned Val) { + MinimumJumpTableSize = Val; +} + unsigned TargetLoweringBase::getMaximumJumpTableSize() const { return MaximumJumpTableSize; } @@ -1843,3 +1859,11 @@ void TargetLoweringBase::setMaximumJumpTableSize(unsigned Val) { MaximumJumpTableSize = Val; } + +bool TargetLoweringBase::getFewJumpTables() const { + return FewJumpTables; +} + +void TargetLoweringBase::setFewJumpTables(bool Val) { + FewJumpTables = Val; +} Index: llvm/lib/Target/AArch64/AArch64ISelLowering.cpp =================================================================== --- llvm/lib/Target/AArch64/AArch64ISelLowering.cpp +++ llvm/lib/Target/AArch64/AArch64ISelLowering.cpp @@ -513,9 +513,15 @@ setPrefFunctionAlignment(STI.getPrefFunctionAlignment()); setPrefLoopAlignment(STI.getPrefLoopAlignment()); - // Only change the limit for entries in a jump table if specified by + // Only change the limits for entries in a jump table if specified by // the subtarget, but not at the command line. - unsigned MaxJT = STI.getMaximumJumpTableSize(); + const bool FewJT = STI.getFewJumpTables(); + if (FewJT && !getFewJumpTables()) + setFewJumpTables(FewJT); + const unsigned MinJT = STI.getMinimumJumpTableSize(); + if (MinJT && getMinimumJumpTableSize() == 0) + setMinimumJumpTableSize(MinJT); + const unsigned MaxJT = STI.getMaximumJumpTableSize(); if (MaxJT && getMaximumJumpTableSize() == 0) setMaximumJumpTableSize(MaxJT); Index: llvm/lib/Target/AArch64/AArch64Subtarget.h =================================================================== --- llvm/lib/Target/AArch64/AArch64Subtarget.h +++ llvm/lib/Target/AArch64/AArch64Subtarget.h @@ -90,6 +90,8 @@ unsigned MaxPrefetchIterationsAhead = UINT_MAX; unsigned PrefFunctionAlignment = 0; unsigned PrefLoopAlignment = 0; + bool FewJumpTables = false; + unsigned MinJumpTableSize = 0; unsigned MaxJumpTableSize = 0; // ReserveX18 - X18 is not available as a general purpose register. @@ -204,6 +206,8 @@ unsigned getPrefFunctionAlignment() const { return PrefFunctionAlignment; } unsigned getPrefLoopAlignment() const { return PrefLoopAlignment; } + bool getFewJumpTables() const { return FewJumpTables; } + unsigned getMinimumJumpTableSize() const { return MinJumpTableSize; } unsigned getMaximumJumpTableSize() const { return MaxJumpTableSize; } /// CPU has TBI (top byte of addresses is ignored during HW address Index: llvm/lib/Target/AArch64/AArch64Subtarget.cpp =================================================================== --- llvm/lib/Target/AArch64/AArch64Subtarget.cpp +++ llvm/lib/Target/AArch64/AArch64Subtarget.cpp @@ -65,6 +65,8 @@ case ExynosM1: PrefFunctionAlignment = 4; PrefLoopAlignment = 3; + // FIXME: FewJumpTables = true; + // FIXME: MinJumpTableSize = 4; MaxJumpTableSize = 12; break; case Kryo: Index: llvm/test/CodeGen/AArch64/max-jump-table.ll =================================================================== --- llvm/test/CodeGen/AArch64/max-jump-table.ll +++ llvm/test/CodeGen/AArch64/max-jump-table.ll @@ -1,7 +1,7 @@ -; RUN: llc %s -O2 -print-machineinstrs -mtriple=aarch64-linux-gnu -jump-table-density=40 -o - 2>%t; FileCheck %s --check-prefixes=CHECK,CHECK0 <%t -; RUN: llc %s -O2 -print-machineinstrs -mtriple=aarch64-linux-gnu -jump-table-density=40 -max-jump-table=4 -o - 2>%t; FileCheck %s --check-prefixes=CHECK,CHECK4 <%t -; RUN: llc %s -O2 -print-machineinstrs -mtriple=aarch64-linux-gnu -jump-table-density=40 -max-jump-table=8 -o - 2>%t; FileCheck %s --check-prefixes=CHECK,CHECK8 <%t -; RUN: llc %s -O2 -print-machineinstrs -mtriple=aarch64-linux-gnu -jump-table-density=40 -mcpu=exynos-m1 -o - 2>%t; FileCheck %s --check-prefixes=CHECK,CHECKM1 <%t +; RUN: llc %s -O2 -print-machineinstrs -mtriple=aarch64-linux-gnu -jump-table-density=40 -o /dev/null 2> %t; FileCheck %s --check-prefixes=CHECK,CHECK0 < %t +; RUN: llc %s -O2 -print-machineinstrs -mtriple=aarch64-linux-gnu -jump-table-density=40 -max-jump-table=4 -o /dev/null 2> %t; FileCheck %s --check-prefixes=CHECK,CHECK4 < %t +; RUN: llc %s -O2 -print-machineinstrs -mtriple=aarch64-linux-gnu -jump-table-density=40 -max-jump-table=8 -o /dev/null 2> %t; FileCheck %s --check-prefixes=CHECK,CHECK8 < %t +; RUN: llc %s -O2 -print-machineinstrs -mtriple=aarch64-linux-gnu -jump-table-density=40 -mcpu=exynos-m1 -o /dev/null 2> %t; FileCheck %s --check-prefixes=CHECK,CHECKM1 < %t declare void @ext(i32) @@ -27,7 +27,7 @@ i32 17, label %bb17 ] ; CHECK-LABEL: function jt1: -; CHECK: Jump Tables: +; CHECK-NEXT: Jump Tables: ; CHECK0-NEXT: jt#0: ; CHECK0-NOT: jt#1: ; CHECK4-NEXT: jt#0: @@ -77,7 +77,7 @@ i32 15, label %bb6 ] ; CHECK-LABEL: function jt2: -; CHECK: Jump Tables: +; CHECK-NEXT: Jump Tables: ; CHECK0-NEXT: jt#0: BB#1 BB#2 BB#3 BB#4 BB#7 BB#7 BB#7 BB#7 BB#7 BB#7 BB#7 BB#7 BB#7 BB#5 BB#6{{$}} ; CHECK4-NEXT: jt#0: BB#1 BB#2 BB#3 BB#4{{$}} ; CHECK8-NEXT: jt#0: BB#1 BB#2 BB#3 BB#4{{$}}