Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions llvm/lib/Target/EVM/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -37,18 +37,18 @@ add_llvm_target(EVMCodeGen
EVMMachineFunctionInfo.cpp
EVMMarkRecursiveFunctions.cpp
EVMMCInstLower.cpp
EVMMachineFunctionInfo.cpp
EVMOptimizeLiveIntervals.cpp
EVMPeephole.cpp
EVMRegColoring.cpp
EVMRegisterInfo.cpp
EVMSHA3ConstFolding.cpp
EVMSingleUseExpression.cpp
EVMSplitCriticalEdges.cpp
EVMStackModel.cpp
EVMStackShuffler.cpp
EVMStackSolver.cpp
EVMStackModel.cpp
EVMStackify.cpp
EVMStackifyCodeEmitter.cpp
EVMStackShuffler.cpp
EVMSubtarget.cpp
EVMTargetMachine.cpp
EVMTargetTransformInfo.cpp
Expand All @@ -71,6 +71,8 @@ add_llvm_target(EVMCodeGen
Target
TargetParser
TransformUtils
EVMDesc
EVMInfo

ADD_TO_COMPONENT
EVM
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/Target/EVM/EVM.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ FunctionPass *createEVMSplitCriticalEdges();
FunctionPass *createEVMStackify();
FunctionPass *createEVMBPStackification();
FunctionPass *createEVMLowerJumpUnless();
FunctionPass *createEVMPeepholePass();
ModulePass *createEVMFinalizeStackFrames();
ModulePass *createEVMMarkRecursiveFunctionsPass();
ModulePass *createEVMConstantUnfolding();
Expand All @@ -91,6 +92,7 @@ void initializeEVMLowerJumpUnlessPass(PassRegistry &);
void initializeEVMFinalizeStackFramesPass(PassRegistry &);
void initializeEVMMarkRecursiveFunctionsPass(PassRegistry &);
void initializeEVMConstantUnfoldingPass(PassRegistry &);
void initializeEVMPeepholePass(PassRegistry &);

struct EVMLinkRuntimePass : PassInfoMixin<EVMLinkRuntimePass> {
EVMLinkRuntimePass() = default;
Expand Down
93 changes: 12 additions & 81 deletions llvm/lib/Target/EVM/EVMLowerJumpUnless.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,14 @@
#include "EVMMachineFunctionInfo.h"
#include "EVMSubtarget.h"
#include "MCTargetDesc/EVMMCTargetDesc.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/Support/CodeGen.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetOptions.h"

using namespace llvm;

#define DEBUG_TYPE "evm-lower-jump-unless"
#define EVM_LOWER_JUMP_UNLESS_NAME "EVM Lower jump_unless"

STATISTIC(NumPseudoJumpUnlessFolded, "Number of PseudoJUMP_UNLESS folded");

namespace {
class EVMLowerJumpUnless final : public MachineFunctionPass {
public:
Expand Down Expand Up @@ -57,66 +51,14 @@ FunctionPass *llvm::createEVMLowerJumpUnless() {
return new EVMLowerJumpUnless();
}

// Lower jump_unless into iszero and jumpi instructions. This instruction
// can only be present in non-stackified functions.
static void lowerJumpUnless(MachineInstr &MI, const EVMInstrInfo *TII,
const bool IsStackified, MachineRegisterInfo &MRI) {
assert(!IsStackified && "Found jump_unless in stackified function");
assert(MI.getNumExplicitOperands() == 2 &&
"Unexpected number of operands in jump_unless");
auto NewReg = MRI.createVirtualRegister(&EVM::GPRRegClass);
BuildMI(*MI.getParent(), MI, MI.getDebugLoc(), TII->get(EVM::ISZERO), NewReg)
.add(MI.getOperand(1));
BuildMI(*MI.getParent(), MI, MI.getDebugLoc(), TII->get(EVM::JUMPI))
.add(MI.getOperand(0))
.addReg(NewReg);
}

/// Fold `<PrevMI> ; PseudoJUMP_UNLESS` into `PseudoJUMPI`.
///
/// Supported `PrevMI` patterns and changes:
/// • `ISZERO_S` -> delete `ISZERO_S`
/// • `EQ_S` -> change to `SUB_S`
/// • `SUB_S` -> change to `EQ_S`
///
/// Returns `true` if any fold was performed.
static bool tryFoldJumpUnless(MachineInstr &MI, const EVMInstrInfo *TII) {
auto I = MachineBasicBlock::iterator(&MI);
auto *PrevMI = I == MI.getParent()->begin() ? nullptr : &*std::prev(I);
bool CanFold = PrevMI && (PrevMI->getOpcode() == EVM::ISZERO_S ||
PrevMI->getOpcode() == EVM::EQ_S ||
PrevMI->getOpcode() == EVM::SUB_S);

if (!CanFold)
return false;

++NumPseudoJumpUnlessFolded;

if (PrevMI->getOpcode() == EVM::ISZERO_S)
PrevMI->eraseFromParent();
else if (PrevMI->getOpcode() == EVM::EQ_S)
PrevMI->setDesc(TII->get(EVM::SUB_S));
else if (PrevMI->getOpcode() == EVM::SUB_S)
PrevMI->setDesc(TII->get(EVM::EQ_S));
return true;
}

/// Lower a `PseudoJUMP_UNLESS` to condition-setting + `PseudoJUMPI`.
///
/// If `FoldJumps` is enabled and the local pattern allows it, an
/// optimisation in `tryFoldJumpUnless` removes the explicit `ISZERO_S`.
/// Otherwise the pseudo-op expands to:
/// ISZERO_S
/// PseudoJUMPI
// Lower pseudo jump_unless into iszero and jumpi instructions. This pseudo
// instruction can only be present in stackified functions.
static void lowerPseudoJumpUnless(MachineInstr &MI, const EVMInstrInfo *TII,
const bool IsStackified,
const bool FoldJumps) {
const bool IsStackified) {
assert(IsStackified && "Found pseudo jump_unless in non-stackified function");
assert(MI.getNumExplicitOperands() == 1 &&
"Unexpected number of operands in pseudo jump_unless");

if (!FoldJumps || !tryFoldJumpUnless(MI, TII))
BuildMI(*MI.getParent(), MI, MI.getDebugLoc(), TII->get(EVM::ISZERO_S));
BuildMI(*MI.getParent(), MI, MI.getDebugLoc(), TII->get(EVM::ISZERO_S));
BuildMI(*MI.getParent(), MI, MI.getDebugLoc(), TII->get(EVM::PseudoJUMPI))
.add(MI.getOperand(0));
}
Expand All @@ -127,32 +69,21 @@ bool EVMLowerJumpUnless::runOnMachineFunction(MachineFunction &MF) {
<< "********** Function: " << MF.getName() << '\n';
});

CodeGenOptLevel OptLevel = MF.getTarget().getOptLevel();
MachineRegisterInfo &MRI = MF.getRegInfo();
const auto *TII = MF.getSubtarget<EVMSubtarget>().getInstrInfo();
const bool IsStackified =
MF.getInfo<EVMMachineFunctionInfo>()->getIsStackified();

bool Changed = false;
for (MachineBasicBlock &MBB : MF) {
auto TermIt = MBB.getFirstInstrTerminator();
if (TermIt == MBB.end())
continue;

switch (TermIt->getOpcode()) {
case EVM::PseudoJUMP_UNLESS:
lowerPseudoJumpUnless(*TermIt, TII, IsStackified,
OptLevel != CodeGenOptLevel::None);
break;
case EVM::JUMP_UNLESS:
lowerJumpUnless(*TermIt, TII, IsStackified, MRI);
break;
default:
continue;
for (auto &MI : make_early_inc_range(MBB)) {
if (MI.getOpcode() == EVM::PseudoJUMP_UNLESS)
lowerPseudoJumpUnless(MI, TII, IsStackified);
else
continue;

MI.eraseFromParent();
Changed = true;
}

TermIt->eraseFromParent();
Changed = true;
}
return Changed;
}
100 changes: 100 additions & 0 deletions llvm/lib/Target/EVM/EVMPeephole.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@

//
// 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
//
//===----------------------------------------------------------------------===//
//
// Pre-emission peephole optimizations.
//
//===----------------------------------------------------------------------===//

#include "EVM.h"
#include "MCTargetDesc/EVMMCTargetDesc.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/TargetInstrInfo.h"
#include "llvm/CodeGen/TargetSubtargetInfo.h"

#define DEBUG_TYPE "evm-peephole"
#define EVM_PEEPHOLE "EVM Peephole"

using namespace llvm;

namespace {
/// Perform foldings on stack-form MIR before emission.
class EVMPeephole final : public MachineFunctionPass {
public:
static char ID;
EVMPeephole() : MachineFunctionPass(ID) {}

StringRef getPassName() const override { return EVM_PEEPHOLE; }
bool runOnMachineFunction(MachineFunction &MF) override;
bool optimizeConditionaJumps(MachineBasicBlock &MBB) const;
};
} // namespace

bool EVMPeephole::runOnMachineFunction(MachineFunction &MF) {
bool Changed = false;
for (MachineBasicBlock &MBB : MF) {
Changed |= optimizeConditionaJumps(MBB);
}
return Changed;
}

static bool isNegatedAndJumpedOn(const MachineBasicBlock &MBB,
MachineBasicBlock::const_iterator I) {
if (I == MBB.end() || I->getOpcode() != EVM::ISZERO_S)
return false;
++I;
// When a conditional jump’s predicate is a (possibly nested) bitwise `or`,
// both operands are eligible for folding. Currently we only fold the operand
// computed last.
// TODO: #887 Apply folding to all operands.
while (I != MBB.end() && I->getOpcode() == EVM::OR_S)
++I;
return I != MBB.end() && I->getOpcode() == EVM::PseudoJUMPI;
}

bool EVMPeephole::optimizeConditionaJumps(MachineBasicBlock &MBB) const {
MachineBasicBlock::iterator I = MBB.begin();
const TargetInstrInfo *TII = MBB.getParent()->getSubtarget().getInstrInfo();

while (I != MBB.end()) {
// Fold ISZERO ISZERO to nothing, only if it's a predicate to JUMPI.
if (I->getOpcode() == EVM::ISZERO_S &&
isNegatedAndJumpedOn(MBB, std::next(I))) {
std::next(I)->eraseFromParent();
I->eraseFromParent();
return true;
}

// Fold EQ ISZERO to SUB, only if it's a predicate to JUMPI.
if (I->getOpcode() == EVM::EQ_S &&
isNegatedAndJumpedOn(MBB, std::next(I))) {
I->setDesc(TII->get(EVM::SUB_S));
std::next(I)->eraseFromParent();
return true;
}

// Fold SUB ISZERO to EQ, only if it's a predicate to JUMPI.
if (I->getOpcode() == EVM::SUB_S &&
isNegatedAndJumpedOn(MBB, std::next(I))) {
I->setDesc(TII->get(EVM::EQ_S));
std::next(I)->eraseFromParent();
return true;
}

++I;
}
return false;
}

char EVMPeephole::ID = 0;

INITIALIZE_PASS(EVMPeephole, DEBUG_TYPE, EVM_PEEPHOLE, false, false)

FunctionPass *llvm::createEVMPeepholePass() { return new EVMPeephole(); }
9 changes: 4 additions & 5 deletions llvm/lib/Target/EVM/EVMTargetMachine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,15 +48,12 @@ extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeEVMTarget() {
// Register the target.
const RegisterTargetMachine<EVMTargetMachine> X(getTheEVMTarget());
auto &PR = *PassRegistry::getPassRegistry();
initializeEVMAAWrapperPassPass(PR);
initializeEVMAllocaHoistingPass(PR);
initializeEVMBPStackificationPass(PR);
initializeEVMCodegenPreparePass(PR);
initializeEVMExternalAAWrapperPass(PR);
initializeEVMAllocaHoistingPass(PR);
initializeEVMLinkRuntimePass(PR);
initializeEVMLowerIntrinsicsPass(PR);
initializeEVMLowerJumpUnlessPass(PR);
initializeEVMOptimizeLiveIntervalsPass(PR);
initializeEVMPeepholePass(PR);
initializeEVMRegColoringPass(PR);
initializeEVMSingleUseExpressionPass(PR);
initializeEVMSplitCriticalEdgesPass(PR);
Expand Down Expand Up @@ -299,6 +296,8 @@ void EVMPassConfig::addPreEmitPass() {
void EVMPassConfig::addPreEmitPass2() {
addPass(createEVMLowerJumpUnless());
addPass(createEVMConstantUnfolding());
if (getOptLevel() != CodeGenOptLevel::None)
addPass(createEVMPeepholePass());
}

TargetPassConfig *EVMTargetMachine::createPassConfig(PassManagerBase &PM) {
Expand Down
86 changes: 86 additions & 0 deletions llvm/test/CodeGen/EVM/O0-pipeline.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
; RUN: llc -O0 -debug-pass=Structure < %s -o /dev/null 2>&1 | FileCheck %s
target triple = "evm"

; REQUIRES: asserts

; CHECK-LABEL: Pass Arguments:
; CHECK-NEXT: Target Library Information
; CHECK-NEXT: Target Pass Configuration
; CHECK-NEXT: Machine Module Information
; CHECK-NEXT: Target Transform Information
; CHECK-NEXT: Create Garbage Collector Module Metadata
; CHECK-NEXT: Assumption Cache Tracker
; CHECK-NEXT: Profile summary info
; CHECK-NEXT: Machine Branch Probability Analysis
; CHECK-NEXT: ModulePass Manager
; CHECK-NEXT: Pre-ISel Intrinsic Lowering
; CHECK-NEXT: EVM Lower Intrinsics
; CHECK-NEXT: FunctionPass Manager
; CHECK-NEXT: Module Verifier
; CHECK-NEXT: Lower Garbage Collection Instructions
; CHECK-NEXT: Shadow Stack GC Lowering
; CHECK-NEXT: Lower constant intrinsics
; CHECK-NEXT: Remove unreachable blocks from the CFG
; CHECK-NEXT: Expand vector predication intrinsics
; CHECK-NEXT: Instrument function entry/exit with calls to e.g. mcount() (post inlining)
; CHECK-NEXT: Scalarize Masked Memory Intrinsics
; CHECK-NEXT: Expand reduction intrinsics
; CHECK-NEXT: Final transformations before code generation
; CHECK-NEXT: Lower invoke and unwind, for unwindless code generators
; CHECK-NEXT: Remove unreachable blocks from the CFG
; CHECK-NEXT: CallGraph Construction
; CHECK-NEXT: EVM mark recursive functions
; CHECK-NEXT: FunctionPass Manager
; CHECK-NEXT: Prepare callbr
; CHECK-NEXT: Safe Stack instrumentation pass
; CHECK-NEXT: Insert stack protectors
; CHECK-NEXT: Module Verifier
; CHECK-NEXT: Assignment Tracking Analysis
; CHECK-NEXT: Unnamed pass: implement Pass::getPassName()
; CHECK-NEXT: EVM Argument Move
; CHECK-NEXT: Finalize ISel and expand pseudo-instructions
; CHECK-NEXT: Local Stack Slot Allocation
; CHECK-NEXT: Eliminate PHI nodes for register allocation
; CHECK-NEXT: Two-Address instruction pass
; CHECK-NEXT: Remove Redundant DEBUG_VALUE analysis
; CHECK-NEXT: Fixup Statepoint Caller Saved
; CHECK-NEXT: Lazy Machine Block Frequency Analysis
; CHECK-NEXT: Machine Optimization Remark Emitter
; CHECK-NEXT: Prologue/Epilogue Insertion & Frame Finalization
; CHECK-NEXT: Post-RA pseudo instruction expansion pass
; CHECK-NEXT: Insert fentry calls
; CHECK-NEXT: Insert XRay ops
; CHECK-NEXT: EVM split critical edges
; CHECK-NEXT: MachineDominator Tree Construction
; CHECK-NEXT: Slot index numbering
; CHECK-NEXT: Live Interval Analysis
; CHECK-NEXT: EVM Optimize Live Intervals
; CHECK-NEXT: EVM Single use expressions
; CHECK-NEXT: Slot index numbering
; CHECK-NEXT: Live Interval Analysis
; CHECK-NEXT: Machine Natural Loop Construction
; CHECK-NEXT: Virtual Register Map
; CHECK-NEXT: Live Stack Slot Analysis
; CHECK-NEXT: Machine Block Frequency Analysis
; CHECK-NEXT: EVM backward propagation stackification
; CHECK-NEXT: Stack Slot Coloring
; CHECK-NEXT: EVM finalize stack frames
; CHECK-NEXT: FunctionPass Manager
; CHECK-NEXT: Machine Sanitizer Binary Metadata
; CHECK-NEXT: Lazy Machine Block Frequency Analysis
; CHECK-NEXT: Machine Optimization Remark Emitter
; CHECK-NEXT: Stack Frame Layout Analysis
; CHECK-NEXT: EVM Lower jump_unless
; CHECK-NEXT: EVM constant unfolding
; CHECK-NEXT: FunctionPass Manager
; CHECK-NEXT: Lazy Machine Block Frequency Analysis
; CHECK-NEXT: Machine Optimization Remark Emitter
; CHECK-NEXT: EVM Assembly
; CHECK-NEXT: Free MachineFunction

define void @f() {
ret void
}
;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
; CHECK: {{.*}}
Loading
Loading