OptUtils.cpp
5.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
//===- OptUtils.cpp - MLIR Execution Engine optimization pass utilities ---===//
//
// Part of the MLIR 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 implements the utility functions to trigger LLVM optimizations from
// MLIR Execution Engine.
//
//===----------------------------------------------------------------------===//
#include "mlir/ExecutionEngine/OptUtils.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/Analysis/TargetTransformInfo.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/LegacyPassNameParser.h"
#include "llvm/IR/Module.h"
#include "llvm/InitializePasses.h"
#include "llvm/Pass.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/StringSaver.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Transforms/IPO.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
#include <climits>
#include <mutex>
// Run the module and function passes managed by the module manager.
static void runPasses(llvm::legacy::PassManager &modulePM,
llvm::legacy::FunctionPassManager &funcPM,
llvm::Module &m) {
funcPM.doInitialization();
for (auto &func : m) {
funcPM.run(func);
}
funcPM.doFinalization();
modulePM.run(m);
}
// Initialize basic LLVM transformation passes under lock.
void mlir::initializeLLVMPasses() {
static std::mutex mutex;
std::lock_guard<std::mutex> lock(mutex);
auto ®istry = *llvm::PassRegistry::getPassRegistry();
llvm::initializeCore(registry);
llvm::initializeTransformUtils(registry);
llvm::initializeScalarOpts(registry);
llvm::initializeIPO(registry);
llvm::initializeInstCombine(registry);
llvm::initializeAggressiveInstCombine(registry);
llvm::initializeAnalysis(registry);
llvm::initializeVectorization(registry);
}
// Populate pass managers according to the optimization and size levels.
// This behaves similarly to LLVM opt.
static void populatePassManagers(llvm::legacy::PassManager &modulePM,
llvm::legacy::FunctionPassManager &funcPM,
unsigned optLevel, unsigned sizeLevel,
llvm::TargetMachine *targetMachine) {
llvm::PassManagerBuilder builder;
builder.OptLevel = optLevel;
builder.SizeLevel = sizeLevel;
builder.Inliner = llvm::createFunctionInliningPass(
optLevel, sizeLevel, /*DisableInlineHotCallSite=*/false);
builder.LoopVectorize = optLevel > 1 && sizeLevel < 2;
builder.SLPVectorize = optLevel > 1 && sizeLevel < 2;
builder.DisableUnrollLoops = (optLevel == 0);
if (targetMachine) {
// Add pass to initialize TTI for this specific target. Otherwise, TTI will
// be initialized to NoTTIImpl by default.
modulePM.add(createTargetTransformInfoWrapperPass(
targetMachine->getTargetIRAnalysis()));
funcPM.add(createTargetTransformInfoWrapperPass(
targetMachine->getTargetIRAnalysis()));
}
builder.populateModulePassManager(modulePM);
builder.populateFunctionPassManager(funcPM);
}
// Create and return a lambda that uses LLVM pass manager builder to set up
// optimizations based on the given level.
std::function<llvm::Error(llvm::Module *)>
mlir::makeOptimizingTransformer(unsigned optLevel, unsigned sizeLevel,
llvm::TargetMachine *targetMachine) {
return [optLevel, sizeLevel, targetMachine](llvm::Module *m) -> llvm::Error {
llvm::legacy::PassManager modulePM;
llvm::legacy::FunctionPassManager funcPM(m);
populatePassManagers(modulePM, funcPM, optLevel, sizeLevel, targetMachine);
runPasses(modulePM, funcPM, *m);
return llvm::Error::success();
};
}
// Create and return a lambda that is given a set of passes to run, plus an
// optional optimization level to pre-populate the pass manager.
std::function<llvm::Error(llvm::Module *)> mlir::makeLLVMPassesTransformer(
llvm::ArrayRef<const llvm::PassInfo *> llvmPasses,
llvm::Optional<unsigned> mbOptLevel, llvm::TargetMachine *targetMachine,
unsigned optPassesInsertPos) {
return [llvmPasses, mbOptLevel, optPassesInsertPos,
targetMachine](llvm::Module *m) -> llvm::Error {
llvm::legacy::PassManager modulePM;
llvm::legacy::FunctionPassManager funcPM(m);
bool insertOptPasses = mbOptLevel.hasValue();
for (unsigned i = 0, e = llvmPasses.size(); i < e; ++i) {
const auto *passInfo = llvmPasses[i];
if (!passInfo->getNormalCtor())
continue;
if (insertOptPasses && optPassesInsertPos == i) {
populatePassManagers(modulePM, funcPM, mbOptLevel.getValue(), 0,
targetMachine);
insertOptPasses = false;
}
auto *pass = passInfo->createPass();
if (!pass)
return llvm::make_error<llvm::StringError>(
"could not create pass " + passInfo->getPassName(),
llvm::inconvertibleErrorCode());
modulePM.add(pass);
}
if (insertOptPasses)
populatePassManagers(modulePM, funcPM, mbOptLevel.getValue(), 0,
targetMachine);
runPasses(modulePM, funcPM, *m);
return llvm::Error::success();
};
}