Index: include/llvm/IR/Attributes.td =================================================================== --- include/llvm/IR/Attributes.td +++ include/llvm/IR/Attributes.td @@ -165,6 +165,7 @@ 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 @@ -194,4 +195,5 @@ def : MergeRule<"setAND">; def : MergeRule<"setAND">; def : MergeRule<"setOR">; +def : MergeRule<"setOR">; def : MergeRule<"adjustCallerSSPLevel">; Index: lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp =================================================================== --- lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -7956,7 +7956,14 @@ return NumCases * 100 >= Range * Density; } -static inline bool areJTsAllowed(const TargetLowering &TLI) { +static inline bool areJTsAllowed(const TargetLowering &TLI, + const SwitchInst *SI) { + // return false if function containing SI has NoUseJumpTable Attribute set + const Function *fn = SI->getParent()->getParent(); + if (fn->hasFnAttribute("no-jump-tables") && + fn->getFnAttribute("no-jump-tables").getValueAsString() == "true") + return false; + return TLI.isOperationLegalOrCustom(ISD::BR_JT, MVT::Other) || TLI.isOperationLegalOrCustom(ISD::BRIND, MVT::Other); } @@ -8050,7 +8057,7 @@ #endif const TargetLowering &TLI = DAG.getTargetLoweringInfo(); - if (!areJTsAllowed(TLI)) + if (!areJTsAllowed(TLI, SI)) return; const int64_t N = Clusters.size(); Index: test/CodeGen/X86/switch.ll =================================================================== --- test/CodeGen/X86/switch.ll +++ test/CodeGen/X86/switch.ll @@ -30,6 +30,47 @@ ; 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 @@ 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 Index: test/Transforms/Inline/attributes.ll =================================================================== --- test/Transforms/Inline/attributes.ll +++ test/Transforms/Inline/attributes.ll @@ -241,6 +241,49 @@ ; 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