diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.h b/llvm/lib/Target/RISCV/RISCVISelLowering.h --- a/llvm/lib/Target/RISCV/RISCVISelLowering.h +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.h @@ -520,7 +520,8 @@ RISCVCCAssignFn Fn) const; template - SDValue getAddr(NodeTy *N, SelectionDAG &DAG, bool IsLocal = true) const; + SDValue getAddr(NodeTy *N, SelectionDAG &DAG, bool IsLocal = true, + bool IsExternWeak = false) const; SDValue getStaticTLSAddr(GlobalAddressSDNode *N, SelectionDAG &DAG, bool UseGOT) const; diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp --- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp @@ -2700,7 +2700,7 @@ template SDValue RISCVTargetLowering::getAddr(NodeTy *N, SelectionDAG &DAG, - bool IsLocal) const { + bool IsLocal, bool IsExternWeak) const { SDLoc DL(N); EVT Ty = getPointerTy(DAG.getDataLayout()); @@ -2730,10 +2730,16 @@ return SDValue(DAG.getMachineNode(RISCV::ADDI, DL, Ty, MNHi, AddrLo), 0); } case CodeModel::Medium: { + SDValue Addr = getTargetNode(N, DL, Ty, DAG, 0); + if (IsExternWeak) + // Extern weak symbols must be addressed indirectly as 0 may not be + // within 2GiB of PC. This generates the pattern (PseudoLA sym), which + // expands to (ld (addi (auipc %got_pcrel_hi(sym)) %pcrel_lo(auipc))). + return SDValue(DAG.getMachineNode(RISCV::PseudoLGA, DL, Ty, Addr), 0); + // Generate a sequence for accessing addresses within any 2GiB range within // the address space. This generates the pattern (PseudoLLA sym), which // expands to (addi (auipc %pcrel_hi(sym)) %pcrel_lo(auipc)). - SDValue Addr = getTargetNode(N, DL, Ty, DAG, 0); return SDValue(DAG.getMachineNode(RISCV::PseudoLLA, DL, Ty, Addr), 0); } } @@ -2749,7 +2755,8 @@ const GlobalValue *GV = N->getGlobal(); bool IsLocal = getTargetMachine().shouldAssumeDSOLocal(*GV->getParent(), GV); - SDValue Addr = getAddr(N, DAG, IsLocal); + bool IsExternWeak = GV->hasExternalWeakLinkage(); + SDValue Addr = getAddr(N, DAG, IsLocal, IsExternWeak); // In order to maximise the opportunity for common subexpression elimination, // emit a separate ADD node for the global address offset instead of folding diff --git a/llvm/test/CodeGen/RISCV/codemodel-lowering.ll b/llvm/test/CodeGen/RISCV/codemodel-lowering.ll --- a/llvm/test/CodeGen/RISCV/codemodel-lowering.ll +++ b/llvm/test/CodeGen/RISCV/codemodel-lowering.ll @@ -161,8 +161,8 @@ ; RV32I-MEDIUM-LABEL: lower_extern_weak: ; RV32I-MEDIUM: # %bb.0: ; RV32I-MEDIUM-NEXT: .LBB4_1: # Label of block must be emitted -; RV32I-MEDIUM-NEXT: auipc a0, %pcrel_hi(W) -; RV32I-MEDIUM-NEXT: addi a0, a0, %pcrel_lo(.LBB4_1) +; RV32I-MEDIUM-NEXT: auipc a0, %got_pcrel_hi(W) +; RV32I-MEDIUM-NEXT: lw a0, %pcrel_lo(.LBB4_1)(a0) ; RV32I-MEDIUM-NEXT: lw a0, 0(a0) ; RV32I-MEDIUM-NEXT: ret %1 = load volatile i32, i32* @W