Skip to content
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

Add support for pc-relative addressing on 64-bit RISC-V #16

Merged
merged 4 commits into from
Jul 1, 2019
Merged
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
11 changes: 11 additions & 0 deletions llvm/include/llvm/CodeGen/MachineBasicBlock.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,10 @@ class MachineBasicBlock
/// branch.
bool AddressTaken = false;

/// Indicate that this basic block needs its symbol be emitted regardless of
/// whether the flow just falls-through to it.
bool LabelMustBeEmitted = false;

/// Indicate that this basic block is the entry block of an EH scope, i.e.,
/// the block that used to have a catchpad or cleanuppad instruction in the
/// LLVM IR.
Expand Down Expand Up @@ -159,6 +163,13 @@ class MachineBasicBlock
/// branch.
void setHasAddressTaken() { AddressTaken = true; }

/// Test whether this block must have its label emitted.
bool hasLabelMustBeEmitted() const { return LabelMustBeEmitted; }

/// Set this block to reflect that, regardless how we flow to it, we need
/// its label be emitted.
void setLabelMustBeEmitted() { LabelMustBeEmitted = true; }

/// Return the MachineFunction containing this basic block.
const MachineFunction *getParent() const { return xParent; }
MachineFunction *getParent() { return xParent; }
Expand Down
5 changes: 4 additions & 1 deletion llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2922,13 +2922,16 @@ void AsmPrinter::EmitBasicBlockStart(const MachineBasicBlock &MBB) const {

// Print the main label for the block.
if (MBB.pred_empty() ||
(isBlockOnlyReachableByFallthrough(&MBB) && !MBB.isEHFuncletEntry())) {
(isBlockOnlyReachableByFallthrough(&MBB) && !MBB.isEHFuncletEntry() &&
!MBB.hasLabelMustBeEmitted())) {
if (isVerbose()) {
// NOTE: Want this comment at start of line, don't emit with AddComment.
OutStreamer->emitRawComment(" %bb." + Twine(MBB.getNumber()) + ":",
false);
}
} else {
if (isVerbose() && MBB.hasLabelMustBeEmitted())
OutStreamer->AddComment("Label of block must be emitted");
OutStreamer->EmitLabel(MBB.getSymbol());
}
}
Expand Down
98 changes: 77 additions & 21 deletions llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCInstBuilder.h"
#include "llvm/MC/MCObjectFileInfo.h"
#include "llvm/MC/MCParser/MCAsmLexer.h"
#include "llvm/MC/MCParser/MCParsedAsmOperand.h"
#include "llvm/MC/MCParser/MCTargetAsmParser.h"
Expand Down Expand Up @@ -79,9 +80,18 @@ class RISCVAsmParser : public MCTargetAsmParser {
// synthesize the desired immedate value into the destination register.
void emitLoadImm(unsigned DestReg, int64_t Value, MCStreamer &Out);

// Helper to emit a combination of AUIPC and SecondOpcode. Used to implement
// helpers such as emitLoadLocalAddress and emitLoadAddress.
void emitAuipcInstPair(MCOperand DestReg, MCOperand TmpReg,
const MCExpr *Symbol, RISCVMCExpr::VariantKind VKHi,
unsigned SecondOpcode, SMLoc IDLoc, MCStreamer &Out);

// Helper to emit pseudo instruction "lla" used in PC-rel addressing.
void emitLoadLocalAddress(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out);

// Helper to emit pseudo instruction "la" used in GOT/PC-rel addressing.
void emitLoadAddress(MCInst &Inst, SMLoc IDLoc, MCStreamer &Out);

/// Helper for processing MC instructions that have been successfully matched
/// by MatchAndEmitInstruction. Modifications to the emitted instructions,
/// like the expansion of pseudo instructions (e.g., "li"), can be performed
Expand Down Expand Up @@ -505,10 +515,12 @@ struct RISCVOperand : public MCParsedAsmOperand {
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);
}
}

Expand Down Expand Up @@ -861,8 +873,8 @@ bool RISCVAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
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 a %pcrel_hi/%got_pcrel_hi modifier "
"or an integer in the range");
case Match_InvalidSImm21Lsb0JAL:
return generateImmOutOfRangeError(
Operands, ErrorInfo, -(1 << 20), (1 << 20) - 2,
Expand Down Expand Up @@ -1408,42 +1420,82 @@ void RISCVAsmParser::emitLoadImm(unsigned DestReg, int64_t Value,
}
}

void RISCVAsmParser::emitLoadLocalAddress(MCInst &Inst, SMLoc IDLoc,
MCStreamer &Out) {
// The local load address pseudo-instruction "lla" is used in PC-relative
// addressing of symbols:
// lla rdest, symbol
// expands to
// TmpLabel: AUIPC rdest, %pcrel_hi(symbol)
// ADDI rdest, %pcrel_lo(TmpLabel)
void RISCVAsmParser::emitAuipcInstPair(MCOperand DestReg, MCOperand TmpReg,
const MCExpr *Symbol,
RISCVMCExpr::VariantKind VKHi,
unsigned SecondOpcode, SMLoc IDLoc,
MCStreamer &Out) {
// A pair of instructions for PC-relative addressing; expands to
// TmpLabel: AUIPC TmpReg, VKHi(symbol)
// OP DestReg, TmpReg, %pcrel_lo(TmpLabel)
MCContext &Ctx = getContext();

MCSymbol *TmpLabel = Ctx.createTempSymbol(
"pcrel_hi", /* AlwaysAddSuffix */ true, /* CanBeUnnamed */ false);
Out.EmitLabel(TmpLabel);

MCOperand DestReg = Inst.getOperand(0);
const RISCVMCExpr *Symbol = RISCVMCExpr::create(
Inst.getOperand(1).getExpr(), RISCVMCExpr::VK_RISCV_PCREL_HI, Ctx);

const RISCVMCExpr *SymbolHi = RISCVMCExpr::create(Symbol, VKHi, Ctx);
emitToStreamer(
Out, MCInstBuilder(RISCV::AUIPC).addOperand(DestReg).addExpr(Symbol));
Out, MCInstBuilder(RISCV::AUIPC).addOperand(TmpReg).addExpr(SymbolHi));

const MCExpr *RefToLinkTmpLabel =
RISCVMCExpr::create(MCSymbolRefExpr::create(TmpLabel, Ctx),
RISCVMCExpr::VK_RISCV_PCREL_LO, Ctx);

emitToStreamer(Out, MCInstBuilder(RISCV::ADDI)
.addOperand(DestReg)
emitToStreamer(Out, MCInstBuilder(SecondOpcode)
.addOperand(DestReg)
.addOperand(TmpReg)
.addExpr(RefToLinkTmpLabel));
}

void RISCVAsmParser::emitLoadLocalAddress(MCInst &Inst, SMLoc IDLoc,
MCStreamer &Out) {
// The load local address pseudo-instruction "lla" is used in PC-relative
// addressing of local symbols:
// lla rdest, symbol
// expands to
// TmpLabel: AUIPC rdest, %pcrel_hi(symbol)
// ADDI rdest, rdest, %pcrel_lo(TmpLabel)
MCOperand DestReg = Inst.getOperand(0);
const MCExpr *Symbol = Inst.getOperand(1).getExpr();
emitAuipcInstPair(DestReg, DestReg, Symbol, RISCVMCExpr::VK_RISCV_PCREL_HI,
RISCV::ADDI, IDLoc, Out);
}

void RISCVAsmParser::emitLoadAddress(MCInst &Inst, SMLoc IDLoc,
MCStreamer &Out) {
// The load address pseudo-instruction "la" is used in PC-relative and
// GOT-indirect addressing of global symbols:
// la rdest, symbol
// expands to either (for non-PIC)
// TmpLabel: AUIPC rdest, %pcrel_hi(symbol)
// ADDI rdest, rdest, %pcrel_lo(TmpLabel)
// or (for PIC)
// TmpLabel: AUIPC rdest, %got_pcrel_hi(symbol)
// Lx rdest, %pcrel_lo(TmpLabel)(rdest)
MCOperand DestReg = Inst.getOperand(0);
const MCExpr *Symbol = Inst.getOperand(1).getExpr();
unsigned SecondOpcode;
RISCVMCExpr::VariantKind VKHi;
// FIXME: Should check .option (no)pic when implemented
if (getContext().getObjectFileInfo()->isPositionIndependent()) {
SecondOpcode = isRV64() ? RISCV::LD : RISCV::LW;
VKHi = RISCVMCExpr::VK_RISCV_GOT_HI;
} else {
SecondOpcode = RISCV::ADDI;
VKHi = RISCVMCExpr::VK_RISCV_PCREL_HI;
}
emitAuipcInstPair(DestReg, DestReg, Symbol, VKHi, SecondOpcode, IDLoc, Out);
}

bool RISCVAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
MCStreamer &Out) {
Inst.setLoc(IDLoc);

if (Inst.getOpcode() == RISCV::PseudoLI) {
switch (Inst.getOpcode()) {
default:
break;
case RISCV::PseudoLI: {
unsigned Reg = Inst.getOperand(0).getReg();
const MCOperand &Op1 = Inst.getOperand(1);
if (Op1.isExpr()) {
Expand All @@ -1463,9 +1515,13 @@ bool RISCVAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
Imm = SignExtend64<32>(Imm);
emitLoadImm(Reg, Imm, Out);
return false;
} else if (Inst.getOpcode() == RISCV::PseudoLLA) {
}
case RISCV::PseudoLLA:
emitLoadLocalAddress(Inst, IDLoc, Out);
return false;
case RISCV::PseudoLA:
emitLoadAddress(Inst, IDLoc, Out);
return false;
}

emitToStreamer(Out, Inst);
Expand Down
7 changes: 7 additions & 0 deletions llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ bool RISCVAsmBackend::shouldForceRelocation(const MCAssembler &Asm,
switch ((unsigned)Fixup.getKind()) {
default:
break;
case RISCV::fixup_riscv_got_hi20:
return true;
case RISCV::fixup_riscv_pcrel_lo12_i:
case RISCV::fixup_riscv_pcrel_lo12_s:
// For pcrel_lo12, force a relocation if the target of the corresponding
Expand All @@ -48,6 +50,9 @@ bool RISCVAsmBackend::shouldForceRelocation(const MCAssembler &Asm,
default:
llvm_unreachable("Unexpected fixup kind for pcrel_lo12");
break;
case RISCV::fixup_riscv_got_hi20:
ShouldForce = true;
break;
case RISCV::fixup_riscv_pcrel_hi20:
ShouldForce = T->getValue()->findAssociatedFragment() !=
Fixup.getValue()->findAssociatedFragment();
Expand Down Expand Up @@ -173,6 +178,8 @@ static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
switch (Kind) {
default:
llvm_unreachable("Unknown fixup kind!");
case RISCV::fixup_riscv_got_hi20:
llvm_unreachable("Relocation should be unconditionally forced\n");
case FK_Data_1:
case FK_Data_2:
case FK_Data_4:
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ class RISCVAsmBackend : public MCAsmBackend {
{ "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 },
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ unsigned RISCVELFObjectWriter::getRelocType(MCContext &Ctx,
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:
Expand Down
3 changes: 3 additions & 0 deletions llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ enum Fixups {
// 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_pcrel_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,
Expand Down
3 changes: 3 additions & 0 deletions llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,9 @@ unsigned RISCVMCCodeEmitter::getImmOpValue(const MCInst &MI, unsigned OpNo,
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;
Expand Down
7 changes: 6 additions & 1 deletion llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ const MCFixup *RISCVMCExpr::getPCRelHiFixup() const {
switch ((unsigned)F.getKind()) {
default:
continue;
case RISCV::fixup_riscv_got_hi20:
case RISCV::fixup_riscv_pcrel_hi20:
return &F;
}
Expand Down Expand Up @@ -137,6 +138,7 @@ bool RISCVMCExpr::evaluateAsRelocatableImpl(MCValue &Res,
case VK_RISCV_HI:
case VK_RISCV_PCREL_LO:
case VK_RISCV_PCREL_HI:
case VK_RISCV_GOT_HI:
return false;
}
}
Expand All @@ -154,6 +156,7 @@ RISCVMCExpr::VariantKind RISCVMCExpr::getVariantKindForName(StringRef name) {
.Case("hi", VK_RISCV_HI)
.Case("pcrel_lo", VK_RISCV_PCREL_LO)
.Case("pcrel_hi", VK_RISCV_PCREL_HI)
.Case("got_pcrel_hi", VK_RISCV_GOT_HI)
.Default(VK_RISCV_Invalid);
}

Expand All @@ -169,14 +172,16 @@ StringRef RISCVMCExpr::getVariantKindName(VariantKind Kind) {
return "pcrel_lo";
case VK_RISCV_PCREL_HI:
return "pcrel_hi";
case VK_RISCV_GOT_HI:
return "got_pcrel_hi";
}
}

bool RISCVMCExpr::evaluateAsConstant(int64_t &Res) const {
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))
Expand Down
7 changes: 4 additions & 3 deletions llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ class RISCVMCExpr : public MCTargetExpr {
VK_RISCV_HI,
VK_RISCV_PCREL_LO,
VK_RISCV_PCREL_HI,
VK_RISCV_GOT_HI,
VK_RISCV_CALL,
VK_RISCV_Invalid
};
Expand All @@ -53,11 +54,11 @@ class RISCVMCExpr : public MCTargetExpr {

const MCExpr *getSubExpr() const { return Expr; }

/// Get the MCExpr of the VK_RISCV_PCREL_HI Fixup that the
/// VK_RISCV_PCREL_LO points to.
/// Get the corresponding PC-relative HI fixup that a VK_RISCV_PCREL_LO
/// points to.
///
/// \returns nullptr if this isn't a VK_RISCV_PCREL_LO pointing to a
/// VK_RISCV_PCREL_HI.
/// known PC-relative HI fixup.
const MCFixup *getPCRelHiFixup() const;

void printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const override;
Expand Down
Loading