Skip to content

Commit ba4aae2

Browse files
committed
[EVM] Improve code generation for conditional jumps
The patch introduces a few SelectionDAG patterns to improve codegen for the `br (brcond (setcc))` case. Additionally, due to the late expansion of JUMP_UNLESS, the patch introduces a peephole pass that optimizes JUMPI predicates: * `ISZERO ISZERO` is folded to nothing * `EQ ISZERO` is folded to `SUB` * `SUB ISZERO` is folded to `EQ`
1 parent 41a3e45 commit ba4aae2

File tree

11 files changed

+209
-21
lines changed

11 files changed

+209
-21
lines changed

llvm/lib/Target/EVM/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ add_llvm_target(EVMCodeGen
3838
EVMMarkRecursiveFunctions.cpp
3939
EVMMCInstLower.cpp
4040
EVMOptimizeLiveIntervals.cpp
41+
EVMPeephole.cpp
4142
EVMRegColoring.cpp
4243
EVMRegisterInfo.cpp
4344
EVMSHA3ConstFolding.cpp

llvm/lib/Target/EVM/EVM.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ FunctionPass *createEVMSplitCriticalEdges();
6868
FunctionPass *createEVMStackify();
6969
FunctionPass *createEVMBPStackification();
7070
FunctionPass *createEVMLowerJumpUnless();
71+
FunctionPass *createEVMPeepholePass();
7172
ModulePass *createEVMFinalizeStackFrames();
7273
ModulePass *createEVMMarkRecursiveFunctionsPass();
7374
ModulePass *createEVMConstantUnfolding();
@@ -91,6 +92,7 @@ void initializeEVMLowerJumpUnlessPass(PassRegistry &);
9192
void initializeEVMFinalizeStackFramesPass(PassRegistry &);
9293
void initializeEVMMarkRecursiveFunctionsPass(PassRegistry &);
9394
void initializeEVMConstantUnfoldingPass(PassRegistry &);
95+
void initializeEVMPeepholePass(PassRegistry &);
9496

9597
struct EVMLinkRuntimePass : PassInfoMixin<EVMLinkRuntimePass> {
9698
EVMLinkRuntimePass() = default;

llvm/lib/Target/EVM/EVMInstrInfo.td

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -430,10 +430,17 @@ let isBarrier = 1 in {
430430
} // isBarrier = 1
431431
} // isBranch = 1, isTerminator = 1
432432

433+
def : Pat<(brcond (setcc GPR:$src, 0, SETNE), bb:$dst),
434+
(JUMPI bb:$dst, GPR:$src)>;
435+
def : Pat<(brcond (setcc GPR:$rs0, GPR:$rs1, SETEQ), bb:$dst),
436+
(JUMPI bb:$dst, (EQ GPR:$rs0, GPR:$rs1))>;
437+
def : Pat<(brcond (setcc GPR:$rs0, GPR:$rs1, SETNE), bb:$dst),
438+
(JUMPI bb:$dst, (SUB GPR:$rs1, GPR:$rs0))>;
439+
433440
def : Pat<(brcond (setcc GPR:$src, 0, SETEQ), bb:$dst),
434441
(JUMP_UNLESS bb:$dst, GPR:$src)>;
435-
def : Pat<(brcond (setcc GPR:$rs0, GPR:$rs1, SETNE), bb:$dst),
436-
(JUMP_UNLESS bb:$dst, (EQ GPR:$rs0, GPR:$rs1))>;
442+
def : Pat<(brcond (setcc GPR:$src, -1, SETGT), bb:$dst),
443+
(JUMP_UNLESS bb:$dst, (LT GPR:$src, (CONST_I256 0)))>;
437444
def : Pat<(brcond (setcc GPR:$rs0, GPR:$rs1, SETGE), bb:$dst),
438445
(JUMP_UNLESS bb:$dst, (LT GPR:$rs0, GPR:$rs1))>;
439446
def : Pat<(brcond (setcc GPR:$rs0, GPR:$rs1, SETLE), bb:$dst),
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// Pre-emission peephole optimizations.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#include "EVM.h"
14+
#include "MCTargetDesc/EVMMCTargetDesc.h"
15+
#include "llvm/CodeGen/MachineBasicBlock.h"
16+
#include "llvm/CodeGen/MachineFunctionPass.h"
17+
#include "llvm/CodeGen/MachineInstr.h"
18+
#include "llvm/CodeGen/MachineInstrBuilder.h"
19+
#include "llvm/CodeGen/TargetInstrInfo.h"
20+
#include "llvm/CodeGen/TargetSubtargetInfo.h"
21+
22+
#define DEBUG_TYPE "evm-peephole"
23+
#define EVM_PEEPHOLE "EVM Peephole"
24+
25+
using namespace llvm;
26+
27+
namespace {
28+
/// Perform foldings on stack-form MIR before emission.
29+
class EVMPeephole final : public MachineFunctionPass {
30+
public:
31+
static char ID;
32+
EVMPeephole() : MachineFunctionPass(ID) {}
33+
34+
StringRef getPassName() const override { return EVM_PEEPHOLE; }
35+
bool runOnMachineFunction(MachineFunction &MF) override;
36+
bool optimizeConditionaJumps(MachineBasicBlock &MBB) const;
37+
};
38+
} // namespace
39+
40+
bool EVMPeephole::runOnMachineFunction(MachineFunction &MF) {
41+
bool Changed = false;
42+
for (MachineBasicBlock &MBB : MF) {
43+
Changed |= optimizeConditionaJumps(MBB);
44+
}
45+
return Changed;
46+
}
47+
48+
static bool isNegatadAndJumpedOn(const MachineBasicBlock &MBB,
49+
MachineBasicBlock::const_iterator I) {
50+
if (I == MBB.end() || I->getOpcode() != EVM::ISZERO_S)
51+
return false;
52+
++I;
53+
if (I == MBB.end())
54+
return false;
55+
if (I->getOpcode() == EVM::PseudoJUMPI)
56+
return true;
57+
if (I->getOpcode() != EVM::PUSH4_S)
58+
return false;
59+
++I;
60+
return I != MBB.end() && I->getOpcode() == EVM::JUMPI;
61+
}
62+
63+
bool EVMPeephole::optimizeConditionaJumps(MachineBasicBlock &MBB) const {
64+
MachineBasicBlock::iterator I = MBB.begin();
65+
const TargetInstrInfo *TII = MBB.getParent()->getSubtarget().getInstrInfo();
66+
67+
while (I != MBB.end()) {
68+
// Fold ISZERO ISZERO to nothing, only if it's a predicate to JUMPI.
69+
if (I->getOpcode() == EVM::ISZERO_S &&
70+
isNegatadAndJumpedOn(MBB, std::next(I))) {
71+
std::next(I)->eraseFromParent();
72+
I->eraseFromParent();
73+
return true;
74+
}
75+
76+
// Fold EQ ISZERO to SUB, only if it's a predicate to JUMPI.
77+
if (I->getOpcode() == EVM::EQ_S &&
78+
isNegatadAndJumpedOn(MBB, std::next(I))) {
79+
I->setDesc(TII->get(EVM::SUB_S));
80+
std::next(I)->eraseFromParent();
81+
return true;
82+
}
83+
84+
// Fold SUB ISZERO to EQ, only if it's a predicate to JUMPI.
85+
if (I->getOpcode() == EVM::SUB_S &&
86+
isNegatadAndJumpedOn(MBB, std::next(I))) {
87+
I->setDesc(TII->get(EVM::EQ_S));
88+
std::next(I)->eraseFromParent();
89+
return true;
90+
}
91+
92+
++I;
93+
}
94+
return false;
95+
}
96+
97+
char EVMPeephole::ID = 0;
98+
99+
INITIALIZE_PASS(EVMPeephole, DEBUG_TYPE, EVM_PEEPHOLE, false, false)
100+
101+
FunctionPass *llvm::createEVMPeepholePass() { return new EVMPeephole(); }

llvm/lib/Target/EVM/EVMTargetMachine.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeEVMTarget() {
5353
initializeEVMLinkRuntimePass(PR);
5454
initializeEVMLowerIntrinsicsPass(PR);
5555
initializeEVMOptimizeLiveIntervalsPass(PR);
56+
initializeEVMPeepholePass(PR);
5657
initializeEVMRegColoringPass(PR);
5758
initializeEVMSingleUseExpressionPass(PR);
5859
initializeEVMSplitCriticalEdgesPass(PR);
@@ -295,6 +296,8 @@ void EVMPassConfig::addPreEmitPass() {
295296
void EVMPassConfig::addPreEmitPass2() {
296297
addPass(createEVMLowerJumpUnless());
297298
addPass(createEVMConstantUnfolding());
299+
if (getOptLevel() != CodeGenOptLevel::None)
300+
addPass(createEVMPeepholePass());
298301
}
299302

300303
TargetPassConfig *EVMTargetMachine::createPassConfig(PassManagerBase &PM) {

llvm/test/CodeGen/EVM/O3-pipeline.ll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ target triple = "evm"
147147
; CHECK-NEXT: EVM Lower jump_unless
148148
; CHECK-NEXT: EVM constant unfolding
149149
; CHECK-NEXT: FunctionPass Manager
150+
; CHECK-NEXT: EVM Peephole
150151
; CHECK-NEXT: Lazy Machine Block Frequency Analysis
151152
; CHECK-NEXT: Machine Optimization Remark Emitter
152153
; CHECK-NEXT: EVM Assembly

llvm/test/CodeGen/EVM/br.ll

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,9 @@ define i256 @diamond(i256 %rs1, i256 %rs2) nounwind {
88
; CHECK-LABEL: diamond:
99
; CHECK: ; %bb.0:
1010
; CHECK-NEXT: JUMPDEST
11-
; CHECK-NEXT: DUP2
12-
; CHECK-NEXT: DUP2
13-
; CHECK-NEXT: EQ
14-
; CHECK-NEXT: ISZERO
11+
; CHECK-NEXT: DUP1
12+
; CHECK-NEXT: DUP3
13+
; CHECK-NEXT: SUB
1514
; CHECK-NEXT: PUSH4 @.BB0_2
1615
; CHECK-NEXT: JUMPI
1716
; CHECK-NEXT: ; %bb.1: ; %true_bb

llvm/test/CodeGen/EVM/branch-folder-after-stackification.ll

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,8 @@ define i256 @test(i256 %arg) {
99
; CHECK: ; %bb.0: ; %entry
1010
; CHECK-NEXT: JUMPDEST
1111
; CHECK-NEXT: PUSH0
12-
; CHECK-NEXT: NOT
1312
; CHECK-NEXT: DUP2
14-
; CHECK-NEXT: SGT
15-
; CHECK-NEXT: ISZERO
13+
; CHECK-NEXT: SLT
1614
; CHECK-NEXT: PUSH4 @.BB0_2
1715
; CHECK-NEXT: JUMPI
1816
; CHECK-NEXT: ; %bb.1:

llvm/test/CodeGen/EVM/brcond.ll

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@ define void @br_eq(i256 %a, i256 %b) {
1212
; CHECK-NEXT: JUMPDEST
1313
; CHECK-NEXT: SWAP2
1414
; CHECK-NEXT: POP
15-
; CHECK-NEXT: EQ
16-
; CHECK-NEXT: ISZERO
15+
; CHECK-NEXT: SUB
1716
; CHECK-NEXT: PUSH4 @.BB0_2
1817
; CHECK-NEXT: JUMPI
1918
; CHECK-NEXT: ; %bb.1: ; %true
@@ -227,9 +226,6 @@ define void @br_eq_0(i256 %a) {
227226
; CHECK-NEXT: JUMPDEST
228227
; CHECK-NEXT: SWAP1
229228
; CHECK-NEXT: POP
230-
; CHECK-NEXT: PUSH0
231-
; CHECK-NEXT: EQ
232-
; CHECK-NEXT: ISZERO
233229
; CHECK-NEXT: PUSH4 @.BB10_2
234230
; CHECK-NEXT: JUMPI
235231
; CHECK-NEXT: ; %bb.1: ; %true
@@ -329,9 +325,6 @@ define void @br_ule_0(i256 %a) {
329325
; CHECK-NEXT: JUMPDEST
330326
; CHECK-NEXT: SWAP1
331327
; CHECK-NEXT: POP
332-
; CHECK-NEXT: PUSH0
333-
; CHECK-NEXT: EQ
334-
; CHECK-NEXT: ISZERO
335328
; CHECK-NEXT: PUSH4 @.BB15_2
336329
; CHECK-NEXT: JUMPI
337330
; CHECK-NEXT: ; %bb.1: ; %true
@@ -392,10 +385,10 @@ define void @br_slt_0(i256 %a) {
392385
; CHECK: ; %bb.0:
393386
; CHECK-NEXT: JUMPDEST
394387
; CHECK-NEXT: PUSH0
395-
; CHECK-NEXT: NOT
396388
; CHECK-NEXT: SWAP2
397389
; CHECK-NEXT: POP
398-
; CHECK-NEXT: SGT
390+
; CHECK-NEXT: SLT
391+
; CHECK-NEXT: ISZERO
399392
; CHECK-NEXT: PUSH4 @.BB18_2
400393
; CHECK-NEXT: JUMPI
401394
; CHECK-NEXT: ; %bb.1: ; %true
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
# RUN: llc -x mir -mtriple=evm-unknown-unknown -run-pass=evm-peephole < %s | FileCheck %s
2+
3+
--- |
4+
target datalayout = "E-p:256:256-i256:256:256-S256-a:256:256"
5+
target triple = "evm-unknown-unknown"
6+
7+
define void @iszero_fallthrough() {
8+
ret void
9+
}
10+
11+
define void @iszero_iszero_fallthrough() {
12+
ret void
13+
}
14+
15+
define void @iszero_iszero_or_fallthrough() {
16+
ret void
17+
}
18+
...
19+
---
20+
name: iszero_fallthrough
21+
liveins:
22+
- { reg: '$arguments', virtual-reg: '' }
23+
- { reg: '$value_stack', virtual-reg: '' }
24+
body: |
25+
bb.0:
26+
successors: %bb.1(0x80000000)
27+
liveins: $arguments, $value_stack
28+
29+
ISZERO_S
30+
31+
bb.1:
32+
successors:
33+
liveins: $value_stack
34+
35+
...
36+
---
37+
name: iszero_iszero_fallthrough
38+
liveins:
39+
- { reg: '$arguments', virtual-reg: '' }
40+
- { reg: '$value_stack', virtual-reg: '' }
41+
body: |
42+
bb.0:
43+
successors: %bb.1(0x80000000)
44+
liveins: $arguments, $value_stack
45+
46+
ISZERO_S
47+
ISZERO_S
48+
49+
bb.1:
50+
successors:
51+
liveins: $value_stack
52+
53+
...
54+
---
55+
name: iszero_iszero_or_fallthrough
56+
liveins:
57+
- { reg: '$arguments', virtual-reg: '' }
58+
- { reg: '$value_stack', virtual-reg: '' }
59+
body: |
60+
bb.0:
61+
successors: %bb.1(0x80000000)
62+
liveins: $arguments, $value_stack
63+
64+
ISZERO_S
65+
ISZERO_S
66+
OR_S
67+
68+
bb.1:
69+
successors:
70+
liveins: $value_stack
71+
72+
...
73+
74+
# CHECK-LABEL: name: iszero_fallthrough
75+
# CHECK: ISZERO_S
76+
#
77+
# CHECK-LABEL: name: iszero_iszero_fallthrough
78+
# CHECK: ISZERO_S
79+
# CHECK-NEXT: ISZERO_S
80+
#
81+
# CHECK-LABEL: name: iszero_iszero_or_fallthrough
82+
# CHECK: ISZERO_S
83+
# CHECK-NEXT: ISZERO_S
84+
# CHECK-NEXT: OR_S
85+

0 commit comments

Comments
 (0)