Index: lib/Target/Mips/MipsISelLowering.cpp =================================================================== --- lib/Target/Mips/MipsISelLowering.cpp +++ lib/Target/Mips/MipsISelLowering.cpp @@ -3152,15 +3152,27 @@ // The long-calls feature is ignored in case of PIC. // While we do not support -mshared / -mno-shared properly, // ignore long-calls in case of -mabicalls too. - if (Subtarget.useLongCalls() && !Subtarget.isABICalls() && !IsPIC) { - // Get the address of the callee into a register to prevent - // using of the `jal` instruction for the direct call. - if (auto *N = dyn_cast(Callee)) - Callee = Subtarget.hasSym32() ? getAddrNonPIC(N, SDLoc(N), Ty, DAG) - : getAddrNonPICSym64(N, SDLoc(N), Ty, DAG); - else if (auto *N = dyn_cast(Callee)) - Callee = Subtarget.hasSym32() ? getAddrNonPIC(N, SDLoc(N), Ty, DAG) - : getAddrNonPICSym64(N, SDLoc(N), Ty, DAG); + if (!Subtarget.isABICalls() && !IsPIC) { + if (auto *N = dyn_cast(Callee)) { + if (Subtarget.useLongCalls()) + Callee = Subtarget.hasSym32() + ? getAddrNonPIC(N, SDLoc(N), Ty, DAG) + : getAddrNonPICSym64(N, SDLoc(N), Ty, DAG); + } else if (auto *N = dyn_cast(Callee)) { + bool UseLongCalls = Subtarget.useLongCalls(); + // If the function has long-call/far/near attribute + // it overrides command line switch pased to the backend. + if (auto *F = dyn_cast(N->getGlobal())) { + if (F->hasFnAttribute("long-call")) + UseLongCalls = true; + else if (F->hasFnAttribute("near-call")) + UseLongCalls = false; + } + if (UseLongCalls) + Callee = Subtarget.hasSym32() + ? getAddrNonPIC(N, SDLoc(N), Ty, DAG) + : getAddrNonPICSym64(N, SDLoc(N), Ty, DAG); + } } if (GlobalAddressSDNode *G = dyn_cast(Callee)) { Index: test/CodeGen/Mips/long-call-attr.ll =================================================================== --- /dev/null +++ test/CodeGen/Mips/long-call-attr.ll @@ -0,0 +1,30 @@ +; RUN: llc -march=mips -mcpu=mips32 --mattr=+long-calls,+noabicalls < %s \ +; RUN: | FileCheck %s +; RUN: llc -march=mips -mcpu=mips32 --mattr=-long-calls,+noabicalls < %s \ +; RUN: | FileCheck %s + +declare void @far() #0 + +define void @near() #1 { + ret void +} + +define void @foo() #2 { + call void @far() #3 + +; CHECK: lui $1, %hi(far) +; CHECK-NEXT: addiu $25, $1, %lo(far) +; CHECK-NEXT: jalr $25 + + call void @near() #4 + +; CHECK: jal near + + ret void +} + +attributes #0 = { "long-call" } +attributes #1 = { noinline nounwind "near-call" } +attributes #2 = { noinline nounwind } +attributes #3 = { "long-call" } +attributes #4 = { "near-call" }