Skip to content

Commit

Permalink
[EVM] Move generation of JUMPDEST to the AsmPrinter phase
Browse files Browse the repository at this point in the history
Signed-off-by: Vladimir Radosavljevic <[email protected]>
  • Loading branch information
vladimirradosavljevic committed Dec 9, 2024
1 parent 18eab55 commit 916ff45
Show file tree
Hide file tree
Showing 6 changed files with 74 additions and 47 deletions.
54 changes: 53 additions & 1 deletion llvm/lib/Target/EVM/EVMAsmPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@

using namespace llvm;

extern cl::opt<bool> EVMKeepRegisters;

#define DEBUG_TYPE "asm-printer"

namespace {
Expand All @@ -48,10 +50,13 @@ class EVMAsmPrinter : public AsmPrinter {

void emitInstruction(const MachineInstr *MI) override;

void emitBasicBlockStart(const MachineBasicBlock &MBB) override;

void emitFunctionEntryLabel() override;

private:
void emitLinkerSymbol(const MachineInstr *MI);
void emitJumpDest();
};
} // end of anonymous namespace

Expand All @@ -77,14 +82,55 @@ void EVMAsmPrinter::emitFunctionEntryLabel() {
}
}

void EVMAsmPrinter::emitBasicBlockStart(const MachineBasicBlock &MBB) {
AsmPrinter::emitBasicBlockStart(MBB);

// Emit JUMPDEST instruction at the beginning of the basic block, if
// this is not a block that is only reachable by fallthrough.
if (!EVMKeepRegisters && !AsmPrinter::isBlockOnlyReachableByFallthrough(&MBB))
emitJumpDest();
}

void EVMAsmPrinter::emitInstruction(const MachineInstr *MI) {
EVMMCInstLower MCInstLowering(OutContext, *this, VRegMapping,
MF->getRegInfo());

switch (MI->getOpcode()) {
default:
break;
case EVM::PseudoCALL:
case EVM::PseudoCALL: {
// Generate push instruction with the address of a function.
MCInst Push;
Push.setOpcode(EVM::PUSH4_S);
assert(MI->getOperand(0).isGlobal() &&
"The first operand of PseudoCALL should be a GlobalValue.");

// TODO: #745: Refactor EVMMCInstLower::Lower so we could use lowerOperand
// instead of creating a MCOperand directly.
MCOperand MCOp = MCOperand::createExpr(MCSymbolRefExpr::create(
getSymbol(MI->getOperand(0).getGlobal()), OutContext));
Push.addOperand(MCOp);
EmitToStreamer(*OutStreamer, Push);

// Jump to a function.
MCInst Jump;
Jump.setOpcode(EVM::JUMP_S);
EmitToStreamer(*OutStreamer, Jump);

// In case a function has a return label, emit it, and also
// emit a JUMPDEST instruction.
if (MI->getNumExplicitOperands() > 1) {
// We need to emit ret label after JUMP instruction, so we couldn't
// use setPostInstrSymbol since label would be created after
// JUMPDEST instruction. To overcome this, we added MCSymbol operand
// and we are emitting label manually here.
assert(MI->getOperand(1).isMCSymbol() &&
"The second operand of PseudoCALL should be a MCSymbol.");
OutStreamer->emitLabel(MI->getOperand(1).getMCSymbol());
emitJumpDest();
}
return;
}
case EVM::PseudoRET: {
// TODO: #746: Use PseudoInstExpansion and do this expansion in tblgen.
MCInst Jump;
Expand Down Expand Up @@ -141,6 +187,12 @@ void EVMAsmPrinter::emitLinkerSymbol(const MachineInstr *MI) {
EmitToStreamer(*OutStreamer, MCI);
}

void EVMAsmPrinter::emitJumpDest() {
MCInst JumpDest;
JumpDest.setOpcode(EVM::JUMPDEST_S);
EmitToStreamer(*OutStreamer, JumpDest);
}

extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeEVMAsmPrinter() {
const RegisterAsmPrinter<EVMAsmPrinter> X(getTheEVMTarget());
}
30 changes: 13 additions & 17 deletions llvm/lib/Target/EVM/EVMAssembly.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,13 +120,6 @@ void EVMAssembly::appendConstant(uint64_t Val) {
appendConstant(APInt(256, Val));
}

void EVMAssembly::appendLabel() {
CurMIIt = BuildMI(*CurMBB, CurMIIt, DebugLoc(), TII->get(EVM::JUMPDEST));
AssemblyInstrs.insert(&*CurMIIt);
LLVM_DEBUG(dumpInst(&*CurMIIt));
CurMIIt = std::next(CurMIIt);
}

void EVMAssembly::appendLabelReference(MCSymbol *Label) {
CurMIIt = BuildMI(*CurMBB, CurMIIt, DebugLoc(), TII->get(EVM::PUSH_LABEL))
.addSym(Label);
Expand All @@ -145,22 +138,25 @@ void EVMAssembly::appendFuncCall(const MachineInstr *MI,
MCSymbol *RetSym) {
// Push the function label
assert(CurMBB == MI->getParent());

// Create pseudo jump to the callee, that will be expanded into PUSH and JUMP
// instructions in the AsmPrinter.
CurMIIt =
BuildMI(*CurMBB, CurMIIt, MI->getDebugLoc(), TII->get(EVM::PUSH_LABEL))
BuildMI(*CurMBB, CurMIIt, MI->getDebugLoc(), TII->get(EVM::PseudoCALL))
.addGlobalAddress(Func);

// If this function returns, we need to create a label after JUMP instruction
// that is followed by JUMPDEST and this is taken care in the AsmPrinter.
// In case we use setPostInstrSymbol here, the label will be created
// after the JUMPDEST instruction, which is not what we want.
if (RetSym)
MachineInstrBuilder(*CurMIIt->getParent()->getParent(), CurMIIt)
.addSym(RetSym);

// PUSH_LABEL technically increases the stack height on 1, but we don't
// increase it explicitly here, as the label will be consumed by the following
// JUMP.
AssemblyInstrs.insert(&*CurMIIt);
StackHeight += StackAdj;
LLVM_DEBUG(dumpInst(&*CurMIIt));

CurMIIt = std::next(CurMIIt);
// Create jump to the callee.
CurMIIt =
BuildMI(*CurMBB, CurMIIt, MI->getDebugLoc(), TII->get(EVM::PseudoCALL));
if (RetSym)
CurMIIt->setPostInstrSymbol(*MF, RetSym);
AssemblyInstrs.insert(&*CurMIIt);
LLVM_DEBUG(dumpInst(&*CurMIIt));
CurMIIt = std::next(CurMIIt);
Expand Down
2 changes: 0 additions & 2 deletions llvm/lib/Target/EVM/EVMAssembly.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,6 @@ class EVMAssembly {

void appendConstant(uint64_t Val);

void appendLabel();

void appendFuncCall(const MachineInstr *MI, const llvm::GlobalValue *Func,
int stackAdj, MCSymbol *RetSym = nullptr);

Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Target/EVM/EVMInstrInfo.td
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ def FCALL
: NRI<(outs), (ins jmptarget:$callee, variable_ops), [],
"FCALL\t$callee">;
let isPseudo = 1 in
def PseudoCALL : EVMPseudo<(outs), (ins), []>;
def PseudoCALL : EVMPseudo<(outs), (ins jmptarget:$callee, variable_ops), []>;
} // Uses = [SP], isCall = 1


Expand Down
7 changes: 0 additions & 7 deletions llvm/lib/Target/EVM/EVMOptimizedCodeTransform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,6 @@ void EVMOptimizedCodeTransform::operator()(CFG::FunctionCall const &Call) {
(Call.CanContinue ? 1 : 0),
Call.CanContinue ? CallToReturnMCSymbol.at(Call.Call)
: nullptr);
if (Call.CanContinue)
Assembly.appendLabel();

// Update stack, remove arguments and return label from CurrentStack.
for (size_t I = 0; I < Call.NumArguments + (Call.CanContinue ? 1 : 0); ++I)
Expand Down Expand Up @@ -330,10 +328,6 @@ void EVMOptimizedCodeTransform::operator()(const CFG::BasicBlock &Block) {
}
assert(static_cast<int>(CurrentStack.size()) == Assembly.getStackHeight());

// Emit jumpdest, if required.
if (EVMUtils::valueOrNullptr(BlockLabels, &Block))
Assembly.appendLabel();

for (const auto &Operation : Block.Operations) {
createOperationEntryLayout(Operation);

Expand Down Expand Up @@ -485,7 +479,6 @@ void EVMOptimizedCodeTransform::operator()() {
CurrentStack.emplace_back(Param);

Assembly.setStackHeight(static_cast<int>(CurrentStack.size()));
Assembly.appendLabel();

// Visit the function entry block.
(*this)(EntryBB);
Expand Down
26 changes: 7 additions & 19 deletions llvm/lib/Target/EVM/EVMStackify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -735,10 +735,6 @@ void StackModel::handleLStackAtJump(MachineBasicBlock *MBB, MachineInstr *MI,
MI->getOpcode() == EVM::JUMP ? EVM::PseudoJUMP : EVM::PseudoJUMPI;
BuildMI(*MI->getParent(), MI, DebugLoc(), TII->get(PseudoJumpOpc))
.addMBB(MBB);

// Add JUMPDEST at the beginning of the target MBB.
if (MBB->empty() || MBB->begin()->getOpcode() != EVM::JUMPDEST)
BuildMI(*MBB, MBB->begin(), DebugLoc(), TII->get(EVM::JUMPDEST));
}

void StackModel::handleCondJump(MachineInstr *MI) {
Expand Down Expand Up @@ -868,25 +864,21 @@ void StackModel::handleCall(MachineInstr *MI) {
// Callee removes them form the stack and pushes return values.

MachineBasicBlock &MBB = *MI->getParent();
// Create return destination.
MIIter It = BuildMI(MBB, MI, MI->getDebugLoc(), TII->get(EVM::JUMPDEST));

// Add symbol just after the jump that will be used as the return
// address from the function.
MCSymbol *RetSym = MF->getContext().createTempSymbol("FUNC_RET", true);

// Create jump to the callee.
It = BuildMI(MBB, It, MI->getDebugLoc(), TII->get(EVM::PseudoCALL));
It->setPostInstrSymbol(*MF, RetSym);
// Create pseudo jump to the callee, that will be expanded into PUSH, JUMP
// return label and JUMPDEST instructions in the AsmPrinter.
const MachineOperand *CalleeOp = MI->explicit_uses().begin();
assert(CalleeOp->isGlobal());
MIIter It = BuildMI(MBB, MI, MI->getDebugLoc(), TII->get(EVM::PseudoCALL))
.addGlobalAddress(CalleeOp->getGlobal())
.addSym(RetSym);

// Create push of the return address.
BuildMI(MBB, It, MI->getDebugLoc(), TII->get(EVM::PUSH_LABEL)).addSym(RetSym);

// Create push of the callee's address.
const MachineOperand *CalleeOp = MI->explicit_uses().begin();
assert(CalleeOp->isGlobal());
BuildMI(MBB, It, MI->getDebugLoc(), TII->get(EVM::PUSH_LABEL))
.addGlobalAddress(CalleeOp->getGlobal());
}

void StackModel::clearFrameObjsAtInst(MachineInstr *MI) {
Expand Down Expand Up @@ -986,10 +978,6 @@ void StackModel::preProcess() {
assert(!MF->empty());
allocateFrameObjects();
allocateXStack();
// Add JUMPDEST at the beginning of the first MBB,
// so this function can be jumped to.
MachineBasicBlock &MBB = MF->front();
BuildMI(MBB, MBB.begin(), DebugLoc(), TII->get(EVM::JUMPDEST));
}

// Remove all registers operands of the \p MI and repaces the opcode with
Expand Down

0 comments on commit 916ff45

Please sign in to comment.