Index: lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp =================================================================== --- lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp +++ lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp @@ -503,10 +503,12 @@ bool IsConstantImm = evaluateConstantImm(getImm(), Imm, VK); if (!IsConstantImm) { IsValid = RISCVAsmParser::classifySymbolRef(getImm(), VK, Imm); - return IsValid && VK == RISCVMCExpr::VK_RISCV_PCREL_HI; + return IsValid && (VK == RISCVMCExpr::VK_RISCV_PCREL_HI || + VK == RISCVMCExpr::VK_RISCV_GOT_HI); } else { return isUInt<20>(Imm) && (VK == RISCVMCExpr::VK_RISCV_None || - VK == RISCVMCExpr::VK_RISCV_PCREL_HI); + VK == RISCVMCExpr::VK_RISCV_PCREL_HI || + VK == RISCVMCExpr::VK_RISCV_GOT_HI); } } @@ -859,8 +861,8 @@ case Match_InvalidUImm20AUIPC: return generateImmOutOfRangeError( Operands, ErrorInfo, 0, (1 << 20) - 1, - "operand must be a symbol with %pcrel_hi() modifier or an integer in " - "the range"); + "operand must be a symbol with %pcrel_hi/%got_hi() modifier or an " + "integer in the range"); case Match_InvalidSImm21Lsb0JAL: return generateImmOutOfRangeError( Operands, ErrorInfo, -(1 << 20), (1 << 20) - 2, Index: lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h =================================================================== --- lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h +++ lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h @@ -85,6 +85,7 @@ { "fixup_riscv_pcrel_hi20", 12, 20, MCFixupKindInfo::FKF_IsPCRel }, { "fixup_riscv_pcrel_lo12_i", 20, 12, MCFixupKindInfo::FKF_IsPCRel }, { "fixup_riscv_pcrel_lo12_s", 0, 32, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_riscv_got_hi20", 12, 20, MCFixupKindInfo::FKF_IsPCRel }, { "fixup_riscv_jal", 12, 20, MCFixupKindInfo::FKF_IsPCRel }, { "fixup_riscv_branch", 0, 32, MCFixupKindInfo::FKF_IsPCRel }, { "fixup_riscv_rvc_jump", 2, 11, MCFixupKindInfo::FKF_IsPCRel }, Index: lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp =================================================================== --- lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp +++ lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp @@ -147,6 +147,7 @@ return (((Value >> 5) & 0x7f) << 25) | ((Value & 0x1f) << 7); case RISCV::fixup_riscv_hi20: case RISCV::fixup_riscv_pcrel_hi20: + case RISCV::fixup_riscv_got_hi20: // Add 1 if bit 11 is 1, to compensate for low 12 bits being negative. return ((Value + 0x800) >> 12) & 0xfffff; case RISCV::fixup_riscv_jal: { Index: lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp =================================================================== --- lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp +++ lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp @@ -84,6 +84,8 @@ return ELF::R_RISCV_PCREL_LO12_I; case RISCV::fixup_riscv_pcrel_lo12_s: return ELF::R_RISCV_PCREL_LO12_S; + case RISCV::fixup_riscv_got_hi20: + return ELF::R_RISCV_GOT_HI20; case RISCV::fixup_riscv_jal: return ELF::R_RISCV_JAL; case RISCV::fixup_riscv_branch: Index: lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h =================================================================== --- lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h +++ lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h @@ -35,6 +35,9 @@ // fixup_riscv_pcrel_lo12_s - 12-bit fixup corresponding to pcrel_lo(foo) for // the S-type store instructions fixup_riscv_pcrel_lo12_s, + // fixup_riscv_got_hi20 - 20-bit fixup corresponding to got_hi(foo) for + // instructions like auipc + fixup_riscv_got_hi20, // fixup_riscv_jal - 20-bit fixup for symbol references in the jal // instruction fixup_riscv_jal, Index: lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp =================================================================== --- lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp +++ lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp @@ -235,6 +235,9 @@ case RISCVMCExpr::VK_RISCV_PCREL_HI: FixupKind = RISCV::fixup_riscv_pcrel_hi20; break; + case RISCVMCExpr::VK_RISCV_GOT_HI: + FixupKind = RISCV::fixup_riscv_got_hi20; + break; case RISCVMCExpr::VK_RISCV_CALL: FixupKind = RISCV::fixup_riscv_call; break; Index: lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h =================================================================== --- lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h +++ lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h @@ -29,6 +29,7 @@ VK_RISCV_HI, VK_RISCV_PCREL_LO, VK_RISCV_PCREL_HI, + VK_RISCV_GOT_HI, VK_RISCV_CALL, VK_RISCV_Invalid }; Index: lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp =================================================================== --- lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp +++ lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp @@ -55,6 +55,7 @@ case VK_RISCV_HI: case VK_RISCV_PCREL_LO: case VK_RISCV_PCREL_HI: + case VK_RISCV_GOT_HI: return false; } } @@ -72,6 +73,7 @@ .Case("hi", VK_RISCV_HI) .Case("pcrel_lo", VK_RISCV_PCREL_LO) .Case("pcrel_hi", VK_RISCV_PCREL_HI) + .Case("got_hi", VK_RISCV_GOT_HI) .Default(VK_RISCV_Invalid); } @@ -87,6 +89,8 @@ return "pcrel_lo"; case VK_RISCV_PCREL_HI: return "pcrel_hi"; + case VK_RISCV_GOT_HI: + return "got_hi"; } } @@ -94,7 +98,7 @@ MCValue Value; if (Kind == VK_RISCV_PCREL_HI || Kind == VK_RISCV_PCREL_LO || - Kind == VK_RISCV_CALL) + Kind == VK_RISCV_GOT_HI || Kind == VK_RISCV_CALL) return false; if (!getSubExpr()->evaluateAsRelocatable(Value, nullptr, nullptr)) Index: lib/Target/RISCV/RISCVISelLowering.h =================================================================== --- lib/Target/RISCV/RISCVISelLowering.h +++ lib/Target/RISCV/RISCVISelLowering.h @@ -112,6 +112,9 @@ return true; } + template + SDValue getAddrPIC(NodeTy *N, SelectionDAG &DAG, bool UseGOT, + unsigned Flags = 0) const; template SDValue getAddr(NodeTy *N, SelectionDAG &DAG, unsigned Flags = 0) const; Index: lib/Target/RISCV/RISCVISelLowering.cpp =================================================================== --- lib/Target/RISCV/RISCVISelLowering.cpp +++ lib/Target/RISCV/RISCVISelLowering.cpp @@ -349,6 +349,28 @@ N->getOffset(), Flags); } +template +SDValue RISCVTargetLowering::getAddrPIC(NodeTy *N, SelectionDAG &DAG, + bool UseGOT, unsigned Flags) const { + SDLoc DL(N); + EVT Ty = getPointerTy(DAG.getDataLayout()); + + if (UseGOT) { + // Use PC-relative addressing to access the GOT for this symbol, then load + // the address from the GOT. This generates the pattern + // (ld (WrapperPCRel %got_hi(sym))). + SDValue Addr = getTargetNode(N, DL, Ty, DAG, Flags | RISCVII::MO_GOT_HI); + SDValue Wrapper = DAG.getNode(RISCVISD::WRAPPER_PCREL, DL, Ty, Addr); + return DAG.getLoad(Ty, DL, DAG.getEntryNode(), Wrapper, + MachinePointerInfo()); + } + + // Use PC-relative addressing to access the symbol. This generates the pattern + // (WrapperPCRel %pcrel_hi(sym)). + SDValue Addr = getTargetNode(N, DL, Ty, DAG, Flags | RISCVII::MO_PCREL_HI); + return DAG.getNode(RISCVISD::WRAPPER_PCREL, DL, Ty, Addr); +} + template SDValue RISCVTargetLowering::getAddr(NodeTy *N, SelectionDAG &DAG, unsigned Flags) const { @@ -384,10 +406,14 @@ int64_t Offset = N->getOffset(); MVT XLenVT = Subtarget.getXLenVT(); - if (isPositionIndependent()) - report_fatal_error("Unable to lowerGlobalAddress"); - - SDValue Addr = getAddr(N, DAG); + SDValue Addr; + if (isPositionIndependent()) { + const GlobalValue *GV = N->getGlobal(); + bool UseGOT = + !getTargetMachine().shouldAssumeDSOLocal(*GV->getParent(), GV); + Addr = getAddrPIC(N, DAG, UseGOT); + } else + Addr = getAddr(N, DAG); // In order to maximise the opportunity for common subexpression elimination, // emit a separate ADD node for the global address offset instead of folding @@ -404,7 +430,7 @@ BlockAddressSDNode *N = cast(Op); if (isPositionIndependent()) - report_fatal_error("Unable to lowerBlockAddress"); + return getAddrPIC(N, DAG, /*UseGOT=*/false); return getAddr(N, DAG); } @@ -414,7 +440,7 @@ ConstantPoolSDNode *N = cast(Op); if (isPositionIndependent()) - report_fatal_error("Unable to lowerConstantPool"); + return getAddrPIC(N, DAG, /*UseGOT=*/false); return getAddr(N, DAG); } Index: lib/Target/RISCV/RISCVMCInstLower.cpp =================================================================== --- lib/Target/RISCV/RISCVMCInstLower.cpp +++ lib/Target/RISCV/RISCVMCInstLower.cpp @@ -49,6 +49,9 @@ case RISCVII::MO_PCREL_HI: Kind = RISCVMCExpr::VK_RISCV_PCREL_HI; break; + case RISCVII::MO_GOT_HI: + Kind = RISCVMCExpr::VK_RISCV_GOT_HI; + break; } const MCExpr *ME = Index: lib/Target/RISCV/Utils/RISCVBaseInfo.h =================================================================== --- lib/Target/RISCV/Utils/RISCVBaseInfo.h +++ lib/Target/RISCV/Utils/RISCVBaseInfo.h @@ -53,6 +53,7 @@ MO_HI, MO_PCREL_LO, MO_PCREL_HI, + MO_GOT_HI, }; } // namespace RISCVII Index: test/CodeGen/RISCV/pic-models.ll =================================================================== --- /dev/null +++ test/CodeGen/RISCV/pic-models.ll @@ -0,0 +1,54 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=riscv32 -relocation-model=static < %s \ +; RUN: | FileCheck -check-prefix=RV32-STATIC %s +; RUN: llc -mtriple=riscv32 -relocation-model=pic < %s \ +; RUN: | FileCheck -check-prefix=RV32-PIC %s + +; Check basic lowering of PIC addressing. +; TODO: Check other relocation models? + +@external_var = external global i32 +@internal_var = internal global i32 42 + + +; external address + +define i32* @f1() { +; RV32-STATIC-LABEL: f1: +; RV32-STATIC: # %bb.0: # %entry +; RV32-STATIC-NEXT: lui a0, %hi(external_var) +; RV32-STATIC-NEXT: addi a0, a0, %lo(external_var) +; RV32-STATIC-NEXT: ret +; +; RV32-PIC-LABEL: f1: +; RV32-PIC: # %bb.0: # %entry +; RV32-PIC-NEXT: .LBB0_1: # %entry +; RV32-PIC-NEXT: # Label of block must be emitted +; RV32-PIC-NEXT: auipc a0, %got_hi(external_var) +; RV32-PIC-NEXT: addi a0, a0, %pcrel_lo(.LBB0_1) +; RV32-PIC-NEXT: lw a0, 0(a0) +; RV32-PIC-NEXT: ret +entry: + ret i32* @external_var +} + + +; internal address + +define i32* @f2() { +; RV32-STATIC-LABEL: f2: +; RV32-STATIC: # %bb.0: # %entry +; RV32-STATIC-NEXT: lui a0, %hi(internal_var) +; RV32-STATIC-NEXT: addi a0, a0, %lo(internal_var) +; RV32-STATIC-NEXT: ret +; +; RV32-PIC-LABEL: f2: +; RV32-PIC: # %bb.0: # %entry +; RV32-PIC-NEXT: .LBB1_1: # %entry +; RV32-PIC-NEXT: # Label of block must be emitted +; RV32-PIC-NEXT: auipc a0, %pcrel_hi(internal_var) +; RV32-PIC-NEXT: addi a0, a0, %pcrel_lo(.LBB1_1) +; RV32-PIC-NEXT: ret +entry: + ret i32* @internal_var +} Index: test/MC/RISCV/rv32i-invalid.s =================================================================== --- test/MC/RISCV/rv32i-invalid.s +++ test/MC/RISCV/rv32i-invalid.s @@ -40,7 +40,7 @@ ## uimm20 lui a0, -1 # CHECK: :[[@LINE]]:9: error: operand must be a symbol with %hi() modifier or an integer in the range [0, 1048575] lui s0, 1048576 # CHECK: :[[@LINE]]:9: error: operand must be a symbol with %hi() modifier or an integer in the range [0, 1048575] -auipc zero, -0xf # CHECK: :[[@LINE]]:13: error: operand must be a symbol with %pcrel_hi() modifier or an integer in the range [0, 1048575] +auipc zero, -0xf # CHECK: :[[@LINE]]:13: error: operand must be a symbol with %pcrel_hi/%got_hi() modifier or an integer in the range [0, 1048575] ## simm21_lsb0 jal gp, -1048578 # CHECK: :[[@LINE]]:9: error: immediate must be a multiple of 2 bytes in the range [-1048576, 1048574] @@ -105,7 +105,7 @@ ## uimm20 lui a0, %lo(1) # CHECK: :[[@LINE]]:9: error: operand must be a symbol with %hi() modifier or an integer in the range [0, 1048575] -auipc a1, %lo(foo) # CHECK: :[[@LINE]]:11: error: operand must be a symbol with %pcrel_hi() modifier or an integer in the range [0, 1048575] +auipc a1, %lo(foo) # CHECK: :[[@LINE]]:11: error: operand must be a symbol with %pcrel_hi/%got_hi() modifier or an integer in the range [0, 1048575] ## simm21_lsb0 jal gp, %lo(1) # CHECK: :[[@LINE]]:9: error: immediate must be a multiple of 2 bytes in the range [-1048576, 1048574] @@ -125,10 +125,10 @@ lui a0, %pcrel_lo(foo) # CHECK: :[[@LINE]]:9: error: operand must be a symbol with %hi() modifier or an integer in the range [0, 1048575] lui a0, %pcrel_hi(foo) # CHECK: :[[@LINE]]:9: error: operand must be a symbol with %hi() modifier or an integer in the range [0, 1048575] -auipc a0, foo # CHECK: :[[@LINE]]:11: error: operand must be a symbol with %pcrel_hi() modifier or an integer in the range [0, 1048575] -auipc a0, %lo(foo) # CHECK: :[[@LINE]]:11: error: operand must be a symbol with %pcrel_hi() modifier or an integer in the range [0, 1048575] -auipc a0, %hi(foo) # CHECK: :[[@LINE]]:11: error: operand must be a symbol with %pcrel_hi() modifier or an integer in the range [0, 1048575] -auipc a0, %pcrel_lo(foo) # CHECK: :[[@LINE]]:11: error: operand must be a symbol with %pcrel_hi() modifier or an integer in the range [0, 1048575] +auipc a0, foo # CHECK: :[[@LINE]]:11: error: operand must be a symbol with %pcrel_hi/%got_hi() modifier or an integer in the range [0, 1048575] +auipc a0, %lo(foo) # CHECK: :[[@LINE]]:11: error: operand must be a symbol with %pcrel_hi/%got_hi() modifier or an integer in the range [0, 1048575] +auipc a0, %hi(foo) # CHECK: :[[@LINE]]:11: error: operand must be a symbol with %pcrel_hi/%got_hi() modifier or an integer in the range [0, 1048575] +auipc a0, %pcrel_lo(foo) # CHECK: :[[@LINE]]:11: error: operand must be a symbol with %pcrel_hi/%got_hi() modifier or an integer in the range [0, 1048575] # Unrecognized operand modifier addi t0, sp, %modifer(255) # CHECK: :[[@LINE]]:15: error: unrecognized operand modifier Index: test/MC/RISCV/rv32i-valid.s =================================================================== --- test/MC/RISCV/rv32i-valid.s +++ test/MC/RISCV/rv32i-valid.s @@ -53,6 +53,11 @@ # CHECK-OBJ: auipc a0, 0 # CHECK-OBJ: R_RISCV_PCREL_HI20 foo auipc a0, %pcrel_hi(foo) +# CHECK-ASM: auipc a0, %got_hi(foo) +# CHECK-ASM: encoding: [0x17,0bAAAA0101,A,A] +# CHECK-OBJ: auipc a0, 0 +# CHECK-OBJ: R_RISCV_GOT_HI20 foo +auipc a0, %got_hi(foo) # CHECK-ASM-AND-OBJ: jal a2, 1048574 # CHECK-ASM: encoding: [0x6f,0xf6,0xff,0x7f]