Skip to content

Commit 02077da

Browse files
Alexey Zhikhartsevdancgr
Alexey Zhikhartsev
authored andcommitted
Add jump-threading optimization for deterministic finite automata
The current JumpThreading pass does not jump thread loops since it can result in irreducible control flow that harms other optimizations. This prevents switch statements inside a loop from being optimized to use unconditional branches. This code pattern occurs in the core_state_transition function of Coremark. The state machine can be implemented manually with goto statements resulting in a large runtime improvement, and this transform makes the switch implementation match the goto version in performance. This patch specifically targets switch statements inside a loop that have the opportunity to be threaded. Once it identifies an opportunity, it creates new paths that branch directly to the correct code block. For example, the left CFG could be transformed to the right CFG: ``` sw.bb sw.bb / | \ / | \ case1 case2 case3 case1 case2 case3 \ | / / | \ latch.bb latch.2 latch.3 latch.1 br sw.bb / | \ sw.bb.2 sw.bb.3 sw.bb.1 br case2 br case3 br case1 ``` Co-author: Justin Kreiner @jkreiner Co-author: Ehsan Amiri @amehsan Reviewed By: SjoerdMeijer Differential Revision: https://reviews.llvm.org/D99205
1 parent 8e8701a commit 02077da

16 files changed

+2395
-0
lines changed

llvm/include/llvm/InitializePasses.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ void initializeCrossDSOCFIPass(PassRegistry&);
124124
void initializeDAEPass(PassRegistry&);
125125
void initializeDAHPass(PassRegistry&);
126126
void initializeDCELegacyPassPass(PassRegistry&);
127+
void initializeDFAJumpThreadingLegacyPassPass(PassRegistry &);
127128
void initializeDSELegacyPassPass(PassRegistry&);
128129
void initializeDataFlowSanitizerLegacyPassPass(PassRegistry &);
129130
void initializeDeadMachineInstructionElimPass(PassRegistry&);

llvm/include/llvm/LinkAllPasses.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ namespace {
174174
(void) llvm::createStripDeadPrototypesPass();
175175
(void) llvm::createTailCallEliminationPass();
176176
(void) llvm::createJumpThreadingPass();
177+
(void) llvm::createDFAJumpThreadingPass();
177178
(void) llvm::createUnifyFunctionExitNodesPass();
178179
(void) llvm::createInstCountPass();
179180
(void) llvm::createConstantHoistingPass();

llvm/include/llvm/Transforms/Scalar.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,14 @@ FunctionPass *createReassociatePass();
253253
FunctionPass *createJumpThreadingPass(bool FreezeSelectCond = false,
254254
int Threshold = -1);
255255

256+
//===----------------------------------------------------------------------===//
257+
//
258+
// DFAJumpThreading - When a switch statement inside a loop is used to
259+
// implement a deterministic finite automata we can jump thread the switch
260+
// statement reducing number of conditional jumps.
261+
//
262+
FunctionPass *createDFAJumpThreadingPass();
263+
256264
//===----------------------------------------------------------------------===//
257265
//
258266
// CFGSimplification - Merge basic blocks, eliminate unreachable blocks,
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//===- DFAJumpThreading.h - Threads a switch statement inside a loop ------===//
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+
// This file provides the interface for the DFAJumpThreading pass.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef LLVM_TRANSFORMS_SCALAR_DFAJUMPTHREADING_H
14+
#define LLVM_TRANSFORMS_SCALAR_DFAJUMPTHREADING_H
15+
16+
#include "llvm/IR/Function.h"
17+
#include "llvm/IR/PassManager.h"
18+
19+
namespace llvm {
20+
21+
struct DFAJumpThreadingPass : PassInfoMixin<DFAJumpThreadingPass> {
22+
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
23+
};
24+
25+
} // end namespace llvm
26+
27+
#endif // LLVM_TRANSFORMS_SCALAR_DFAJUMPTHREADING_H

llvm/lib/Passes/PassBuilder.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@
145145
#include "llvm/Transforms/Scalar/ConstraintElimination.h"
146146
#include "llvm/Transforms/Scalar/CorrelatedValuePropagation.h"
147147
#include "llvm/Transforms/Scalar/DCE.h"
148+
#include "llvm/Transforms/Scalar/DFAJumpThreading.h"
148149
#include "llvm/Transforms/Scalar/DeadStoreElimination.h"
149150
#include "llvm/Transforms/Scalar/DivRemPairs.h"
150151
#include "llvm/Transforms/Scalar/EarlyCSE.h"
@@ -302,6 +303,7 @@ extern cl::opt<bool> EnableCHR;
302303
extern cl::opt<bool> EnableLoopInterchange;
303304
extern cl::opt<bool> EnableUnrollAndJam;
304305
extern cl::opt<bool> EnableLoopFlatten;
306+
extern cl::opt<bool> EnableDFAJumpThreading;
305307
extern cl::opt<bool> RunNewGVN;
306308
extern cl::opt<bool> RunPartialInlining;
307309
extern cl::opt<bool> ExtraVectorizerPasses;
@@ -829,6 +831,9 @@ PassBuilder::buildFunctionSimplificationPipeline(OptimizationLevel Level,
829831

830832
// Re-consider control flow based optimizations after redundancy elimination,
831833
// redo DCE, etc.
834+
if (EnableDFAJumpThreading && Level.getSizeLevel() == 0)
835+
FPM.addPass(DFAJumpThreadingPass());
836+
832837
FPM.addPass(JumpThreadingPass());
833838
FPM.addPass(CorrelatedValuePropagationPass());
834839

llvm/lib/Passes/PassRegistry.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,7 @@ FUNCTION_PASS("coro-elide", CoroElidePass())
212212
FUNCTION_PASS("coro-cleanup", CoroCleanupPass())
213213
FUNCTION_PASS("correlated-propagation", CorrelatedValuePropagationPass())
214214
FUNCTION_PASS("dce", DCEPass())
215+
FUNCTION_PASS("dfa-jump-threading", DFAJumpThreadingPass())
215216
FUNCTION_PASS("div-rem-pairs", DivRemPairsPass())
216217
FUNCTION_PASS("dse", DSEPass())
217218
FUNCTION_PASS("dot-cfg", CFGPrinterPass())

llvm/lib/Transforms/IPO/PassManagerBuilder.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,10 @@ cl::opt<bool> EnableLoopFlatten("enable-loop-flatten", cl::init(false),
9999
cl::Hidden,
100100
cl::desc("Enable the LoopFlatten Pass"));
101101

102+
cl::opt<bool> EnableDFAJumpThreading("enable-dfa-jump-thread",
103+
cl::desc("Enable DFA jump threading."),
104+
cl::init(false), cl::Hidden);
105+
102106
static cl::opt<bool>
103107
EnablePrepareForThinLTO("prepare-for-thinlto", cl::init(false), cl::Hidden,
104108
cl::desc("Enable preparation for ThinLTO."));
@@ -500,6 +504,9 @@ void PassManagerBuilder::addFunctionSimplificationPasses(
500504
MPM.add(createInstructionCombiningPass());
501505
addExtensionsToPM(EP_Peephole, MPM);
502506
if (OptLevel > 1) {
507+
if (EnableDFAJumpThreading && SizeLevel == 0)
508+
MPM.add(createDFAJumpThreadingPass());
509+
503510
MPM.add(createJumpThreadingPass()); // Thread jumps
504511
MPM.add(createCorrelatedValuePropagationPass());
505512
}

llvm/lib/Transforms/Scalar/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ add_llvm_component_library(LLVMScalarOpts
99
CorrelatedValuePropagation.cpp
1010
DCE.cpp
1111
DeadStoreElimination.cpp
12+
DFAJumpThreading.cpp
1213
DivRemPairs.cpp
1314
EarlyCSE.cpp
1415
FlattenCFGPass.cpp

0 commit comments

Comments
 (0)