diff --git a/llvm/include/llvm/IR/Attributes.td b/llvm/include/llvm/IR/Attributes.td index a9bcda094b77..8b490ec4fc84 100644 --- a/llvm/include/llvm/IR/Attributes.td +++ b/llvm/include/llvm/IR/Attributes.td @@ -168,6 +168,7 @@ def LessPreciseFPMAD : StrBoolAttr<"less-precise-fpmad">; def NoInfsFPMath : StrBoolAttr<"no-infs-fp-math">; def NoNansFPMath : StrBoolAttr<"no-nans-fp-math">; def UnsafeFPMath : StrBoolAttr<"unsafe-fp-math">; +def NoJumpTables : StrBoolAttr<"no-jump-tables">; class CompatRule { // The name of the function called to check the attribute of the caller and @@ -197,4 +198,5 @@ def : MergeRule<"setAND">; def : MergeRule<"setAND">; def : MergeRule<"setAND">; def : MergeRule<"setOR">; +def : MergeRule<"setOR">; def : MergeRule<"adjustCallerSSPLevel">; diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp index 0f610cee3b88..71c015df520f 100644 --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -7961,7 +7961,12 @@ bool SelectionDAGBuilder::isDense(const CaseClusterVector &Clusters, return NumCases * 100 >= Range * Density; } -static inline bool areJTsAllowed(const TargetLowering &TLI) { +static inline bool areJTsAllowed(const TargetLowering &TLI, + const SwitchInst *SI) { + const Function *Fn = SI->getParent()->getParent(); + if (Fn->getFnAttribute("no-jump-tables").getValueAsString() == "true") + return false; + return TLI.isOperationLegalOrCustom(ISD::BR_JT, MVT::Other) || TLI.isOperationLegalOrCustom(ISD::BRIND, MVT::Other); } @@ -8055,7 +8060,7 @@ void SelectionDAGBuilder::findJumpTables(CaseClusterVector &Clusters, #endif const TargetLowering &TLI = DAG.getTargetLoweringInfo(); - if (!areJTsAllowed(TLI)) + if (!areJTsAllowed(TLI, SI)) return; const int64_t N = Clusters.size(); diff --git a/llvm/test/CodeGen/X86/switch.ll b/llvm/test/CodeGen/X86/switch.ll index 70da4a2abb7d..5bba78d4490f 100644 --- a/llvm/test/CodeGen/X86/switch.ll +++ b/llvm/test/CodeGen/X86/switch.ll @@ -30,6 +30,47 @@ return: ret void ; NOOPT: jmpq } +; Should never be lowered as a jump table because of the attribute +define void @basic_nojumptable(i32 %x) "no-jump-tables"="true" { +entry: + switch i32 %x, label %return [ + i32 3, label %bb0 + i32 1, label %bb1 + i32 4, label %bb1 + i32 5, label %bb2 + ] +bb0: tail call void @g(i32 0) br label %return +bb1: tail call void @g(i32 1) br label %return +bb2: tail call void @g(i32 1) br label %return +return: ret void + +; Lowered as a jump table, both with and without optimization. +; CHECK-LABEL: basic_nojumptable +; CHECK-NOT: jmpq *.LJTI +} + +; Should be lowered as a jump table because of the attribute +define void @basic_nojumptable_false(i32 %x) "no-jump-tables"="false" { +entry: + switch i32 %x, label %return [ + i32 3, label %bb0 + i32 1, label %bb1 + i32 4, label %bb1 + i32 5, label %bb2 + ] +bb0: tail call void @g(i32 0) br label %return +bb1: tail call void @g(i32 1) br label %return +bb2: tail call void @g(i32 1) br label %return +return: ret void + +; Lowered as a jump table, both with and without optimization. +; CHECK-LABEL: basic_nojumptable_false +; CHECK: decl +; CHECK: cmpl $4 +; CHECK: ja +; CHECK: jmpq *.LJTI +} + define void @simple_ranges(i32 %x) { entry: @@ -47,6 +88,8 @@ bb0: tail call void @g(i32 0) br label %return bb1: tail call void @g(i32 1) br label %return return: ret void + + ; Should be lowered to two range checks. ; CHECK-LABEL: simple_ranges ; CHECK: leal -100 diff --git a/llvm/test/Transforms/Inline/attributes.ll b/llvm/test/Transforms/Inline/attributes.ll index 0458fa23f795..62b10fb3beb5 100644 --- a/llvm/test/Transforms/Inline/attributes.ll +++ b/llvm/test/Transforms/Inline/attributes.ll @@ -241,6 +241,49 @@ define i32 @test_no-implicit-float3(i32 %i) noimplicitfloat { ; CHECK-NEXT: ret i32 } +; Check that no-jump-tables flag propagates from inlined callee to caller + +define i32 @no-use-jump-tables_callee0(i32 %i) { + ret i32 %i +; CHECK: @no-use-jump-tables_callee0(i32 %i) { +; CHECK-NEXT: ret i32 +} + +define i32 @no-use-jump-tables_callee1(i32 %i) "no-jump-tables"="true" { + ret i32 %i +; CHECK: @no-use-jump-tables_callee1(i32 %i) [[NOUSEJUMPTABLES:#[0-9]+]] { +; CHECK-NEXT: ret i32 +} + +define i32 @test_no-use-jump-tables0(i32 %i) { + %1 = call i32 @no-use-jump-tables_callee0(i32 %i) + ret i32 %1 +; CHECK: @test_no-use-jump-tables0(i32 %i) { +; CHECK-NEXT: ret i32 +} + +define i32 @test_no-use-jump-tables1(i32 %i) { + %1 = call i32 @no-use-jump-tables_callee1(i32 %i) + ret i32 %1 +; CHECK: @test_no-use-jump-tables1(i32 %i) [[NOUSEJUMPTABLES]] { +; CHECK-NEXT: ret i32 +} + +define i32 @test_no-use-jump-tables2(i32 %i) "no-jump-tables"="true" { + %1 = call i32 @no-use-jump-tables_callee0(i32 %i) + ret i32 %1 +; CHECK: @test_no-use-jump-tables2(i32 %i) [[NOUSEJUMPTABLES]] { +; CHECK-NEXT: ret i32 +} + +define i32 @test_no-use-jump-tables3(i32 %i) "no-jump-tables"="true" { + %1 = call i32 @no-use-jump-tables_callee1(i32 %i) + ret i32 %1 +; CHECK: @test_no-use-jump-tables3(i32 %i) [[NOUSEJUMPTABLES]] { +; CHECK-NEXT: ret i32 +} + ; CHECK: attributes [[FPMAD_FALSE]] = { "less-precise-fpmad"="false" } ; CHECK: attributes [[FPMAD_TRUE]] = { "less-precise-fpmad"="true" } ; CHECK: attributes [[NOIMPLICITFLOAT]] = { noimplicitfloat } +; CHECK: attributes [[NOUSEJUMPTABLES]] = { "no-jump-tables"="true" } \ No newline at end of file