Skip to content

[RISCV] Vendor Relocations for Xqci extension #135400

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions llvm/include/llvm/MC/MCAsmBackend.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,8 @@ class MCAsmBackend {

virtual bool evaluateTargetFixup(const MCAssembler &Asm, const MCFixup &Fixup,
const MCFragment *DF, const MCValue &Target,
const MCSubtargetInfo *STI,
uint64_t &Value) {
const MCSubtargetInfo *STI, uint64_t &Value,
bool RecordReloc) {
llvm_unreachable("Need to implement hook if target has custom fixups");
}

Expand Down
4 changes: 2 additions & 2 deletions llvm/lib/MC/MCAssembler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -158,8 +158,8 @@ bool MCAssembler::evaluateFixup(const MCFixup &Fixup, const MCFragment *DF,
bool IsResolved = false;
unsigned FixupFlags = getBackend().getFixupKindInfo(Fixup.getKind()).Flags;
if (FixupFlags & MCFixupKindInfo::FKF_IsTarget) {
IsResolved =
getBackend().evaluateTargetFixup(*this, Fixup, DF, Target, STI, Value);
IsResolved = getBackend().evaluateTargetFixup(*this, Fixup, DF, Target, STI,
Value, RecordReloc);
} else {
const MCSymbol *Add = Target.getAddSym();
const MCSymbol *Sub = Target.getSubSym();
Expand Down
171 changes: 135 additions & 36 deletions llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//

#include "RISCVAsmBackend.h"
#include "RISCVFixupKinds.h"
#include "RISCVMCExpr.h"
#include "llvm/ADT/APInt.h"
#include "llvm/MC/MCAsmInfo.h"
Expand Down Expand Up @@ -37,7 +38,7 @@ static cl::opt<bool> ULEB128Reloc(
RISCVAsmBackend::RISCVAsmBackend(const MCSubtargetInfo &STI, uint8_t OSABI,
bool Is64Bit, const MCTargetOptions &Options)
: MCAsmBackend(llvm::endianness::little, ELF::R_RISCV_RELAX), STI(STI),
OSABI(OSABI), Is64Bit(Is64Bit), TargetOptions(Options) {
OSABI(OSABI), Is64Bit(Is64Bit), TargetOptions(Options), VendorSymbols() {
RISCVFeatures::validate(STI.getTargetTriple(), STI.getFeatureBits());
}

Expand Down Expand Up @@ -84,10 +85,12 @@ MCFixupKindInfo RISCVAsmBackend::getFixupKindInfo(MCFixupKind Kind) const {
{"fixup_riscv_call", 0, 64, MCFixupKindInfo::FKF_IsPCRel},
{"fixup_riscv_call_plt", 0, 64, MCFixupKindInfo::FKF_IsPCRel},

{"fixup_riscv_qc_e_branch", 0, 48, MCFixupKindInfo::FKF_IsPCRel},
{"fixup_riscv_qc_e_32", 16, 32, 0},
{"fixup_riscv_qc_abs20_u", 12, 20, 0},
{"fixup_riscv_qc_e_jump_plt", 0, 48, MCFixupKindInfo::FKF_IsPCRel},
{"fixup_riscv_qc_e_branch", 0, 48,
MCFixupKindInfo::FKF_IsPCRel | MCFixupKindInfo::FKF_IsTarget},
{"fixup_riscv_qc_e_32", 16, 32, MCFixupKindInfo::FKF_IsTarget},
{"fixup_riscv_qc_abs20_u", 12, 20, MCFixupKindInfo::FKF_IsTarget},
{"fixup_riscv_qc_e_jump_plt", 0, 48,
MCFixupKindInfo::FKF_IsPCRel | MCFixupKindInfo::FKF_IsTarget},
};
static_assert((std::size(Infos)) == RISCV::NumTargetFixupKinds,
"Not all fixup kinds added to Infos array");
Expand Down Expand Up @@ -571,37 +574,10 @@ static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
}
}

bool RISCVAsmBackend::evaluateTargetFixup(
const MCAssembler &Asm, const MCFixup &Fixup, const MCFragment *DF,
const MCValue &Target, const MCSubtargetInfo *STI, uint64_t &Value) {
const MCFixup *AUIPCFixup;
const MCFragment *AUIPCDF;
MCValue AUIPCTarget;
switch (Fixup.getTargetKind()) {
default:
llvm_unreachable("Unexpected fixup kind!");
case RISCV::fixup_riscv_pcrel_hi20:
AUIPCFixup = &Fixup;
AUIPCDF = DF;
AUIPCTarget = Target;
break;
case RISCV::fixup_riscv_pcrel_lo12_i:
case RISCV::fixup_riscv_pcrel_lo12_s: {
AUIPCFixup = cast<RISCVMCExpr>(Fixup.getValue())->getPCRelHiFixup(&AUIPCDF);
if (!AUIPCFixup) {
Asm.getContext().reportError(Fixup.getLoc(),
"could not find corresponding %pcrel_hi");
return true;
}

// MCAssembler::evaluateFixup will emit an error for this case when it sees
// the %pcrel_hi, so don't duplicate it when also seeing the %pcrel_lo.
const MCExpr *AUIPCExpr = AUIPCFixup->getValue();
if (!AUIPCExpr->evaluateAsRelocatable(AUIPCTarget, &Asm))
return true;
break;
}
}
static bool evaluateAUIPCFixup(const MCAssembler &Asm,
const MCFixup *AUIPCFixup,
const MCFragment *AUIPCDF, MCValue AUIPCTarget,
uint64_t &Value) {

if (!AUIPCTarget.getAddSym())
return false;
Expand All @@ -622,6 +598,129 @@ bool RISCVAsmBackend::evaluateTargetFixup(
return AUIPCFixup->getTargetKind() == RISCV::fixup_riscv_pcrel_hi20;
}

StringRef
RISCVAsmBackend::getVendorSymbolNameForRelocation(unsigned FixupKind) const {
switch (FixupKind) {
case RISCV::fixup_riscv_qc_e_branch:
case RISCV::fixup_riscv_qc_abs20_u:
case RISCV::fixup_riscv_qc_e_32:
case RISCV::fixup_riscv_qc_e_jump_plt:
return "QUALCOMM";
}

return "";
}

bool RISCVAsmBackend::evaluateVendorFixup(const MCAssembler &Asm,
const MCFixup &Fixup,
const MCFragment *DF,
const MCValue &Target,
const MCSubtargetInfo *STI,
uint64_t &Value, bool RecordReloc) {
// This is a copy of the target-independent branch of
// MCAssembler::evaluateFixup
bool IsResolved = false;
const MCSymbol *Add = Target.getAddSym();
const MCSymbol *Sub = Target.getSubSym();
Value = Target.getConstant();
if (Add && Add->isDefined())
Value += Asm.getSymbolOffset(*Add);
if (Sub && Sub->isDefined())
Value -= Asm.getSymbolOffset(*Sub);

unsigned FixupFlags = getFixupKindInfo(Fixup.getKind()).Flags;
if (FixupFlags & MCFixupKindInfo::FKF_IsPCRel) {
Value -= Asm.getFragmentOffset(*DF) + Fixup.getOffset();

if (Add && !Sub && !Add->isUndefined() && !Add->isAbsolute()) {
IsResolved = Asm.getWriter().isSymbolRefDifferenceFullyResolvedImpl(
Asm, *Add, *DF, false, true);
}
} else {
IsResolved = Target.isAbsolute();
}
// End copy of MCAssembler::evaluateFixup

// If we failed to resolve, or we need to force relocations (relaxations),
// then record a vendor relocation too.
if ((!IsResolved || shouldForceRelocation(Asm, Fixup, Target, STI)) &&
RecordReloc) {
// Here are the additions to emit a vendor relocation for fixups that need
// them.
MCContext &Ctx = Asm.getContext();

StringRef VendorIdentifier =
getVendorSymbolNameForRelocation(Fixup.getTargetKind());

auto It = VendorSymbols.find(VendorIdentifier);
if (It == VendorSymbols.end()) {
auto *VendorSymbol =
cast<MCSymbolELF>(Ctx.createLocalSymbol(VendorIdentifier));

// Vendor Symbols are Absolute, Local, NOTYPE.
VendorSymbol->setType(ELF::STT_NOTYPE);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The symbol is by default NOTYPE and LOCAL. In the rare scenario that the users changes the type/binding, we should respect that.

So setType/setBinding should be omitted.

VendorSymbol->setBinding(ELF::STB_LOCAL);
VendorSymbol->setVariableValue(MCConstantExpr::create(0, Ctx));
const_cast<MCAssembler &>(Asm).registerSymbol(*VendorSymbol);

It = VendorSymbols.try_emplace(VendorIdentifier, VendorSymbol).first;
}

MCSymbolELF *VendorSymbol = It->getValue();
const MCExpr *VendorExpr = MCSymbolRefExpr::create(VendorSymbol, Ctx);
MCFixup VendorFixup =
MCFixup::create(Fixup.getOffset(), VendorExpr,
FirstLiteralRelocationKind + ELF::R_RISCV_VENDOR);
// Explicitly create MCValue so that the absolute symbol is not evaluated to
// a constant.
MCValue VendorTarget = MCValue::get(VendorSymbol);
uint64_t VendorValue;
Asm.getWriter().recordRelocation(const_cast<MCAssembler &>(Asm), DF,
VendorFixup, VendorTarget, VendorValue);
}

return IsResolved;
}

bool RISCVAsmBackend::evaluateTargetFixup(const MCAssembler &Asm,
const MCFixup &Fixup,
const MCFragment *DF,
const MCValue &Target,
const MCSubtargetInfo *STI,
uint64_t &Value, bool RecordReloc) {
switch (Fixup.getTargetKind()) {
case RISCV::fixup_riscv_pcrel_hi20:
return evaluateAUIPCFixup(Asm, &Fixup, DF, Target, Value);
case RISCV::fixup_riscv_pcrel_lo12_i:
case RISCV::fixup_riscv_pcrel_lo12_s: {
const MCFragment *AUIPCDF;
const MCFixup *AUIPCFixup =
cast<RISCVMCExpr>(Fixup.getValue())->getPCRelHiFixup(&AUIPCDF);
if (!AUIPCFixup) {
Asm.getContext().reportError(Fixup.getLoc(),
"could not find corresponding %pcrel_hi");
return true;
}

// MCAssembler::evaluateFixup will emit an error for this case when it sees
// the %pcrel_hi, so don't duplicate it when also seeing the %pcrel_lo.
const MCExpr *AUIPCExpr = AUIPCFixup->getValue();
MCValue AUIPCTarget;
if (!AUIPCExpr->evaluateAsRelocatable(AUIPCTarget, &Asm))
return true;

return evaluateAUIPCFixup(Asm, AUIPCFixup, AUIPCDF, AUIPCTarget, Value);
}
case RISCV::fixup_riscv_qc_e_branch:
case RISCV::fixup_riscv_qc_abs20_u:
case RISCV::fixup_riscv_qc_e_32:
case RISCV::fixup_riscv_qc_e_jump_plt:
return evaluateVendorFixup(Asm, Fixup, DF, Target, STI, Value, RecordReloc);
}

llvm_unreachable("Unexpected target fixup kind!");
}

bool RISCVAsmBackend::handleAddSubRelocations(const MCAssembler &Asm,
const MCFragment &F,
const MCFixup &Fixup,
Expand Down
15 changes: 13 additions & 2 deletions llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "MCTargetDesc/RISCVBaseInfo.h"
#include "MCTargetDesc/RISCVFixupKinds.h"
#include "MCTargetDesc/RISCVMCTargetDesc.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/MC/MCAsmBackend.h"
#include "llvm/MC/MCFixupKindInfo.h"
#include "llvm/MC/MCSubtargetInfo.h"
Expand All @@ -20,6 +21,7 @@ namespace llvm {
class MCAssembler;
class MCObjectTargetWriter;
class raw_ostream;
class MCSymbolELF;

class RISCVAsmBackend : public MCAsmBackend {
const MCSubtargetInfo &STI;
Expand All @@ -28,6 +30,8 @@ class RISCVAsmBackend : public MCAsmBackend {
bool ForceRelocs = false;
const MCTargetOptions &TargetOptions;

StringMap<MCSymbolELF *> VendorSymbols;

public:
RISCVAsmBackend(const MCSubtargetInfo &STI, uint8_t OSABI, bool Is64Bit,
const MCTargetOptions &Options);
Expand All @@ -45,8 +49,15 @@ class RISCVAsmBackend : public MCAsmBackend {

bool evaluateTargetFixup(const MCAssembler &Asm, const MCFixup &Fixup,
const MCFragment *DF, const MCValue &Target,
const MCSubtargetInfo *STI,
uint64_t &Value) override;
const MCSubtargetInfo *STI, uint64_t &Value,
bool RecordReloc) override;

bool evaluateVendorFixup(const MCAssembler &Asm, const MCFixup &Fixup,
const MCFragment *DF, const MCValue &Target,
const MCSubtargetInfo *STI, uint64_t &Value,
bool RecordReloc);

StringRef getVendorSymbolNameForRelocation(unsigned TargetFixupKind) const;

bool handleAddSubRelocations(const MCAssembler &Asm, const MCFragment &F,
const MCFixup &Fixup, const MCValue &Target,
Expand Down
38 changes: 38 additions & 0 deletions llvm/test/MC/RISCV/xqcibi-relocations-relax.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# RUN: llvm-mc -triple riscv32 -mattr=+experimental-xqcibi %s \
# RUN: | FileCheck -check-prefix=ASM %s
# RUN: llvm-mc -triple riscv32 -mattr=+experimental-xqcibi %s \
# RUN: -filetype=obj -o - \
# RUN: | llvm-objdump -dr --mattr=+experimental-xqcibi - \
# RUN: | FileCheck -check-prefix=OBJ %s

## This test checks that we emit the right relocations for Xqcibi
## relative branches, when relaxations are enabled. These require a relocation.
## The QC.E.B<op>I instructions also require a vendor relocation.

# These are required to turn off autocompression, but to re-enable
# linker relaxation.
.option exact
.option relax

# ASM-LABEL: this_section:
# OBJ-LABEL: <this_section>:
this_section:

# ASM: qc.bnei t2, 11, same_section
# OBJ: qc.bnei t2, 0xb, 0x0 <this_section>
# OBJ-NEXT: R_RISCV_BRANCH same_section{{$}}
# OBJ-NOT: R_RISCV
qc.bnei t2, 11, same_section

# ASM: qc.e.bgeui s1, 21, same_section
# OBJ: qc.e.bgeui s1, 0x15, 0x4 <this_section+0x4>
# OBJ-NEXT: R_RISCV_VENDOR QUALCOMM{{$}}
# OBJ-NEXT: R_RISCV_CUSTOM193 same_section{{$}}
# OBJ-NOT: R_RISCV
qc.e.bgeui s1, 21, same_section

# ASM-LABEL: same_section:
# OBJ-LABEL: <same_section>:
same_section:
nop

Loading