Index: llvm/lib/Target/RISCV/RISCVISelLowering.cpp =================================================================== --- llvm/lib/Target/RISCV/RISCVISelLowering.cpp +++ llvm/lib/Target/RISCV/RISCVISelLowering.cpp @@ -2185,14 +2185,18 @@ // If the callee is a GlobalAddress/ExternalSymbol node, turn it into a // TargetGlobalAddress/TargetExternalSymbol node so that legalize won't // split it and then direct call can be matched by PseudoCALL. + // GlobalAddress may become a normal node + // and indirectly called if using NonLazyBind. if (GlobalAddressSDNode *S = dyn_cast(Callee)) { const GlobalValue *GV = S->getGlobal(); - unsigned OpFlags = RISCVII::MO_CALL; - if (!getTargetMachine().shouldAssumeDSOLocal(*GV->getParent(), GV)) - OpFlags = RISCVII::MO_PLT; + unsigned OpFlags = + Subtarget.classifyGlobalFunctionReference(GV, getTargetMachine()); - Callee = DAG.getTargetGlobalAddress(GV, DL, PtrVT, 0, OpFlags); + if (OpFlags == RISCVII::MO_GOT_HI) + Callee = getAddr(S, DAG, /*IsLocal=*/false); + else + Callee = DAG.getTargetGlobalAddress(GV, DL, PtrVT, 0, OpFlags); } else if (ExternalSymbolSDNode *S = dyn_cast(Callee)) { unsigned OpFlags = RISCVII::MO_CALL; Index: llvm/lib/Target/RISCV/RISCVSubtarget.h =================================================================== --- llvm/lib/Target/RISCV/RISCVSubtarget.h +++ llvm/lib/Target/RISCV/RISCVSubtarget.h @@ -67,6 +67,11 @@ // definition of this function is auto-generated by tblgen. void ParseSubtargetFeatures(StringRef CPU, StringRef FS); + // Return how the function given by GV should be invoked: + // via the PLT, by taking its address from the GOT, or with a direct call. + unsigned char classifyGlobalFunctionReference(const GlobalValue *GV, + const TargetMachine &TM) const; + const RISCVFrameLowering *getFrameLowering() const override { return &FrameLowering; } Index: llvm/lib/Target/RISCV/RISCVSubtarget.cpp =================================================================== --- llvm/lib/Target/RISCV/RISCVSubtarget.cpp +++ llvm/lib/Target/RISCV/RISCVSubtarget.cpp @@ -61,6 +61,17 @@ *static_cast(&TM), *this, *RBI)); } +unsigned char RISCVSubtarget::classifyGlobalFunctionReference( + const GlobalValue *GV, const TargetMachine &TM) const { + auto *F = dyn_cast(GV); + if (!TM.shouldAssumeDSOLocal(*GV->getParent(), GV)) { + if (F && F->hasFnAttribute(Attribute::NonLazyBind)) + return RISCVII::MO_GOT_HI; + return RISCVII::MO_PLT; + } + return RISCVII::MO_CALL; +} + const CallLowering *RISCVSubtarget::getCallLowering() const { return CallLoweringInfo.get(); } Index: llvm/test/CodeGen/RISCV/no-plt.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/RISCV/no-plt.ll @@ -0,0 +1,35 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=riscv64 -relocation-model=pic < %s \ +; RUN: | FileCheck -check-prefix=RV64 %s +; RUN: llc -mtriple=riscv32 -relocation-model=pic < %s \ +; RUN: | FileCheck -check-prefix=RV32 %s + +declare void @global() nonlazybind + +define void @no_plt_call() nounwind { +; RV64-LABEL: no_plt_call: +; RV64: # %bb.0: +; RV64-NEXT: addi sp, sp, -16 +; RV64-NEXT: sd ra, 8(sp) +; RV64-NEXT: .LBB0_1: # Label of block must be emitted +; RV64-NEXT: auipc a0, %got_pcrel_hi(global) +; RV64-NEXT: ld a0, %pcrel_lo(.LBB0_1)(a0) +; RV64-NEXT: jalr a0 +; RV64-NEXT: ld ra, 8(sp) +; RV64-NEXT: addi sp, sp, 16 +; RV64-NEXT: ret +; +; RV32-LABEL: no_plt_call: +; RV32: # %bb.0: +; RV32-NEXT: addi sp, sp, -16 +; RV32-NEXT: sw ra, 12(sp) +; RV32-NEXT: .LBB0_1: # Label of block must be emitted +; RV32-NEXT: auipc a0, %got_pcrel_hi(global) +; RV32-NEXT: lw a0, %pcrel_lo(.LBB0_1)(a0) +; RV32-NEXT: jalr a0 +; RV32-NEXT: lw ra, 12(sp) +; RV32-NEXT: addi sp, sp, 16 +; RV32-NEXT: ret + call void @global() + ret void +}