Skip to content

Commit

Permalink
[EVM] Support commutable operations, re-enable inlining and add some …
Browse files Browse the repository at this point in the history
…NFC fixes.
  • Loading branch information
PavelKopyl committed Nov 14, 2024
1 parent d1784e0 commit 38c8fbd
Show file tree
Hide file tree
Showing 26 changed files with 435 additions and 259 deletions.
2 changes: 1 addition & 1 deletion llvm/lib/Target/EVM/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ add_llvm_target(EVMCodeGen
EVMArgumentMove.cpp
EVMAsmPrinter.cpp
EVMAssembly.cpp
EVMBackwardPropagationStackification.cpp
EVMCodegenPrepare.cpp
EVMControlFlowGraphBuilder.cpp
EVMFrameLowering.cpp
Expand All @@ -40,7 +41,6 @@ add_llvm_target(EVMCodeGen
EVMStackDebug.cpp
EVMStackLayoutGenerator.cpp
EVMStackify.cpp
EVMStackifyEF.cpp
EVMSubtarget.cpp
EVMTargetMachine.cpp
EVMTargetTransformInfo.cpp
Expand Down
4 changes: 2 additions & 2 deletions llvm/lib/Target/EVM/EVM.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ FunctionPass *createEVMRegColoring();
FunctionPass *createEVMSingleUseExpression();
FunctionPass *createEVMSplitCriticalEdges();
FunctionPass *createEVMStackify();
FunctionPass *createEVMStackifyEF();
FunctionPass *createEVMBPStackification();

// PassRegistry initialization declarations.
void initializeEVMCodegenPreparePass(PassRegistry &);
Expand All @@ -65,7 +65,7 @@ void initializeEVMRegColoringPass(PassRegistry &);
void initializeEVMSingleUseExpressionPass(PassRegistry &);
void initializeEVMSplitCriticalEdgesPass(PassRegistry &);
void initializeEVMStackifyPass(PassRegistry &);
void initializeEVMStackifyEFPass(PassRegistry &);
void initializeEVMBPStackificationPass(PassRegistry &);

struct EVMLinkRuntimePass : PassInfoMixin<EVMLinkRuntimePass> {
EVMLinkRuntimePass() = default;
Expand Down
16 changes: 8 additions & 8 deletions llvm/lib/Target/EVM/EVMAssembly.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,10 @@
//
//===----------------------------------------------------------------------===//
//
// This file implements the EVMAssembly class that generates machine IR
// with all the required stack manipulation instructions.
// Resulting machine instructions still have explicit operands, but some of the
// auxiliary instructions (ARGUMENT, RET, EVM::CONST_I256, COPY_I256
// FCALLARGUMENT) are removed after this step, beaking use-def chains. So, the
// resulting Machine IR breaks the MachineVerifier checks.
// This file creates Machine IR in stackified form. It provides different
// callbacks when the EVMOptimizedCodeTransform needs to emit operation,
// stack manipulation instruction, and so on. It the end, it walks over MIR
// instructions removing register operands.
//
//===----------------------------------------------------------------------===//

Expand Down Expand Up @@ -51,12 +49,14 @@ void EVMAssembly::setCurrentLocation(MachineBasicBlock *MBB) {
}

void EVMAssembly::appendInstruction(MachineInstr *MI) {
#ifndef NDEBUG
unsigned Opc = MI->getOpcode();
assert(Opc != EVM::JUMP && Opc != EVM::JUMPI && Opc != EVM::ARGUMENT &&
Opc != EVM::RET && Opc != EVM::CONST_I256 && Opc != EVM::COPY_I256 &&
Opc != EVM::FCALL);
#endif // NDEBUG

auto Ret = AssemblyInstrs.insert(MI);
[[maybe_unused]] auto Ret = AssemblyInstrs.insert(MI);
assert(Ret.second);
int StackAdj = (2 * static_cast<int>(MI->getNumExplicitDefs())) -
static_cast<int>(MI->getNumExplicitOperands());
Expand All @@ -69,7 +69,7 @@ void EVMAssembly::appendSWAPInstruction(unsigned Depth) {
unsigned Opc = EVM::getSWAPOpcode(Depth);
CurMIIt = BuildMI(*CurMBB, CurMIIt, DebugLoc(), TII->get(Opc));
AssemblyInstrs.insert(&*CurMIIt);
dumpInst(&*CurMIIt);
LLVM_DEBUG(dumpInst(&*CurMIIt));
CurMIIt = std::next(CurMIIt);
}

Expand Down
17 changes: 8 additions & 9 deletions llvm/lib/Target/EVM/EVMAssembly.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,10 @@
//
//===----------------------------------------------------------------------===//
//
// This file implements the EVMAssembly class that generates machine IR
// with all the required stack manipulation instructions.
// Resulting machine instructions still have explicit operands, but some of the
// auxiliary instructions (ARGUMENT, RET, EVM::CONST_I256, COPY_I256
// FCALLARGUMENT) are removed after this step, beaking use-def chains. So, the
// resulting Machine IR breaks the MachineVerifier checks.
// This file creates Machine IR in stackified form. It provides different
// callbacks when the EVMOptimizedCodeTransform needs to emit operation,
// stack manipulation instruction, and so on. It the end, it walks over MIR
// instructions removing register operands.
//
//===----------------------------------------------------------------------===//

Expand Down Expand Up @@ -46,7 +44,8 @@ class EVMAssembly {
: MF(MF), TII(TII) {}

// Retrieve the current height of the stack.
// This does not have to be zero at the beginning.
// This does not have to be zero at the MF beginning because of
// possible arguments.
int getStackHeight() const;

void setStackHeight(int Height);
Expand Down Expand Up @@ -84,8 +83,8 @@ class EVMAssembly {

MCSymbol *createFuncRetSymbol();

// Removes unused codegen-only instructions and
// stackifies remaining ones.
// Erases unused codegen-only instructions and removes register operands
// of the remaining ones.
void finalize();

private:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,25 @@
//===----- EVMStackifyEF.cpp - Split Critical Edges ------*- C++ -*--===//
//===----- EVMBPStackification.cpp - BP stackification ---------*- C++ -*--===//
//
// 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 performs spliting of critical edges.
// This file implements backward propagation (BP) stackification.
// Original idea was taken from the Ethereum's compiler (solc) stackification
// algorithm.
// The algorithm is broken into following components:
// - CFG (Control Flow Graph) and CFG builder. Stackification CFG has similar
// structure to LLVM CFG one, but employs wider notion of instruction.
// - Stack layout generator. Contains information about the stack layout at
// entry and exit of each CFG::BasicBlock. It also contains input/output
// stack layout for each operation.
// - Code transformation into stakified form. This component uses both CFG
// and the stack layout information to get stackified LLVM MIR.
// - Stack shuffler. Finds optimal (locally) transformation between two stack
// layouts using three primitives: POP, PUSHn, DUPn. The stack shuffler
// is used by the components above.
//
//===----------------------------------------------------------------------===//

Expand All @@ -28,11 +41,11 @@ using namespace llvm;
#define DEBUG_TYPE "evm-ethereum-stackify"

namespace {
class EVMStackifyEF final : public MachineFunctionPass {
class EVMBPStackification final : public MachineFunctionPass {
public:
static char ID; // Pass identification, replacement for typeid

EVMStackifyEF() : MachineFunctionPass(ID) {}
EVMBPStackification() : MachineFunctionPass(ID) {}

private:
StringRef getPassName() const override {
Expand All @@ -54,19 +67,21 @@ class EVMStackifyEF final : public MachineFunctionPass {
};
} // end anonymous namespace

char EVMStackifyEF::ID = 0;
char EVMBPStackification::ID = 0;

INITIALIZE_PASS_BEGIN(EVMStackifyEF, DEBUG_TYPE, "Ethereum stackification",
false, false)
INITIALIZE_PASS_BEGIN(EVMBPStackification, DEBUG_TYPE,
"Backward propagation stackification", false, false)
INITIALIZE_PASS_DEPENDENCY(MachineLoopInfo)
INITIALIZE_PASS_END(EVMStackifyEF, DEBUG_TYPE, "Ethereum stackification", false,
false)
INITIALIZE_PASS_END(EVMBPStackification, DEBUG_TYPE,
"Backward propagation stackification", false, false)

FunctionPass *llvm::createEVMStackifyEF() { return new EVMStackifyEF(); }
FunctionPass *llvm::createEVMBPStackification() {
return new EVMBPStackification();
}

bool EVMStackifyEF::runOnMachineFunction(MachineFunction &MF) {
bool EVMBPStackification::runOnMachineFunction(MachineFunction &MF) {
LLVM_DEBUG({
dbgs() << "********** Ethereum stackification **********\n"
dbgs() << "********** Backward propagation stackification **********\n"
<< "********** Function: " << MF.getName() << '\n';
});

Expand All @@ -78,7 +93,7 @@ bool EVMStackifyEF::runOnMachineFunction(MachineFunction &MF) {
// We don't preserve SSA form.
MRI.leaveSSA();

assert(MRI.tracksLiveness() && "Stackify expects liveness");
assert(MRI.tracksLiveness() && "Stackification expects liveness");

EVMAssembly Assembly(&MF, TII);
EVMOptimizedCodeTransform::run(Assembly, MF, LIS, MLI);
Expand Down
24 changes: 14 additions & 10 deletions llvm/lib/Target/EVM/EVMControlFlowGraph.h
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
//===----- EVMControlFlowGraph.h - CFG for stackification -------*- C++ -*-===//
//===----- EVMControlFlowGraph.h - CFG for BP stackification ----*- C++ -*-===//
//
// 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 Control Flow Graph used for the stackification algorithm.
// This file defines Control Flow Graph used for the backward propagation
// stackification algorithm.
//
//===----------------------------------------------------------------------===//

Expand All @@ -31,7 +32,7 @@ class MachineBasicBlock;
class MachineInstr;
/// The following structs describe different kinds of stack slots.
/// Each stack slot is equality- and less-than-comparable and
/// specifies an attribute ``canBeFreelyGenerated`` that is true,
/// specifies an attribute 'canBeFreelyGenerated' that is true,
/// if a slot of this kind always has a known value at compile time and
/// therefore can safely be removed from the stack at any time and then
/// regenerated later.
Expand All @@ -53,8 +54,8 @@ struct FunctionCallReturnLabelSlot {

/// The return jump target of a function while generating the code of the
/// function body. I.e. the caller of a function pushes a
/// ``FunctionCallReturnLabelSlot`` (see above) before jumping to the function
/// and this very slot is viewed as ``FunctionReturnLabelSlot`` inside the
/// 'FunctionCallReturnLabelSlot' (see above) before jumping to the function
/// and this very slot is viewed as 'FunctionReturnLabelSlot' inside the
/// function body and jumped to when returning from the function.
struct FunctionReturnLabelSlot {
const MachineFunction *MF = nullptr;
Expand Down Expand Up @@ -99,7 +100,7 @@ struct LiteralSlot {
bool operator<(LiteralSlot const &Rhs) const { return Value.ult(Rhs.Value); }
};

/// A slot containing a Symbol.
/// A slot containing a MCSymbol.
struct SymbolSlot {
MCSymbol *Symbol;
static constexpr bool canBeFreelyGenerated = true;
Expand Down Expand Up @@ -156,7 +157,7 @@ inline bool canBeFreelyGenerated(StackSlot const &Slot) {
Slot);
}

/// Control flow graph consisting of ``CFG::BasicBlock``s connected by control
/// Control flow graph consisting of 'CFG::BasicBlock`s' connected by control
/// flow.
struct CFG {
explicit CFG() {}
Expand All @@ -168,6 +169,9 @@ struct CFG {

struct BuiltinCall {
MachineInstr *Builtin = nullptr;
// True if this instruction has commutable operands. In EVM ISA
// commutable operands always take top two stack slots.
bool IsCommutable = false;
bool TerminatesOrReverts = false;
};

Expand All @@ -179,8 +183,8 @@ struct CFG {
};

struct Assignment {
/// The variables being assigned to also occur as ``output`` in the
/// ``Operation`` containing the assignment, but are also stored here for
/// The variables being assigned to also occur as 'Output' in the
/// 'Operation' containing the assignment, but are also stored here for
/// convenience.
std::vector<VariableSlot> Variables;
};
Expand All @@ -194,7 +198,7 @@ struct CFG {
};

struct FunctionInfo;
/// A basic control flow block containing ``Operation``s acting on the stack.
/// A basic control flow block containing 'Operation`s' acting on the stack.
/// Maintains a list of entry blocks and a typed exit.
struct BasicBlock {
struct InvalidExit {};
Expand Down
Loading

0 comments on commit 38c8fbd

Please sign in to comment.