Skip to content

Commit

Permalink
Merge pull request #16 from Disasm/rv64-pic
Browse files Browse the repository at this point in the history
Add support for pc-relative addressing on 64-bit RISC-V
  • Loading branch information
alexcrichton authored Jul 1, 2019
2 parents 1bbe0b3 + 637e52c commit 8538d56
Show file tree
Hide file tree
Showing 23 changed files with 561 additions and 76 deletions.
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

0 comments on commit 8538d56

Please sign in to comment.