Index: lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp =================================================================== --- lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp +++ lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp @@ -60,7 +60,7 @@ if (FixupKind == RISCV::fixup_riscv_pcrel_lo12_i || FixupKind == RISCV::fixup_riscv_pcrel_hi20) return true; - return false; + return STI.getFeatureBits()[RISCV::FeatureRelax]; } bool fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value, Index: lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp =================================================================== --- lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp +++ lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp @@ -74,6 +74,10 @@ return ELF::R_RISCV_RVC_JUMP; case RISCV::fixup_riscv_rvc_branch: return ELF::R_RISCV_RVC_BRANCH; + case RISCV::fixup_riscv_call: + return ELF::R_RISCV_CALL; + case RISCV::fixup_riscv_relax: + return ELF::R_RISCV_RELAX; } } Index: lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h =================================================================== --- lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h +++ lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h @@ -47,6 +47,12 @@ // fixup_riscv_rvc_branch - 8-bit fixup for symbol references in the // compressed branch instruction fixup_riscv_rvc_branch, + // fixup_riscv_call - A fixup representing a call attached to the auipc + // instruction of an adjacent jalr pair. + fixup_riscv_call, + // fixup_riscv_relax - Used to generate an R_RISCV_RELAX relocation type, + // which indicates the linker may relax the instruction pair. + fixup_riscv_relax, // fixup_riscv_invalid - used as a sentinel and a marker, must be last fixup fixup_riscv_invalid, Index: lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp =================================================================== --- lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp +++ lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp @@ -138,7 +138,7 @@ unsigned RISCVMCCodeEmitter::getImmOpValue(const MCInst &MI, unsigned OpNo, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const { - + bool EnableRelax = STI.getFeatureBits()[RISCV::FeatureRelax]; const MCOperand &MO = MI.getOperand(OpNo); MCInstrDesc const &Desc = MCII.get(MI.getOpcode()); @@ -183,6 +183,11 @@ case RISCVMCExpr::VK_RISCV_PCREL_HI: FixupKind = RISCV::fixup_riscv_pcrel_hi20; break; + case RISCVMCExpr::VK_RISCV_CALL_LO: + return 0; + case RISCVMCExpr::VK_RISCV_CALL_HI: + FixupKind = RISCV::fixup_riscv_call; + break; } } else if (Kind == MCExpr::SymbolRef && cast(Expr)->getKind() == MCSymbolRefExpr::VK_None) { @@ -203,6 +208,15 @@ MCFixup::create(0, Expr, MCFixupKind(FixupKind), MI.getLoc())); ++MCNumFixups; + if (EnableRelax) { + if (FixupKind == RISCV::fixup_riscv_call) { + Fixups.push_back( + MCFixup::create(0, Expr, MCFixupKind(RISCV::fixup_riscv_relax), + MI.getLoc())); + ++MCNumFixups; + } + } + return 0; } Index: lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h =================================================================== --- lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h +++ lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h @@ -29,6 +29,8 @@ VK_RISCV_HI, VK_RISCV_PCREL_LO, VK_RISCV_PCREL_HI, + VK_RISCV_CALL_LO, + VK_RISCV_CALL_HI, VK_RISCV_Invalid }; Index: lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp =================================================================== --- lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp +++ lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp @@ -68,8 +68,10 @@ case VK_RISCV_HI: return "hi"; case VK_RISCV_PCREL_LO: + case VK_RISCV_CALL_LO: return "pcrel_lo"; case VK_RISCV_PCREL_HI: + case VK_RISCV_CALL_HI: return "pcrel_hi"; } } @@ -77,7 +79,8 @@ bool RISCVMCExpr::evaluateAsConstant(int64_t &Res) const { MCValue Value; - if (Kind == VK_RISCV_PCREL_HI || Kind == VK_RISCV_PCREL_LO) + if (Kind == VK_RISCV_PCREL_HI || Kind == VK_RISCV_PCREL_LO || + Kind == VK_RISCV_CALL_HI || Kind == VK_RISCV_CALL_LO) return false; if (!getSubExpr()->evaluateAsRelocatable(Value, nullptr, nullptr)) Index: lib/Target/RISCV/RISCV.td =================================================================== --- lib/Target/RISCV/RISCV.td +++ lib/Target/RISCV/RISCV.td @@ -55,6 +55,10 @@ def RV64 : HwMode<"+64bit">; def RV32 : HwMode<"-64bit">; +def FeatureRelax + : SubtargetFeature<"relax", "EnableLinkerRelax", "true", + "Enable Linker relaxation.">; + //===----------------------------------------------------------------------===// // Registers, calling conventions, instruction descriptions. //===----------------------------------------------------------------------===// Index: lib/Target/RISCV/RISCVAsmPrinter.cpp =================================================================== --- lib/Target/RISCV/RISCVAsmPrinter.cpp +++ lib/Target/RISCV/RISCVAsmPrinter.cpp @@ -95,13 +95,13 @@ // Create high part expression HiExpr for AUIPC. Expr = MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, OutContext); const MCExpr *HiExpr = - RISCVMCExpr::create(Expr, RISCVMCExpr::VK_RISCV_PCREL_HI, OutContext); + RISCVMCExpr::create(Expr, RISCVMCExpr::VK_RISCV_CALL_HI, OutContext); // Create low part expression LoExpr for JALR. auto HiLabel = OutContext.createTempSymbol(); Expr = MCSymbolRefExpr::create(HiLabel, MCSymbolRefExpr::VK_None, OutContext); const MCExpr *LoExpr = - RISCVMCExpr::create(Expr, RISCVMCExpr::VK_RISCV_PCREL_LO, OutContext); + RISCVMCExpr::create(Expr, RISCVMCExpr::VK_RISCV_CALL_LO, OutContext); // Emit .LtmpX: OutStreamer->EmitLabel(HiLabel); Index: lib/Target/RISCV/RISCVSubtarget.h =================================================================== --- lib/Target/RISCV/RISCVSubtarget.h +++ lib/Target/RISCV/RISCVSubtarget.h @@ -36,6 +36,7 @@ bool HasStdExtD = false; bool HasStdExtC = false; bool HasRV64 = false; + bool EnableLinkerRelax = false; unsigned XLen = 32; MVT XLenVT = MVT::i32; RISCVFrameLowering FrameLowering; @@ -77,6 +78,7 @@ bool hasStdExtD() const { return HasStdExtD; } bool hasStdExtC() const { return HasStdExtC; } bool is64Bit() const { return HasRV64; } + bool enableLinkerRelax() const { return EnableLinkerRelax; } MVT getXLenVT() const { return XLenVT; } unsigned getXLen() const { return XLen; } }; Index: test/CodeGen/RISCV/linker-relaxation.ll =================================================================== --- /dev/null +++ test/CodeGen/RISCV/linker-relaxation.ll @@ -0,0 +1,37 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=riscv32 -filetype=obj -mattr=+relax < %s \ +; RUN: | llvm-readobj -r | FileCheck -check-prefix=RELAX-RELOC %s +; RUN: llc -mtriple=riscv32 -filetype=obj -mattr=-relax < %s \ +; RUN: | llvm-readobj -r | FileCheck -check-prefix=RELOC %s +; RUN: llc -mtriple=riscv32 -verify-machineinstrs -mattr=+relax < %s \ +; RUN: | FileCheck %s -check-prefix=RV32I + +declare i32 @external_function(i32) + +define i32 @test_call_external(i32 %a) nounwind { +; RELAX-RELOC: R_RISCV_BRANCH .LBB0_2 0x0 +; RELAX-RELOC: R_RISCV_CALL external_function 0x0 +; RELAX-RELOC: R_RISCV_RELAX external_function 0x0 +; RELOC: R_RISCV_CALL external_function 0x0 +; RV32I-LABEL: test_call_external: +; RV32I: # %bb.0: +; RV32I-NEXT: addi sp, sp, -16 +; RV32I-NEXT: sw ra, 12(sp) +; RV32I-NEXT: addi a1, zero, 3 +; RV32I-NEXT: blt a0, a1, .LBB0_2 +; RV32I-NEXT: # %bb.1: # %if.else +; RV32I-NEXT: .Ltmp0: +; RV32I-NEXT: auipc ra, %pcrel_hi(external_function) +; RV32I-NEXT: jalr ra, ra, %pcrel_lo(.Ltmp0) +; RV32I-NEXT: .LBB0_2: # %if.then +; RV32I-NEXT: lw ra, 12(sp) +; RV32I-NEXT: addi sp, sp, 16 +; RV32I-NEXT: ret + %1 = icmp slt i32 %a, 3 + br i1 %1, label %if.then, label %if.else +if.else: + %2 = call i32 @external_function(i32 %a) + ret i32 %2 +if.then: + ret i32 %a +}