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 @@ -623,7 +623,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; SDValue getDynamicTLSAddr(GlobalAddressSDNode *N, SelectionDAG &DAG) 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 @@ -3686,7 +3686,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()); @@ -3725,10 +3725,27 @@ return DAG.getNode(RISCVISD::ADD_LO, DL, Ty, MNHi, AddrLo); } 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 (PseudoLGA sym), which + // expands to (ld (addi (auipc %got_pcrel_hi(sym)) %pcrel_lo(auipc))). + MachineFunction &MF = DAG.getMachineFunction(); + MachineMemOperand *MemOp = MF.getMachineMemOperand( + MachinePointerInfo::getGOT(MF), + MachineMemOperand::MOLoad | MachineMemOperand::MODereferenceable | + MachineMemOperand::MOInvariant, + LLT(Ty.getSimpleVT()), Align(Ty.getFixedSizeInBits() / 8)); + SDValue Load = + DAG.getMemIntrinsicNode(RISCVISD::LGA, DL, + DAG.getVTList(Ty, MVT::Other), + {DAG.getEntryNode(), Addr}, Ty, MemOp); + return Load; + } + // 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 DAG.getNode(RISCVISD::LLA, DL, Ty, Addr); } } @@ -3739,7 +3756,8 @@ SDLoc DL(Op); GlobalAddressSDNode *N = cast(Op); assert(N->getOffset() == 0 && "unexpected offset in global node"); - return getAddr(N, DAG, N->getGlobal()->isDSOLocal()); + const GlobalValue *GV = N->getGlobal(); + return getAddr(N, DAG, GV->isDSOLocal(), GV->hasExternalWeakLinkage()); } SDValue RISCVTargetLowering::lowerBlockAddress(SDValue Op, 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 @@ -157,8 +157,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