Skip to content

Commit

Permalink
[EraVM][ELF] Fix emission of jump tables
Browse files Browse the repository at this point in the history
The generic implementation tries to emit jump table entries as 256-bit
pointers, which triggers an assertion in MCFixupKind::getKindForSize.

This commit adds custom implementation of emitJumpTableInfo for EraVM,
based on emitJumpTableInfo and emitJumpTableEntry functions from the
AsmPrinter class that emits 16-bit labels and takes scaling by 8 into
account.
  • Loading branch information
atrosinenko authored and asl committed May 13, 2024
1 parent 49c62fe commit dbfdfa8
Show file tree
Hide file tree
Showing 4 changed files with 136 additions and 0 deletions.
44 changes: 44 additions & 0 deletions llvm/lib/Target/EraVM/EraVMAsmPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "llvm/CodeGen/AsmPrinter.h"
#include "llvm/CodeGen/MachineConstantPool.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineJumpTableInfo.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DerivedTypes.h"
Expand Down Expand Up @@ -81,6 +82,7 @@ class EraVMAsmPrinter : public AsmPrinter {
return MCInstLowering.lowerOperand(MO, MCOp);
}

void emitJumpTableInfo() override;
void emitConstantPool() override;
void emitEndOfAsmFile(Module &) override;
};
Expand Down Expand Up @@ -174,6 +176,48 @@ void EraVMAsmPrinter::emitInstruction(const MachineInstr *MI) {
EmitToStreamer(*OutStreamer, TmpInst);
}

void EraVMAsmPrinter::emitJumpTableInfo() {
// The default implementation would try to emit 256-bit fixup, so provide
// custom implementation based on emitJumpTableInfo and emitJumpTableEntry
// from AsmPrinter (the latter is not virtual) that emits 16-bit relocation
// and takes scaling into account.

auto *TS =
static_cast<EraVMTargetStreamer *>(OutStreamer->getTargetStreamer());
const DataLayout &DL = MF->getDataLayout();
const MachineJumpTableInfo *MJTI = MF->getJumpTableInfo();
if (!MJTI)
return;
assert(MJTI->getEntryKind() == MachineJumpTableInfo::EK_BlockAddress);
const std::vector<MachineJumpTableEntry> &JT = MJTI->getJumpTables();
if (JT.empty())
return;

// Switch section.
const Function &F = MF->getFunction();
MCSection *Section = getObjFileLowering().getSectionForJumpTable(F, TM);
OutStreamer->switchSection(Section);

emitAlignment(Align(MJTI->getEntryAlignment(DL)));

for (unsigned JTI = 0, e = JT.size(); JTI != e; ++JTI) {
const std::vector<MachineBasicBlock *> &JTBBs = JT[JTI].MBBs;

// If this jump table was deleted, ignore it.
if (JTBBs.empty())
continue;

OutStreamer->emitLabel(GetJTISymbol(JTI));

for (const MachineBasicBlock *MBB : JTBBs) {
assert(MBB && MBB->getNumber() >= 0 && "Invalid basic block");
const MCExpr *Value =
MCSymbolRefExpr::create(MBB->getSymbol(), OutContext);
TS->emitJumpTarget(Value);
}
}
}

bool EraVMAsmPrinter::runOnMachineFunction(MachineFunction &MF) {
SetupMachineFunction(MF);
emitFunctionBody();
Expand Down
28 changes: 28 additions & 0 deletions llvm/lib/Target/EraVM/MCTargetDesc/EraVMELFStreamer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
//
//===----------------------------------------------------------------------===//

#include "EraVMFixupKinds.h"
#include "EraVMMCTargetDesc.h"
#include "EraVMTargetStreamer.h"
#include "llvm/BinaryFormat/ELF.h"
Expand All @@ -18,6 +19,7 @@
#include "llvm/MC/MCSectionELF.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/Support/Casting.h"

using namespace llvm;

Expand All @@ -28,6 +30,7 @@ class EraVMTargetELFStreamer : public EraVMTargetStreamer {
MCELFStreamer &getStreamer();
EraVMTargetELFStreamer(MCStreamer &S, const MCSubtargetInfo &STI);
void emitCell(const APInt &Value) override;
void emitJumpTarget(const MCExpr *Expr) override;
};

// This part is for ELF object output.
Expand All @@ -40,6 +43,7 @@ class EraVMTargetAsmStreamer : public EraVMTargetStreamer {
EraVMTargetAsmStreamer(MCStreamer &S, formatted_raw_ostream &OS,
MCInstPrinter &InstPrinter, bool VerboseAsm);
void emitCell(const APInt &Value) override;
void emitJumpTarget(const MCExpr *Expr) override;
};

void EraVMTargetELFStreamer::emitCell(const APInt &Value) {
Expand All @@ -49,6 +53,26 @@ void EraVMTargetELFStreamer::emitCell(const APInt &Value) {
Streamer.emitIntValue(Value.sext(EraVM::CellBitWidth));
}

void EraVMTargetELFStreamer::emitJumpTarget(const MCExpr *Expr) {
// The code is similar to MCObjectStreamer::emitValueImpl, but takes the
// specifics of code labels into account: the instruction index is actually
// only 16 bits in size and is counted in 8-byte units.

constexpr auto FK = static_cast<MCFixupKind>(EraVM::fixup_16_scale_8);
auto &S = static_cast<MCObjectStreamer &>(Streamer);

S.visitUsedExpr(*Expr);

// Emit the placeholder.
emitCell(APInt::getZero(EraVM::CellBitWidth));

// Emit the fixup.
auto *DF = cast<MCDataFragment>(S.getCurrentFragment());
// Offset of the 16 least significant bits of 256-bit value.
unsigned Offset = DF->getContents().size() - 2;
DF->getFixups().push_back(MCFixup::create(Offset, Expr, FK));
}

void EraVMTargetAsmStreamer::emitCell(const APInt &Value) {
assert(Value.getBitWidth() <= EraVM::CellBitWidth);

Expand All @@ -59,6 +83,10 @@ void EraVMTargetAsmStreamer::emitCell(const APInt &Value) {
Streamer.emitRawText(OS.str());
}

void EraVMTargetAsmStreamer::emitJumpTarget(const MCExpr *Expr) {
Streamer.emitValue(Expr, EraVM::CellBitWidth / 8);
}

EraVMTargetAsmStreamer::EraVMTargetAsmStreamer(MCStreamer &S,
formatted_raw_ostream &OS,
MCInstPrinter &InstPrinter,
Expand Down
3 changes: 3 additions & 0 deletions llvm/lib/Target/EraVM/MCTargetDesc/EraVMTargetStreamer.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ class EraVMTargetStreamer : public MCTargetStreamer {

/// Emit .cell N (naturally-aligned 256-bit value).
virtual void emitCell(const APInt &Value) {}

/// Emit `.cell @tgt` where `@tgt` is an instruction address.
virtual void emitJumpTarget(const MCExpr *Expr) {}
};
} // namespace llvm

Expand Down
61 changes: 61 additions & 0 deletions llvm/test/MC/EraVM/encoding/jump-table.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
; RUN: llc < %s | FileCheck %s
; RUN: llc -filetype=obj -o %t.o < %s
; RUN: llvm-readelf --sections --relocs --syms %t.o | FileCheck --check-prefix=ELF %s

target datalayout = "E-p:256:256-i8:256:256:256-i256:256:256-S32-a:256:256"
target triple = "eravm"

define i256 @foo(i256 %arg) {
entry:
switch i256 %arg, label %default [
i256 1, label %l1
i256 2, label %l2
i256 3, label %l3
i256 4, label %l4
]
l1:
ret i256 123
l2:
ret i256 234
l3:
ret i256 345
l4:
ret i256 456
default:
ret i256 42
}

; CHECK: foo:
; Make sure raw values from the jump table are used as-is, so R_ERAVM_16_SCALE_8
; is the right relocation to use for jump table entry emission.
; CHECK: jump.le @JTI0_0[r1]

; CHECK: .rodata
; CHECK-NEXT: .p2align 5, 0x0
; CHECK-NEXT:JTI0_0:
; CHECK-NEXT: .cell @.BB0_1
; CHECK-NEXT: .cell @.BB0_2
; CHECK-NEXT: .cell @.BB0_3
; CHECK-NEXT: .cell @.BB0_4

; Capture the index of .rodata section
; ELF: Section Headers:
; ELF: [ [[RODATA:[0-9]+]]] .rodata

; JTI0_0 is mentioned as a const operand of *some* instruction
; ELF: Relocation section '.rela.text' at offset {{0x[0-9a-f]+}} contains {{[0-9]+}} entries:
; ELF-NEXT: Offset Info Type Sym. Value Symbol's Name + Addend
; ELF: {{[0-9a-f]+}} 00000401 R_ERAVM_16_SCALE_32 00000000 .rodata + 0

; JTI0_0 is filled by R_ERAVM_16_SCALE_8 relocations
; ELF: Relocation section '.rela.rodata' at offset {{0x[0-9a-f]+}} contains 4 entries:
; ELF-NEXT: Offset Info Type Sym. Value Symbol's Name + Addend
; ELF-NEXT: 0000001e 00000202 R_ERAVM_16_SCALE_8 00000000 .text + 20
; ELF-NEXT: 0000003e 00000202 R_ERAVM_16_SCALE_8 00000000 .text + 40
; ELF-NEXT: 0000005e 00000202 R_ERAVM_16_SCALE_8 00000000 .text + 50
; ELF-NEXT: 0000007e 00000202 R_ERAVM_16_SCALE_8 00000000 .text + 60

; JTI0_0 starts at zero offset inside .rodata, as expected by the above checks
; ELF: Symbol table '.symtab' contains {{[0-9]+}} entries:
; ELF: Num: Value Size Type Bind Vis Ndx Name
; ELF: {{[0-9]+}}: 00000000 0 NOTYPE LOCAL DEFAULT [[RODATA]] JTI0_0

0 comments on commit dbfdfa8

Please sign in to comment.