From 3cc01e9de014eb22dae505baf9e3cafae435d560 Mon Sep 17 00:00:00 2001 From: Pavel Kopyl Date: Mon, 30 Sep 2024 16:47:00 +0200 Subject: [PATCH] [EVM] Do stackification of instructions in the EVMStackify pass to have valid MIR This change moves the place where normal instructions are replaced with their 'stack' counterparts from the EVMMCInstLower to the EVMStackify pass. This ensures we have a valid MIR after each pass. This change also contains some updates in how labels are represented and resolved in the BE. --- llvm/lib/Target/EVM/CMakeLists.txt | 1 - llvm/lib/Target/EVM/EVMAsmPrinter.cpp | 31 +++++++- llvm/lib/Target/EVM/EVMISelLowering.cpp | 2 +- llvm/lib/Target/EVM/EVMInstrInfo.cpp | 7 ++ llvm/lib/Target/EVM/EVMInstrInfo.td | 10 +-- llvm/lib/Target/EVM/EVMMCInstLower.cpp | 38 ++++------ .../lib/Target/EVM/EVMMachineFunctionInfo.cpp | 27 +++++-- llvm/lib/Target/EVM/EVMMachineFunctionInfo.h | 40 ++++++++-- llvm/lib/Target/EVM/EVMRegColoring.cpp | 2 +- .../lib/Target/EVM/EVMSingleUseExpression.cpp | 11 +-- llvm/lib/Target/EVM/EVMStackify.cpp | 75 ++++++++++++++++--- llvm/lib/Target/EVM/EVMTargetMachine.cpp | 23 +++++- llvm/lib/Target/EVM/EVMTargetMachine.h | 8 ++ llvm/lib/Target/EVM/EVMTargetObjectFile.cpp | 20 ----- llvm/lib/Target/EVM/EVMTargetObjectFile.h | 4 +- .../Target/EVM/MCTargetDesc/EVMAsmBackend.cpp | 34 ++------- .../Target/EVM/MCTargetDesc/EVMFixupKinds.h | 6 +- .../EVM/MCTargetDesc/EVMMCCodeEmitter.cpp | 8 -- llvm/test/CodeGen/EVM/fallthrough.mir | 45 +++++++++++ llvm/test/CodeGen/Generic/undef-phi.ll | 1 - 20 files changed, 271 insertions(+), 122 deletions(-) delete mode 100644 llvm/lib/Target/EVM/EVMTargetObjectFile.cpp create mode 100644 llvm/test/CodeGen/EVM/fallthrough.mir diff --git a/llvm/lib/Target/EVM/CMakeLists.txt b/llvm/lib/Target/EVM/CMakeLists.txt index e2c1e7852fa6..ceed4bf575e0 100644 --- a/llvm/lib/Target/EVM/CMakeLists.txt +++ b/llvm/lib/Target/EVM/CMakeLists.txt @@ -36,7 +36,6 @@ add_llvm_target(EVMCodeGen EVMStackify.cpp EVMSubtarget.cpp EVMTargetMachine.cpp - EVMTargetObjectFile.cpp EVMTargetTransformInfo.cpp LINK_COMPONENTS diff --git a/llvm/lib/Target/EVM/EVMAsmPrinter.cpp b/llvm/lib/Target/EVM/EVMAsmPrinter.cpp index 168dcf273ed7..22b3d476d072 100644 --- a/llvm/lib/Target/EVM/EVMAsmPrinter.cpp +++ b/llvm/lib/Target/EVM/EVMAsmPrinter.cpp @@ -39,12 +39,36 @@ class EVMAsmPrinter : public AsmPrinter { StringRef getPassName() const override { return "EVM Assembly "; } + void SetupMachineFunction(MachineFunction &MF) override; + void emitInstruction(const MachineInstr *MI) override; void emitFunctionEntryLabel() override; + + /// Return true if the basic block has exactly one predecessor and the control + /// transfer mechanism between the predecessor and this block is a + /// fall-through. + bool isBlockOnlyReachableByFallthrough( + const MachineBasicBlock *MBB) const override; }; } // end of anonymous namespace +void EVMAsmPrinter::SetupMachineFunction(MachineFunction &MF) { + // Unbundle bundles. + for (MachineBasicBlock &MBB : MF) { + MachineBasicBlock::instr_iterator I = MBB.instr_begin(), + E = MBB.instr_end(); + for (; I != E; ++I) { + if (I->isBundledWithPred()) { + assert(I->isConditionalBranch() || I->isUnconditionalBranch()); + I->unbundleFromPred(); + } + } + } + + AsmPrinter::SetupMachineFunction(MF); +} + void EVMAsmPrinter::emitFunctionEntryLabel() { AsmPrinter::emitFunctionEntryLabel(); @@ -70,12 +94,17 @@ void EVMAsmPrinter::emitFunctionEntryLabel() { void EVMAsmPrinter::emitInstruction(const MachineInstr *MI) { EVMMCInstLower MCInstLowering(OutContext, *this, VRegMapping, MF->getRegInfo()); - MCInst TmpInst; MCInstLowering.Lower(MI, TmpInst); EmitToStreamer(*OutStreamer, TmpInst); } +bool EVMAsmPrinter::isBlockOnlyReachableByFallthrough( + const MachineBasicBlock *MBB) const { + // For simplicity, always emit BB labels. + return false; +} + extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeEVMAsmPrinter() { const RegisterAsmPrinter X(getTheEVMTarget()); } diff --git a/llvm/lib/Target/EVM/EVMISelLowering.cpp b/llvm/lib/Target/EVM/EVMISelLowering.cpp index f4f65d50ed28..6c8738d2d52f 100644 --- a/llvm/lib/Target/EVM/EVMISelLowering.cpp +++ b/llvm/lib/Target/EVM/EVMISelLowering.cpp @@ -387,7 +387,7 @@ SDValue EVMTargetLowering::LowerFormalArguments( fail(DL, DAG, "VarArg is not supported yet"); MachineFunction &MF = DAG.getMachineFunction(); - auto *MFI = MF.getInfo(); + auto *MFI = MF.getInfo(); // Set up the incoming ARGUMENTS value, which serves to represent the liveness // of the incoming values before they're represented by virtual registers. diff --git a/llvm/lib/Target/EVM/EVMInstrInfo.cpp b/llvm/lib/Target/EVM/EVMInstrInfo.cpp index 69b98ae7152f..caa9e68cb011 100644 --- a/llvm/lib/Target/EVM/EVMInstrInfo.cpp +++ b/llvm/lib/Target/EVM/EVMInstrInfo.cpp @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// #include "EVMInstrInfo.h" +#include "EVMMachineFunctionInfo.h" #include "MCTargetDesc/EVMMCTargetDesc.h" using namespace llvm; @@ -65,6 +66,12 @@ bool EVMInstrInfo::analyzeBranch(MachineBasicBlock &MBB, FBB = nullptr; Cond.clear(); + const auto *MFI = MBB.getParent()->getInfo(); + if (MFI->getIsStackified()) { + LLVM_DEBUG(dbgs() << "Can't analyze terminators in stackified code"); + return true; + } + // Iterate backwards and analyze all terminators. MachineBasicBlock::reverse_iterator I = MBB.rbegin(), E = MBB.rend(); while (I != E) { diff --git a/llvm/lib/Target/EVM/EVMInstrInfo.td b/llvm/lib/Target/EVM/EVMInstrInfo.td index 0ece41690a4b..8700834e45d8 100644 --- a/llvm/lib/Target/EVM/EVMInstrInfo.td +++ b/llvm/lib/Target/EVM/EVMInstrInfo.td @@ -794,7 +794,7 @@ foreach I = {1-16} in { defm PUSH0 : I<(outs), (ins), [], "PUSH0", "", 0x5F, 2>; -def PUSH8_LABEL : NI<(outs), (ins jmptarget:$dst), [], false, "", 0, 0> { +def PUSH_LABEL : NI<(outs), (ins jmptarget:$dst), [], false, "", 0, 0> { let isCodeGenOnly = 1; } @@ -1122,7 +1122,7 @@ def PUSH32_S : NI<(outs), (ins i256imm:$imm), [], true, "PUSH32 $imm", } // Pseudo instructions for linkage -let isCodeGenOnly = 1 in -defm DATA - : I<(outs GPR:$dst), (ins jmptarget:$reloc), [], "", - "", 0, 0>; +let isCodeGenOnly = 1, BaseName = "DATA" in { + def DATA : NI<(outs GPR:$dst), (ins jmptarget:$reloc), [], false, "", 0, 0>; + def DATA_S : NI<(outs), (ins jmptarget:$reloc), [], true, "", 0, 0>; +} diff --git a/llvm/lib/Target/EVM/EVMMCInstLower.cpp b/llvm/lib/Target/EVM/EVMMCInstLower.cpp index ceea05b7f723..297385478bb7 100644 --- a/llvm/lib/Target/EVM/EVMMCInstLower.cpp +++ b/llvm/lib/Target/EVM/EVMMCInstLower.cpp @@ -27,33 +27,23 @@ using namespace llvm; extern cl::opt EVMKeepRegisters; -static void removeRegisterOperands(const MachineInstr *MI, MCInst &OutMI) { - // Remove all uses of stackified registers to bring the instruction format - // into its final stack form used throughout MC, and transition opcodes to - // their _S variant. +// Stackify instruction that were not stackified before. +// Only two instructions need to be stackified here: PUSH_LABEL and DATA_S, +static void stackifyInstruction(const MachineInstr *MI, MCInst &OutMI) { if (MI->isDebugInstr() || MI->isLabel() || MI->isInlineAsm()) return; - // Transform 'register' instruction to 'stack' one. - unsigned RegOpcode = OutMI.getOpcode(); - if (RegOpcode == EVM::PUSH8_LABEL) { - // Replace PUSH8_LABEL with PUSH8_S opcode. - OutMI.setOpcode(EVM::PUSH8_S); - } else { - unsigned StackOpcode = EVM::getStackOpcode(RegOpcode); - OutMI.setOpcode(StackOpcode); - } + // Check there are no register operands. + assert(std::all_of(OutMI.begin(), OutMI.end(), + [](const MCOperand &MO) { return !MO.isReg(); })); - // Remove register operands. - for (auto I = OutMI.getNumOperands(); I; --I) { - auto &MO = OutMI.getOperand(I - 1); - if (MO.isReg()) { - OutMI.erase(&MO); - } - } - - if (RegOpcode == EVM::DATA) + // Set up final opcodes for the following codegen-only instructions. + unsigned Opcode = OutMI.getOpcode(); + if (Opcode == EVM::PUSH_LABEL || Opcode == EVM::DATA_S) OutMI.setOpcode(EVM::PUSH4_S); + + // Check that all the instructions are in the 'stack' form. + assert(EVM::getRegisterOpcode(OutMI.getOpcode())); } MCSymbol * @@ -136,7 +126,7 @@ void EVMMCInstLower::Lower(const MachineInstr *MI, MCInst &OutMI) { case MachineOperand::MO_MCSymbol: { MCSymbolRefExpr::VariantKind Kind = MCSymbolRefExpr::VariantKind::VK_None; unsigned Opc = MI->getOpcode(); - if (Opc == EVM::DATA) + if (Opc == EVM::DATA_S) Kind = MCSymbolRefExpr::VariantKind::VK_EVM_DATA; MCOp = MCOperand::createExpr( @@ -156,7 +146,7 @@ void EVMMCInstLower::Lower(const MachineInstr *MI, MCInst &OutMI) { OutMI.addOperand(MCOp); } if (!EVMKeepRegisters) - removeRegisterOperands(MI, OutMI); + stackifyInstruction(MI, OutMI); else if (Desc.variadicOpsAreDefs()) OutMI.insert(OutMI.begin(), MCOperand::createImm(MI->getNumExplicitDefs())); } diff --git a/llvm/lib/Target/EVM/EVMMachineFunctionInfo.cpp b/llvm/lib/Target/EVM/EVMMachineFunctionInfo.cpp index 63574319e396..50db06c257f9 100644 --- a/llvm/lib/Target/EVM/EVMMachineFunctionInfo.cpp +++ b/llvm/lib/Target/EVM/EVMMachineFunctionInfo.cpp @@ -13,11 +13,26 @@ #include "EVMMachineFunctionInfo.h" using namespace llvm; -EVMFunctionInfo::~EVMFunctionInfo() = default; // anchor. +EVMMachineFunctionInfo::~EVMMachineFunctionInfo() = default; -MachineFunctionInfo * -EVMFunctionInfo::clone(BumpPtrAllocator &Allocator, MachineFunction &DestMF, - const DenseMap - &Src2DstMBB) const { - return DestMF.cloneInfo(*this); +MachineFunctionInfo *EVMMachineFunctionInfo::clone( + BumpPtrAllocator &Allocator, MachineFunction &DestMF, + const DenseMap &Src2DstMBB) + const { + return DestMF.cloneInfo(*this); +} + +yaml::EVMMachineFunctionInfo::~EVMMachineFunctionInfo() = default; + +yaml::EVMMachineFunctionInfo::EVMMachineFunctionInfo( + const llvm::EVMMachineFunctionInfo &MFI) + : IsStackified(MFI.getIsStackified()) {} + +void yaml::EVMMachineFunctionInfo::mappingImpl(yaml::IO &YamlIO) { + MappingTraits::mapping(YamlIO, *this); +} + +void EVMMachineFunctionInfo::initializeBaseYamlFields( + const yaml::EVMMachineFunctionInfo &YamlMFI) { + IsStackified = YamlMFI.IsStackified; } diff --git a/llvm/lib/Target/EVM/EVMMachineFunctionInfo.h b/llvm/lib/Target/EVM/EVMMachineFunctionInfo.h index b39709960358..0d49c32cebe8 100644 --- a/llvm/lib/Target/EVM/EVMMachineFunctionInfo.h +++ b/llvm/lib/Target/EVM/EVMMachineFunctionInfo.h @@ -16,13 +16,33 @@ #include "MCTargetDesc/EVMMCTargetDesc.h" #include "llvm/CodeGen/MIRYamlMapping.h" #include "llvm/CodeGen/MachineRegisterInfo.h" -#include "llvm/MC/MCSymbolWasm.h" namespace llvm { +class EVMMachineFunctionInfo; + +namespace yaml { + +struct EVMMachineFunctionInfo final : public yaml::MachineFunctionInfo { + bool IsStackified = false; + + EVMMachineFunctionInfo() = default; + explicit EVMMachineFunctionInfo(const llvm::EVMMachineFunctionInfo &MFI); + ~EVMMachineFunctionInfo() override; + + void mappingImpl(yaml::IO &YamlIO) override; +}; + +template <> struct MappingTraits { + static void mapping(IO &YamlIO, EVMMachineFunctionInfo &MFI) { + YamlIO.mapOptional("isStackified", MFI.IsStackified, false); + } +}; +} // end namespace yaml + /// This class is derived from MachineFunctionInfo and contains private /// EVM-specific information for each MachineFunction. -class EVMFunctionInfo final : public MachineFunctionInfo { +class EVMMachineFunctionInfo final : public MachineFunctionInfo { /// A mapping from CodeGen vreg index to a boolean value indicating whether /// the given register is considered to be "stackified", meaning it has been /// determined or made to meet the stack requirements: @@ -34,16 +54,21 @@ class EVMFunctionInfo final : public MachineFunctionInfo { /// Number of parameters. Their type doesn't matter as it always is i256. unsigned NumberOfParameters = 0; + /// If the MF's instructions are in 'stack' form. + bool IsStackified = false; + public: - explicit EVMFunctionInfo(MachineFunction &MF) {} - EVMFunctionInfo(const Function &F, const TargetSubtargetInfo *STI) {} - ~EVMFunctionInfo() override; + explicit EVMMachineFunctionInfo(MachineFunction &MF) {} + EVMMachineFunctionInfo(const Function &F, const TargetSubtargetInfo *STI) {} + ~EVMMachineFunctionInfo() override; MachineFunctionInfo * clone(BumpPtrAllocator &Allocator, MachineFunction &DestMF, const DenseMap &Src2DstMBB) const override; + void initializeBaseYamlFields(const yaml::EVMMachineFunctionInfo &YamlMFI); + void stackifyVReg(MachineRegisterInfo &MRI, unsigned VReg) { assert(MRI.getUniqueVRegDef(VReg)); auto I = Register::virtReg2Index(VReg); @@ -72,7 +97,12 @@ class EVMFunctionInfo final : public MachineFunctionInfo { unsigned getNumParams() const { return NumberOfParameters; } + + void setIsStackified(bool Val = true) { IsStackified = Val; } + + bool getIsStackified() const { return IsStackified; } }; + } // end namespace llvm #endif // LLVM_LIB_TARGET_EVM_EVMMACHINEFUNCTIONINFO_H diff --git a/llvm/lib/Target/EVM/EVMRegColoring.cpp b/llvm/lib/Target/EVM/EVMRegColoring.cpp index f2f5fe51c6a0..d18461b3a97a 100644 --- a/llvm/lib/Target/EVM/EVMRegColoring.cpp +++ b/llvm/lib/Target/EVM/EVMRegColoring.cpp @@ -80,7 +80,7 @@ bool EVMRegColoring::runOnMachineFunction(MachineFunction &MF) { LiveIntervals *Liveness = &getAnalysis(); const MachineBlockFrequencyInfo *MBFI = &getAnalysis(); - EVMFunctionInfo &MFI = *MF.getInfo(); + EVMMachineFunctionInfo &MFI = *MF.getInfo(); // Gather all register intervals into a list and sort them. unsigned NumVRegs = MRI->getNumVirtRegs(); diff --git a/llvm/lib/Target/EVM/EVMSingleUseExpression.cpp b/llvm/lib/Target/EVM/EVMSingleUseExpression.cpp index f383fa7e4ca2..8337dc7875d1 100644 --- a/llvm/lib/Target/EVM/EVMSingleUseExpression.cpp +++ b/llvm/lib/Target/EVM/EVMSingleUseExpression.cpp @@ -268,7 +268,8 @@ static bool shouldRematerialize(const MachineInstr &Def, // TODO: Compute memory dependencies in a way that uses AliasAnalysis to be // more precise. static bool isSafeToMove(const MachineOperand *Def, const MachineOperand *Use, - const MachineInstr *Insert, const EVMFunctionInfo &MFI, + const MachineInstr *Insert, + const EVMMachineFunctionInfo &MFI, const MachineRegisterInfo &MRI) { const MachineInstr *DefI = Def->getParent(); const MachineInstr *UseI = Use->getParent(); @@ -390,7 +391,7 @@ static void shrinkToUses(LiveInterval &LI, LiveIntervals &LIS) { static MachineInstr *moveForSingleUse(unsigned Reg, MachineOperand &Op, MachineInstr *Def, MachineBasicBlock &MBB, MachineInstr *Insert, LiveIntervals &LIS, - EVMFunctionInfo &MFI, + EVMMachineFunctionInfo &MFI, MachineRegisterInfo &MRI) { LLVM_DEBUG(dbgs() << "Move for single use: "; Def->dump()); @@ -430,8 +431,8 @@ static MachineInstr *moveForSingleUse(unsigned Reg, MachineOperand &Op, static MachineInstr *rematerializeCheapDef( unsigned Reg, MachineOperand &Op, MachineInstr &Def, MachineBasicBlock &MBB, MachineBasicBlock::instr_iterator Insert, LiveIntervals &LIS, - EVMFunctionInfo &MFI, MachineRegisterInfo &MRI, const EVMInstrInfo *TII, - const EVMRegisterInfo *TRI) { + EVMMachineFunctionInfo &MFI, MachineRegisterInfo &MRI, + const EVMInstrInfo *TII, const EVMRegisterInfo *TRI) { LLVM_DEBUG(dbgs() << "Rematerializing cheap def: "; Def.dump()); LLVM_DEBUG(dbgs() << " - for use in "; Op.getParent()->dump()); @@ -593,7 +594,7 @@ bool EVMSingleUseExpression::runOnMachineFunction(MachineFunction &MF) { bool Changed = false; MachineRegisterInfo &MRI = MF.getRegInfo(); - EVMFunctionInfo &MFI = *MF.getInfo(); + EVMMachineFunctionInfo &MFI = *MF.getInfo(); const auto *TII = MF.getSubtarget().getInstrInfo(); const auto *TRI = MF.getSubtarget().getRegisterInfo(); auto &MDT = getAnalysis(); diff --git a/llvm/lib/Target/EVM/EVMStackify.cpp b/llvm/lib/Target/EVM/EVMStackify.cpp index 5c674f4f10c4..d5c32e402c83 100644 --- a/llvm/lib/Target/EVM/EVMStackify.cpp +++ b/llvm/lib/Target/EVM/EVMStackify.cpp @@ -320,6 +320,8 @@ class StackModel { void peelPhysStack(StackType Type, unsigned NumItems, MachineBasicBlock *BB, MIIter Pos); + void stackifyInstruction(MachineInstr *MI); + static unsigned getDUPOpcode(unsigned Depth); static unsigned getSWAPOpcode(unsigned Depth); @@ -724,10 +726,10 @@ void StackModel::handleLStackAtJump(MachineBasicBlock *MBB, MachineInstr *MI, // EVM::NoRegister. clearPhysStackAtInst(StackType::L, MI, Reg); - // Insert "PUSH8_LABEL %bb" instruction that should be be replaced with + // Insert "PUSH_LABEL %bb" instruction that should be be replaced with // the actual PUSH* one in the MC layer to contain actual jump target // offset. - BuildMI(*MI->getParent(), MI, DebugLoc(), TII->get(EVM::PUSH8_LABEL)) + BuildMI(*MI->getParent(), MI, DebugLoc(), TII->get(EVM::PUSH_LABEL)) .addMBB(MBB); // Add JUMPDEST at the beginning of the target MBB. @@ -759,7 +761,7 @@ void StackModel::handleReturn(MachineInstr *MI) { ReturnRegs.push_back(MO.getReg()); } - auto *MFI = MF->getInfo(); + auto *MFI = MF->getInfo(); if (MFI->getNumParams() >= ReturnRegs.size()) { // Move the return registers to the stack location where // arguments were resided. @@ -874,13 +876,12 @@ void StackModel::handleCall(MachineInstr *MI) { It->setPostInstrSymbol(*MF, RetSym); // Create push of the return address. - BuildMI(MBB, It, MI->getDebugLoc(), TII->get(EVM::PUSH8_LABEL)) - .addSym(RetSym); + 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::PUSH8_LABEL)) + BuildMI(MBB, It, MI->getDebugLoc(), TII->get(EVM::PUSH_LABEL)) .addGlobalAddress(CalleeOp->getGlobal()); } @@ -987,6 +988,29 @@ void StackModel::preProcess() { BuildMI(MBB, MBB.begin(), DebugLoc(), TII->get(EVM::JUMPDEST)); } +// Remove all registers operands of the \p MI and repaces the opcode with +// the stack variant variant. +void StackModel::stackifyInstruction(MachineInstr *MI) { + if (MI->isDebugInstr() || MI->isLabel() || MI->isInlineAsm()) + return; + + unsigned RegOpcode = MI->getOpcode(); + if (RegOpcode == EVM::PUSH_LABEL) + return; + + // Remove register operands. + for (unsigned I = MI->getNumOperands(); I > 0; --I) { + auto &MO = MI->getOperand(I - 1); + if (MO.isReg()) { + MI->removeOperand(I - 1); + } + } + + // Transform 'register' instruction to the 'stack' one. + unsigned StackOpcode = EVM::getStackOpcode(RegOpcode); + MI->setDesc(TII->get(StackOpcode)); +} + void StackModel::postProcess() { for (MachineBasicBlock &MBB : *MF) { for (MachineInstr &MI : MBB) { @@ -1013,6 +1037,42 @@ void StackModel::postProcess() { for (auto *MI : ToErase) MI->eraseFromParent(); + + for (MachineBasicBlock &MBB : *MF) + for (MachineInstr &MI : MBB) + stackifyInstruction(&MI); + + auto *MFI = MF->getInfo(); + MFI->setIsStackified(); + + // In a stackified code register liveness has no meaning. + MachineRegisterInfo &MRI = MF->getRegInfo(); + MRI.invalidateLiveness(); + + // In EVM architecture jump target is set up using one of PUSH* instructions + // that come right before the jump instruction. + // For example: + + // PUSH_LABEL %bb.10 + // JUMPI_S + // PUSH_LABEL %bb.9 + // JUMP_S + // + // The problem here is that such MIR is not valid. There should not be + // non-terminator (PUSH) instructions between terminator (JUMP) ones. + // To overcome this issue, we bundle adjacent instructions + // together and unbundle them in the AsmPrinter. + for (MachineBasicBlock &MBB : *MF) { + MachineBasicBlock::instr_iterator I = MBB.instr_begin(), + E = MBB.instr_end(); + for (; I != E; ++I) { + if (I->isBranch()) { + auto P = std::next(I); + if (P != E && P->getOpcode() == EVM::PUSH_LABEL) + I->bundleWithPred(); + } + } + } } void StackModel::dumpState() const { @@ -1129,9 +1189,6 @@ class EVMStackify final : public MachineFunctionPass { AU.addRequired(); AU.addRequired(); AU.addPreserved(); - AU.addPreserved(); - AU.addPreserved(); - AU.addPreservedID(LiveVariablesID); AU.addPreserved(); MachineFunctionPass::getAnalysisUsage(AU); } diff --git a/llvm/lib/Target/EVM/EVMTargetMachine.cpp b/llvm/lib/Target/EVM/EVMTargetMachine.cpp index 29154cd8c30b..eaf0892de5ff 100644 --- a/llvm/lib/Target/EVM/EVMTargetMachine.cpp +++ b/llvm/lib/Target/EVM/EVMTargetMachine.cpp @@ -17,6 +17,8 @@ #include "EVMTargetObjectFile.h" #include "EVMTargetTransformInfo.h" #include "TargetInfo/EVMTargetInfo.h" +#include "llvm/CodeGen/MIRParser/MIParser.h" +#include "llvm/CodeGen/MIRYamlMapping.h" #include "llvm/CodeGen/Passes.h" #include "llvm/CodeGen/TargetPassConfig.h" #include "llvm/InitializePasses.h" @@ -84,7 +86,26 @@ EVMTargetMachine::getTargetTransformInfo(const Function &F) const { MachineFunctionInfo *EVMTargetMachine::createMachineFunctionInfo( BumpPtrAllocator &Allocator, const Function &F, const TargetSubtargetInfo *STI) const { - return EVMFunctionInfo::create(Allocator, F, STI); + return EVMMachineFunctionInfo::create(Allocator, F, + STI); +} + +yaml::MachineFunctionInfo *EVMTargetMachine::createDefaultFuncInfoYAML() const { + return new yaml::EVMMachineFunctionInfo(); +} + +yaml::MachineFunctionInfo * +EVMTargetMachine::convertFuncInfoToYAML(const MachineFunction &MF) const { + const auto *MFI = MF.getInfo(); + return new yaml::EVMMachineFunctionInfo(*MFI); +} + +bool EVMTargetMachine::parseMachineFunctionInfo( + const yaml::MachineFunctionInfo &MFI, PerFunctionMIParsingState &PFS, + SMDiagnostic &Error, SMRange &SourceRange) const { + const auto &YamlMFI = static_cast(MFI); + PFS.MF.getInfo()->initializeBaseYamlFields(YamlMFI); + return false; } void EVMTargetMachine::registerPassBuilderCallbacks(PassBuilder &PB) { diff --git a/llvm/lib/Target/EVM/EVMTargetMachine.h b/llvm/lib/Target/EVM/EVMTargetMachine.h index 10309fc56005..3bb1b542b48e 100644 --- a/llvm/lib/Target/EVM/EVMTargetMachine.h +++ b/llvm/lib/Target/EVM/EVMTargetMachine.h @@ -43,6 +43,14 @@ class EVMTargetMachine final : public LLVMTargetMachine { createMachineFunctionInfo(BumpPtrAllocator &Allocator, const Function &F, const TargetSubtargetInfo *STI) const override; + yaml::MachineFunctionInfo *createDefaultFuncInfoYAML() const override; + yaml::MachineFunctionInfo * + convertFuncInfoToYAML(const MachineFunction &MF) const override; + bool parseMachineFunctionInfo(const yaml::MachineFunctionInfo &, + PerFunctionMIParsingState &PFS, + SMDiagnostic &Error, + SMRange &SourceRange) const override; + TargetLoweringObjectFile *getObjFileLowering() const override { return TLOF.get(); } diff --git a/llvm/lib/Target/EVM/EVMTargetObjectFile.cpp b/llvm/lib/Target/EVM/EVMTargetObjectFile.cpp deleted file mode 100644 index 1da524fbe949..000000000000 --- a/llvm/lib/Target/EVM/EVMTargetObjectFile.cpp +++ /dev/null @@ -1,20 +0,0 @@ -//===------------- EVMTargetObjectFile.cpp - EVM Object Info --------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file defines the functions of the EVM-specific subclass -// of TargetLoweringObjectFile. -// -//===----------------------------------------------------------------------===// - -#include "EVMTargetObjectFile.h" - -using namespace llvm; - -// Code sections need to be aligned on 1, otherwise linker will add padding -// between .text sections of the object files being linked. -unsigned EVMELFTargetObjectFile::getTextSectionAlignment() const { return 1; } diff --git a/llvm/lib/Target/EVM/EVMTargetObjectFile.h b/llvm/lib/Target/EVM/EVMTargetObjectFile.h index 7de553b2480e..1afa2bb7fb41 100644 --- a/llvm/lib/Target/EVM/EVMTargetObjectFile.h +++ b/llvm/lib/Target/EVM/EVMTargetObjectFile.h @@ -22,7 +22,9 @@ class EVMELFTargetObjectFile final : public TargetLoweringObjectFileELF { public: EVMELFTargetObjectFile() = default; - unsigned getTextSectionAlignment() const override; + // Code sections need to be aligned on 1, otherwise linker will add padding + // between .text sections of the object files being linked. + unsigned getTextSectionAlignment() const override { return 1; } }; } // end namespace llvm diff --git a/llvm/lib/Target/EVM/MCTargetDesc/EVMAsmBackend.cpp b/llvm/lib/Target/EVM/MCTargetDesc/EVMAsmBackend.cpp index e2d4cbfd10af..b8af5de6aab8 100644 --- a/llvm/lib/Target/EVM/MCTargetDesc/EVMAsmBackend.cpp +++ b/llvm/lib/Target/EVM/MCTargetDesc/EVMAsmBackend.cpp @@ -23,6 +23,9 @@ #include "llvm/MC/MCValue.h" #include "llvm/MC/TargetRegistry.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" + +#include using namespace llvm; @@ -100,10 +103,6 @@ const MCFixupKindInfo &EVMAsmBackend::getFixupKindInfo(MCFixupKind Kind) const { // in EVMFixupKinds.h. // // Name Offset (bits) Size (bits) Flags - {"fixup_SecRel_i64", 0, 8 * 8, MCFixupKindInfo::FKF_IsTarget}, - {"fixup_SecRel_i56", 0, 8 * 7, MCFixupKindInfo::FKF_IsTarget}, - {"fixup_SecRel_i48", 0, 8 * 6, MCFixupKindInfo::FKF_IsTarget}, - {"fixup_SecRel_i40", 0, 8 * 5, MCFixupKindInfo::FKF_IsTarget}, {"fixup_SecRel_i32", 0, 8 * 4, MCFixupKindInfo::FKF_IsTarget}, {"fixup_SecRel_i24", 0, 8 * 3, MCFixupKindInfo::FKF_IsTarget}, {"fixup_SecRel_i16", 0, 8 * 2, MCFixupKindInfo::FKF_IsTarget}, @@ -136,6 +135,9 @@ bool EVMAsmBackend::evaluateTargetFixup(const MCAssembler &Asm, return false; Value = Target.getConstant(); + if (Value > std::numeric_limits::max()) + report_fatal_error("Fixup value exceeds the displacement 2^32"); + if (const MCSymbolRefExpr *A = Target.getSymA()) { const MCSymbol &Sym = A->getSymbol(); assert(Sym.isDefined()); @@ -180,18 +182,6 @@ void EVMAsmBackend::relaxInstruction(MCInst &Inst, switch (Inst.getOpcode()) { default: llvm_unreachable("Unexpected instruction for relaxation"); - case EVM::PUSH8_S: - Inst.setOpcode(EVM::PUSH7_S); - break; - case EVM::PUSH7_S: - Inst.setOpcode(EVM::PUSH6_S); - break; - case EVM::PUSH6_S: - Inst.setOpcode(EVM::PUSH5_S); - break; - case EVM::PUSH5_S: - Inst.setOpcode(EVM::PUSH4_S); - break; case EVM::PUSH4_S: Inst.setOpcode(EVM::PUSH3_S); break; @@ -229,14 +219,6 @@ bool EVMAsmBackend::fixupNeedsRelaxationAdvanced(const MCFixup &Fixup, switch (FixUpKind) { default: llvm_unreachable("Unexpected target fixup kind"); - case EVM::fixup_SecRel_i64: - return OffsetByteWidth < 8; - case EVM::fixup_SecRel_i56: - return OffsetByteWidth < 7; - case EVM::fixup_SecRel_i48: - return OffsetByteWidth < 6; - case EVM::fixup_SecRel_i40: - return OffsetByteWidth < 5; case EVM::fixup_SecRel_i32: return OffsetByteWidth < 4; case EVM::fixup_SecRel_i24: @@ -251,10 +233,6 @@ bool EVMAsmBackend::mayNeedRelaxation(const MCInst &Inst, switch (Inst.getOpcode()) { default: return false; - case EVM::PUSH8_S: - case EVM::PUSH7_S: - case EVM::PUSH6_S: - case EVM::PUSH5_S: case EVM::PUSH4_S: case EVM::PUSH3_S: case EVM::PUSH2_S: diff --git a/llvm/lib/Target/EVM/MCTargetDesc/EVMFixupKinds.h b/llvm/lib/Target/EVM/MCTargetDesc/EVMFixupKinds.h index 8d63558bd5ef..ed5ea473e603 100644 --- a/llvm/lib/Target/EVM/MCTargetDesc/EVMFixupKinds.h +++ b/llvm/lib/Target/EVM/MCTargetDesc/EVMFixupKinds.h @@ -14,11 +14,7 @@ namespace llvm { namespace EVM { enum Fixups { - fixup_SecRel_i64 = FirstTargetFixupKind, // 64-bit unsigned - fixup_SecRel_i56, // 56-bit unsigned - fixup_SecRel_i48, // 48-bit unsigned - fixup_SecRel_i40, // 40-bit unsigned - fixup_SecRel_i32, // 32-bit unsigned + fixup_SecRel_i32 = FirstTargetFixupKind, // 32-bit unsigned fixup_SecRel_i24, // 24-bit unsigned fixup_SecRel_i16, // 16-bit unsigned fixup_SecRel_i8, // 8-bit unsigned diff --git a/llvm/lib/Target/EVM/MCTargetDesc/EVMMCCodeEmitter.cpp b/llvm/lib/Target/EVM/MCTargetDesc/EVMMCCodeEmitter.cpp index 0e952d2ed20e..9363d06e4d2f 100644 --- a/llvm/lib/Target/EVM/MCTargetDesc/EVMMCCodeEmitter.cpp +++ b/llvm/lib/Target/EVM/MCTargetDesc/EVMMCCodeEmitter.cpp @@ -54,14 +54,6 @@ EVM::Fixups getFixupForOpc(unsigned Opcode, MCSymbolRefExpr::VariantKind Kind) { switch (Opcode) { default: llvm_unreachable("Unexpected MI for the SymbolRef MO"); - case EVM::PUSH8_S: - return EVM::fixup_SecRel_i64; - case EVM::PUSH7_S: - return EVM::fixup_SecRel_i56; - case EVM::PUSH6_S: - return EVM::fixup_SecRel_i48; - case EVM::PUSH5_S: - return EVM::fixup_SecRel_i40; case EVM::PUSH4_S: switch (Kind) { default: diff --git a/llvm/test/CodeGen/EVM/fallthrough.mir b/llvm/test/CodeGen/EVM/fallthrough.mir new file mode 100644 index 000000000000..b5efb4f62911 --- /dev/null +++ b/llvm/test/CodeGen/EVM/fallthrough.mir @@ -0,0 +1,45 @@ +# RUN: llc -x mir --start-after=evm-stackify < %s | FileCheck %s + + +--- | + + target datalayout = "E-p:256:256-i256:256:256-S256-a:256:256" + target triple = "evm" + define void @test_fallthrough() { ret void } + +... +--- +# CHECK: PUSH4 @.BB0_1 +# CHECK-NEXT: JUMPI +# CHECK-NEXT: PUSH4 @.BB0_2 +# CHECK-NEXT: JUMP +# CHECK-NEXT: .BB0_1: + +name: test_fallthrough +tracksRegLiveness: false +machineFunctionInfo: + isStackified: true +body: | + bb.0: + JUMPDEST_S + PUSH_LABEL %bb.10 { + JUMPI_S + } + PUSH_LABEL %bb.13 { + JUMP_S + } + + bb.10: + liveins: $value_stack + JUMPDEST_S + PUSH0_S + PUSH0_S + REVERT_S + + bb.13: + liveins: $value_stack + JUMPDEST_S + PUSH0_S + PUSH0_S + REVERT_S +... diff --git a/llvm/test/CodeGen/Generic/undef-phi.ll b/llvm/test/CodeGen/Generic/undef-phi.ll index 89d73901436d..0e221fe612ab 100644 --- a/llvm/test/CodeGen/Generic/undef-phi.ll +++ b/llvm/test/CodeGen/Generic/undef-phi.ll @@ -1,5 +1,4 @@ ; RUN: llc < %s -verify-machineinstrs -verify-coalescing -; UNSUPPORTED: target=evm{{.*}} ; ; This function has a PHI with one undefined input. Verify that PHIElimination ; inserts an IMPLICIT_DEF instruction in the predecessor so all paths to the use