From 916ff453ba3b33391262e307c670054b3329f9e9 Mon Sep 17 00:00:00 2001 From: Vladimir Radosavljevic Date: Thu, 5 Dec 2024 11:58:55 +0100 Subject: [PATCH] [EVM] Move generation of JUMPDEST to the AsmPrinter phase Signed-off-by: Vladimir Radosavljevic --- llvm/lib/Target/EVM/EVMAsmPrinter.cpp | 54 ++++++++++++++++++- llvm/lib/Target/EVM/EVMAssembly.cpp | 30 +++++------ llvm/lib/Target/EVM/EVMAssembly.h | 2 - llvm/lib/Target/EVM/EVMInstrInfo.td | 2 +- .../Target/EVM/EVMOptimizedCodeTransform.cpp | 7 --- llvm/lib/Target/EVM/EVMStackify.cpp | 26 +++------ 6 files changed, 74 insertions(+), 47 deletions(-) diff --git a/llvm/lib/Target/EVM/EVMAsmPrinter.cpp b/llvm/lib/Target/EVM/EVMAsmPrinter.cpp index ea39d5e3679a..f0da2b9a00fd 100644 --- a/llvm/lib/Target/EVM/EVMAsmPrinter.cpp +++ b/llvm/lib/Target/EVM/EVMAsmPrinter.cpp @@ -29,6 +29,8 @@ using namespace llvm; +extern cl::opt EVMKeepRegisters; + #define DEBUG_TYPE "asm-printer" namespace { @@ -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 @@ -77,6 +82,15 @@ 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()); @@ -84,7 +98,39 @@ void EVMAsmPrinter::emitInstruction(const MachineInstr *MI) { 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; @@ -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 X(getTheEVMTarget()); } diff --git a/llvm/lib/Target/EVM/EVMAssembly.cpp b/llvm/lib/Target/EVM/EVMAssembly.cpp index 775af0097186..7335679f09c6 100644 --- a/llvm/lib/Target/EVM/EVMAssembly.cpp +++ b/llvm/lib/Target/EVM/EVMAssembly.cpp @@ -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); @@ -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); diff --git a/llvm/lib/Target/EVM/EVMAssembly.h b/llvm/lib/Target/EVM/EVMAssembly.h index 58c0e2ed36de..d6303ae136df 100644 --- a/llvm/lib/Target/EVM/EVMAssembly.h +++ b/llvm/lib/Target/EVM/EVMAssembly.h @@ -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); diff --git a/llvm/lib/Target/EVM/EVMInstrInfo.td b/llvm/lib/Target/EVM/EVMInstrInfo.td index e2776d53e697..959447bf95f1 100644 --- a/llvm/lib/Target/EVM/EVMInstrInfo.td +++ b/llvm/lib/Target/EVM/EVMInstrInfo.td @@ -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 diff --git a/llvm/lib/Target/EVM/EVMOptimizedCodeTransform.cpp b/llvm/lib/Target/EVM/EVMOptimizedCodeTransform.cpp index 046067ee640f..b90758353298 100644 --- a/llvm/lib/Target/EVM/EVMOptimizedCodeTransform.cpp +++ b/llvm/lib/Target/EVM/EVMOptimizedCodeTransform.cpp @@ -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) @@ -330,10 +328,6 @@ void EVMOptimizedCodeTransform::operator()(const CFG::BasicBlock &Block) { } assert(static_cast(CurrentStack.size()) == Assembly.getStackHeight()); - // Emit jumpdest, if required. - if (EVMUtils::valueOrNullptr(BlockLabels, &Block)) - Assembly.appendLabel(); - for (const auto &Operation : Block.Operations) { createOperationEntryLayout(Operation); @@ -485,7 +479,6 @@ void EVMOptimizedCodeTransform::operator()() { CurrentStack.emplace_back(Param); Assembly.setStackHeight(static_cast(CurrentStack.size())); - Assembly.appendLabel(); // Visit the function entry block. (*this)(EntryBB); diff --git a/llvm/lib/Target/EVM/EVMStackify.cpp b/llvm/lib/Target/EVM/EVMStackify.cpp index 145ff2d7d211..d5ff664dc712 100644 --- a/llvm/lib/Target/EVM/EVMStackify.cpp +++ b/llvm/lib/Target/EVM/EVMStackify.cpp @@ -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) { @@ -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) { @@ -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