1/**
2 * Copyright (c) Glow Contributors. See CONTRIBUTORS file.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "glow/LLVMIRCodeGen/LLVMBackend.h"
18#include "glow/LLVMIRCodeGen/LLVMIRGen.h"
19
20#include "llvm/ADT/DenseMap.h"
21#include "llvm/ADT/SmallVector.h"
22#include "llvm/Analysis/BasicAliasAnalysis.h"
23#include "llvm/Analysis/CFLAndersAliasAnalysis.h"
24#include "llvm/Analysis/CFLSteensAliasAnalysis.h"
25#include "llvm/Analysis/GlobalsModRef.h"
26#include "llvm/Analysis/InlineCost.h"
27#include "llvm/Analysis/Passes.h"
28#include "llvm/Analysis/ScopedNoAliasAA.h"
29#include "llvm/Analysis/TargetLibraryInfo.h"
30#include "llvm/Analysis/TargetTransformInfo.h"
31#include "llvm/Analysis/TypeBasedAliasAnalysis.h"
32#include "llvm/IR/Constants.h"
33#include "llvm/IR/DataLayout.h"
34#include "llvm/IR/LegacyPassManager.h"
35#include "llvm/IR/Module.h"
36#include "llvm/IR/Verifier.h"
37#include "llvm/Support/Casting.h"
38#include "llvm/Support/CommandLine.h"
39#include "llvm/Support/ManagedStatic.h"
40#include "llvm/Support/TargetSelect.h"
41#include "llvm/Transforms/IPO/ForceFunctionAttrs.h"
42#include "llvm/Transforms/IPO/FunctionAttrs.h"
43#include "llvm/Transforms/IPO/InferFunctionAttrs.h"
44#include "llvm/Transforms/IPO/Internalize.h"
45#include "llvm/Transforms/Instrumentation.h"
46#include "llvm/Transforms/Scalar.h"
47#include "llvm/Transforms/Scalar/GVN.h"
48#include "llvm/Transforms/Scalar/SimpleLoopUnswitch.h"
49#include "llvm/Transforms/Vectorize.h"
50
51using namespace glow;
52using llvm::dyn_cast;
53using llvm::isa;
54
55bool LLVMIRGen::preserveSymbol(const llvm::GlobalValue &GV) {
56 auto name = GV.getName();
57 // Do not preserve any internal symbols, which typically have no name or
58 // start with libjit_.
59 if (name.empty() || name.startswith("libjit_"))
60 return false;
61 return true;
62}
63
64llvm::Attribute::AttrKind
65LLVMIRGen::getInlinineAttr(const llvm::Function *F) const {
66 return llvm::Attribute::AttrKind::None;
67}
68
69void LLVMIRGen::populatePassManagerBuilderOptions(
70 llvm::PassManagerBuilder &PMB) {
71 PMB.OptLevel = 2;
72 PMB.SizeLevel = 0;
73 PMB.LoopVectorize = true;
74 PMB.SLPVectorize = false;
75 PMB.Inliner = llvm::createFunctionInliningPass();
76}
77
78void LLVMIRGen::updateInlineAttributes(llvm::Module *M) {
79 for (auto &FF : *M) {
80 if (FF.isDeclaration()) {
81 continue;
82 }
83 // Check for no-inline attribute.
84 bool dontInline = FF.hasFnAttribute(llvm::Attribute::AttrKind::NoInline);
85 bool alwaysInline =
86 FF.hasFnAttribute(llvm::Attribute::AttrKind::AlwaysInline);
87 bool optnone = FF.hasFnAttribute(llvm::Attribute::AttrKind::OptimizeNone);
88
89 bool hasOmitFramePointer = FF.hasFnAttribute("omit-frame-pointer");
90 llvm::Attribute omitFramePointerAttr;
91 if (hasOmitFramePointer) {
92 omitFramePointerAttr = FF.getFnAttribute("omit-frame-pointer");
93 }
94
95 bool hasFramePointer = FF.hasFnAttribute("frame-pointer");
96 llvm::Attribute framePointerAttr;
97 if (hasFramePointer) {
98 framePointerAttr = FF.getFnAttribute("frame-pointer");
99 }
100
101 bool hasNoFramePointerElim = FF.hasFnAttribute("no-frame-pointer-elim");
102 llvm::Attribute noFramePointerElimAttr;
103 if (hasNoFramePointerElim) {
104 noFramePointerElimAttr = FF.getFnAttribute("no-frame-pointer-elim");
105 }
106
107 auto inlineAttr = getInlinineAttr(&FF);
108 if (inlineAttr != llvm::Attribute::AttrKind::None) {
109 DCHECK(inlineAttr == llvm::Attribute::AttrKind::AlwaysInline ||
110 inlineAttr == llvm::Attribute::AttrKind::NoInline)
111 << "Unknown inlining attribute returned by getInlinineAttr";
112 dontInline = (inlineAttr == llvm::Attribute::AttrKind::NoInline);
113 }
114 // Replace the target-specific machine code function attributes that were
115 // attached by the frontend. Keep return and parameter attributes, e.g.,
116 // noalias.
117 FF.setAttributes(FF.getAttributes().removeAttributes(
118 M->getContext(), llvm::AttributeList::FunctionIndex));
119 if (hasOmitFramePointer) {
120 FF.addFnAttr("omit-frame-pointer",
121 omitFramePointerAttr.getValueAsString());
122 }
123 if (hasFramePointer) {
124 FF.addFnAttr("frame-pointer", framePointerAttr.getValueAsString());
125 }
126 if (hasNoFramePointerElim) {
127 FF.addFnAttr("no-frame-pointer-elim",
128 noFramePointerElimAttr.getValueAsString());
129 }
130 // Force inline all non-no-inline functions.
131 if (!dontInline || alwaysInline) {
132 FF.addFnAttr(llvm::Attribute::AttrKind::AlwaysInline);
133 continue;
134 }
135 if (dontInline || optnone) {
136 FF.addFnAttr(llvm::Attribute::AttrKind::NoInline);
137 continue;
138 }
139 }
140}
141
142void LLVMIRGen::optimizeLLVMModule(llvm::Module *M, llvm::TargetMachine &TM) {
143 // Make all of the definitions from libjit and unnamed symbols internal and
144 // optimizable. Everything else should be preserved as is.
145 auto preserveSymbolCallback = [&](const llvm::GlobalValue &GV) -> bool {
146 // Do not internalize declarations.
147 if (GV.isDeclaration()) {
148 return true;
149 }
150 return preserveSymbol(GV);
151 };
152
153 // Internalize functions in the module using a backend-specific logic.
154 // Typically only the entry point would be preserved.
155 llvm::internalizeModule(*M, preserveSymbolCallback);
156
157 // Next, we remove all of the 'no-inline' attributes that clang in -O0 adds to
158 // all functions.
159 for (auto &FF : *M) {
160 // For libjit functions that are marked as dllimport or dllexport
161 // This sets them as regular functions.
162 // This allows LLVM to eliminate unused functions,
163 // and speeds up compilation.
164 if (FF.getDLLStorageClass() !=
165 llvm::GlobalValue::DLLStorageClassTypes::DefaultStorageClass) {
166 FF.setLinkage(llvm::GlobalValue::LinkageTypes::InternalLinkage);
167 FF.setDLLStorageClass(llvm::GlobalValue::DefaultStorageClass);
168 }
169
170 // Remove NoInline attribute.
171 FF.removeFnAttr(llvm::Attribute::AttrKind::NoInline);
172
173 // LinkOnce linkage seems to cause problems to OrcJIT on some OS platforms.
174 // In particular, ORCJit doesn't like linkonce_odr linkage which is used for
175 // almost all templatized C++ functions in the LLVM module.
176 if (!FF.isDeclaration() && FF.isLinkOnceLinkage(FF.getLinkage())) {
177 FF.setLinkage(llvm::GlobalValue::LinkageTypes::InternalLinkage);
178 }
179 }
180
181 // Perform specialization of functions for constant arguments before anything
182 // else.
183 performSpecialization();
184
185 // Add instrumentation into the code for better debugging experience.
186 performDebugInstrumentation();
187
188 M->setTargetTriple(TM.getTargetTriple().normalize());
189 M->setDataLayout(TM.createDataLayout());
190
191 // Properly set inline attributes.
192 updateInlineAttributes(M);
193
194 // Add no-frame-pointer-elim=true attribute. It helps with profiling and
195 // debugging the produced code.
196 for (auto &FF : *M) {
197 if (FF.isDeclaration()) {
198 continue;
199 }
200 if (FF.hasFnAttribute("no-frame-pointer-elim") ||
201 FF.hasFnAttribute("frame-pointer") ||
202 FF.hasFnAttribute("omit-frame-pointer")) {
203 continue;
204 }
205 FF.addFnAttr("no-frame-pointer-elim", "true");
206 }
207
208 // The "main" function is parameterized by the base addresses of memory areas
209 // and it is always invoked from either the "jitmain" function or the AOT
210 // entry point. To enable better LLVM optimizations "main" should always be
211 // inlined.
212 getLLVMFunction()->addFnAttr(llvm::Attribute::AttrKind::AlwaysInline);
213
214 // Add an appropriate TargetLibraryInfo pass for the module's triple.
215 llvm::TargetLibraryInfoImpl TLII(llvm::Triple(M->getTargetTriple()));
216 // Disable optimizations of some builtin functions. They cause issues on some
217 // targets.
218 llvm::LibFunc libFunc;
219 if (TLII.getLibFunc(llvm::StringRef("printf"), libFunc)) {
220 TLII.setUnavailable(libFunc);
221 }
222
223 auto *TLIWP = new llvm::TargetLibraryInfoWrapperPass(TLII);
224
225 llvm::legacy::FunctionPassManager FPM(M);
226 llvm::legacy::PassManager PM;
227 llvm::PassManagerBuilder PMB;
228 populatePassManagerBuilderOptions(PMB);
229
230 PM.add(TLIWP);
231
232 // Add internal analysis passes from the target machine.
233 PM.add(createTargetTransformInfoWrapperPass(TM.getTargetIRAnalysis()));
234 FPM.add(createTargetTransformInfoWrapperPass(TM.getTargetIRAnalysis()));
235
236 PMB.populateFunctionPassManager(FPM);
237 PMB.populateModulePassManager(PM);
238
239 FPM.doInitialization();
240 PM.run(*M);
241 for (auto &FF : *M) {
242 FPM.run(FF);
243 }
244 FPM.doFinalization();
245 PM.run(*M);
246}
247