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 @@ -750,7 +750,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 @@ -5158,7 +5158,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()); @@ -5201,10 +5201,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); } } @@ -5214,7 +5231,8 @@ SelectionDAG &DAG) const { 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 @@ -152,8 +152,9 @@ ; RV32I-MEDIUM-LABEL: lower_extern_weak: ; RV32I-MEDIUM: # %bb.0: ; RV32I-MEDIUM-NEXT: .Lpcrel_hi3: -; RV32I-MEDIUM-NEXT: auipc a0, %pcrel_hi(W) +; RV32I-MEDIUM-NEXT: auipc a0, %got_pcrel_hi(W) ; RV32I-MEDIUM-NEXT: lw a0, %pcrel_lo(.Lpcrel_hi3)(a0) +; RV32I-MEDIUM-NEXT: lw a0, 0(a0) ; RV32I-MEDIUM-NEXT: ret %1 = load volatile i32, ptr @W ret i32 %1