Index: lib/Analysis/IPA/InlineCost.cpp =================================================================== --- lib/Analysis/IPA/InlineCost.cpp +++ lib/Analysis/IPA/InlineCost.cpp @@ -1303,7 +1303,8 @@ attributeMatches(Caller, Callee, "target-features") && attributeMatches(Caller, Callee, Attribute::SanitizeAddress) && attributeMatches(Caller, Callee, Attribute::SanitizeMemory) && - attributeMatches(Caller, Callee, Attribute::SanitizeThread); + attributeMatches(Caller, Callee, Attribute::SanitizeThread) && + attributeMatches(Caller, Callee, "arm-long-calls"); } InlineCost InlineCostAnalysis::getInlineCost(CallSite CS, Function *Callee, Index: lib/Target/ARM/ARMISelLowering.cpp =================================================================== --- lib/Target/ARM/ARMISelLowering.cpp +++ lib/Target/ARM/ARMISelLowering.cpp @@ -1682,7 +1682,9 @@ bool isLocalARMFunc = false; ARMFunctionInfo *AFI = MF.getInfo(); - if (EnableARMLongCalls) { + if (EnableARMLongCalls.getNumOccurrences() + ? EnableARMLongCalls + : MF.getFunction()->hasFnAttribute("arm-long-calls")) { assert((Subtarget->isTargetWindows() || getTargetMachine().getRelocationModel() == Reloc::Static) && "long-calls with non-static relocation model!"); Index: test/CodeGen/ARM/fn-attr-long-calls.ll =================================================================== --- /dev/null +++ test/CodeGen/ARM/fn-attr-long-calls.ll @@ -0,0 +1,37 @@ +; RUN: llc -march arm -mcpu cortex-a8 -relocation-model=static %s -o - | FileCheck -check-prefix=NO-OPTION %s +; RUN: llc -march arm -mcpu cortex-a8 -relocation-model=static %s -o - -arm-long-calls | FileCheck -check-prefix=LONGCALL %s +; RUN: llc -march arm -mcpu cortex-a8 -relocation-model=static %s -o - -arm-long-calls=false | FileCheck -check-prefix=NO-LONGCALL %s + +; NO-OPTION-LABEL: {{_?}}caller0 +; NO-OPTION: blx {{r[0-9]+}} + +; LONGCALL-LABEL: {{_?}}caller0 +; LONGCALL: blx {{r[0-9]+}} + +; NO-LONGCALL-LABEL: {{_?}}caller0 +; NO-LONGCALL: bl {{_?}}callee0 + +define i32 @caller0() #0 { +entry: + tail call void @callee0() + ret i32 0 +} + +; NO-OPTION-LABEL: {{_?}}caller1 +; NO-OPTION: bl {{_?}}callee0 + +; LONGCALL-LABEL: {{_?}}caller1 +; LONGCALL: blx {{r[0-9]+}} + +; NO-LONGCALL-LABEL: {{_?}}caller1 +; NO-LONGCALL: bl {{_?}}callee0 + +define i32 @caller1() { +entry: + tail call void @callee0() + ret i32 0 +} + +declare void @callee0() + +attributes #0 = { "arm-long-calls" } Index: test/Transforms/Inline/attributes.ll =================================================================== --- test/Transforms/Inline/attributes.ll +++ test/Transforms/Inline/attributes.ll @@ -160,3 +160,31 @@ ; CHECK-NEXT: @test_target_features_callee1 ; CHECK-NEXT: ret i32 } + +; Check that a function doesn't get inlined if "arm-long-calls" attribute +; doesn't match. +define i32 @test_arm_long_calls_callee0(i32 %i) { + ret i32 %i +} + +define i32 @test_arm_long_calls_callee1(i32 %i) "arm-long-calls" { + ret i32 %i +} + +define i32 @test_arm_long_calls0(i32 %i) { + %1 = call i32 @test_arm_long_calls_callee0(i32 %i) + %2 = call i32 @test_arm_long_calls_callee1(i32 %1) + ret i32 %1 +; CHECK-LABEL: @test_arm_long_calls0( +; CHECK-NEXT: call i32 @test_arm_long_calls_callee1( +; CHECK-NEXT: ret i32 +} + +define i32 @test_arm_long_calls1(i32 %i) "arm-long-calls" { + %1 = call i32 @test_arm_long_calls_callee0(i32 %i) + %2 = call i32 @test_arm_long_calls_callee1(i32 %1) + ret i32 %1 +; CHECK-LABEL: @test_arm_long_calls1( +; CHECK-NEXT: call i32 @test_arm_long_calls_callee0( +; CHECK-NEXT: ret i32 +}