blob: 44f23c5abb07a7c985cc1b204b7ac4b28104349a [file] [log] [blame]
Logan1f028c02010-11-27 01:02:48 +08001/*
Stephen Hinesdb169182012-01-05 18:46:36 -08002 * Copyright 2010-2012, The Android Open Source Project
Logan1f028c02010-11-27 01:02:48 +08003 *
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
Jean-Luc Brouilleta2dd52f2017-02-16 20:57:26 -080017#include "Assert.h"
18#include "Log.h"
Jean-Luc Brouilleta2dd52f2017-02-16 20:57:26 -080019#include "RSTransforms.h"
20#include "RSUtils.h"
21#include "rsDefines.h"
22
Zonr Changc72c4dd2012-04-12 15:38:53 +080023#include "bcc/Compiler.h"
Jean-Luc Brouilleta2dd52f2017-02-16 20:57:26 -080024#include "bcc/CompilerConfig.h"
25#include "bcc/Config.h"
Jean-Luc Brouilleta2dd52f2017-02-16 20:57:26 -080026#include "bcc/Script.h"
27#include "bcc/Source.h"
28#include "bcinfo/MetadataExtractor.h"
Logan1f028c02010-11-27 01:02:48 +080029
Zonr Changade92772012-04-13 15:58:24 +080030#include <llvm/Analysis/Passes.h>
Stephen Hines1bd9f622015-03-18 14:53:10 -070031#include <llvm/Analysis/TargetTransformInfo.h>
Zonr Changade92772012-04-13 15:58:24 +080032#include <llvm/CodeGen/RegAllocRegistry.h>
Stephen Hines1bd9f622015-03-18 14:53:10 -070033#include <llvm/IR/LegacyPassManager.h>
Stephen Hinesb730e232013-01-09 15:31:36 -080034#include <llvm/IR/Module.h>
Zonr Changade92772012-04-13 15:58:24 +080035#include <llvm/Support/TargetRegistry.h>
36#include <llvm/Support/raw_ostream.h>
Stephen Hinesb730e232013-01-09 15:31:36 -080037#include <llvm/IR/DataLayout.h>
Stephen Hines57936132014-11-25 17:54:59 -080038#include <llvm/Target/TargetSubtargetInfo.h>
Zonr Changade92772012-04-13 15:58:24 +080039#include <llvm/Target/TargetMachine.h>
40#include <llvm/Transforms/IPO.h>
Tobias Grosser2f6103b2013-07-01 14:01:06 -070041#include <llvm/Transforms/IPO/PassManagerBuilder.h>
Zonr Changade92772012-04-13 15:58:24 +080042#include <llvm/Transforms/Scalar.h>
Tim Murray50f5eb42014-12-09 17:36:24 -080043#include <llvm/Transforms/Vectorize.h>
Logan35849002011-01-15 07:30:43 +080044
Stephen Hines10ee6af2014-09-09 17:28:23 -070045#include <string>
Pirama Arumuga Nainarf5b49a02016-09-15 23:04:25 -070046#include <set>
Stephen Hines10ee6af2014-09-09 17:28:23 -070047
David Gross97e50992017-03-29 20:52:30 +000048namespace {
49
50// Name of metadata node where list of exported types resides
51// (should be synced with slang_rs_metadata.h)
52static const llvm::StringRef ExportedTypeMetadataName = "#rs_export_type";
53
54// Every exported struct type must have the same layout according to
55// the Module's DataLayout that it does according to the
56// TargetMachine's DataLayout -- that is, the front end (represented
57// by Module) and back end (represented by TargetMachine) must agree.
58bool validateLayoutOfExportedTypes(const llvm::Module &module,
59 const llvm::DataLayout &moduleDataLayout,
60 const llvm::DataLayout &targetDataLayout) {
61 if (moduleDataLayout == targetDataLayout)
62 return true;
63
64 const llvm::NamedMDNode *const exportedTypesMD =
65 module.getNamedMetadata(ExportedTypeMetadataName);
66 if (!exportedTypesMD)
67 return true;
68
69 bool allOk = true;
70 for (const llvm::MDNode *const exportedTypeMD : exportedTypesMD->operands()) {
71 bccAssert(exportedTypeMD->getNumOperands() == 1);
72
73 // The name of the type in LLVM is the name of the type in the
74 // metadata with "struct." prepended.
75 std::string exportedTypeName =
76 "struct." +
77 llvm::cast<llvm::MDString>(exportedTypeMD->getOperand(0))->getString().str();
78
79 llvm::StructType *const exportedType = module.getTypeByName(exportedTypeName);
80
81 if (!exportedType) {
82 // presumably this means the type got optimized away
83 continue;
84 }
85
86 const llvm::StructLayout *const moduleStructLayout = moduleDataLayout.getStructLayout(exportedType);
87 const llvm::StructLayout *const targetStructLayout = targetDataLayout.getStructLayout(exportedType);
88
89 if (moduleStructLayout->getSizeInBits() != targetStructLayout->getSizeInBits()) {
90 ALOGE("%s: getSizeInBits() does not match (%u, %u)", exportedTypeName.c_str(),
91 unsigned(moduleStructLayout->getSizeInBits()), unsigned(targetStructLayout->getSizeInBits()));
92 allOk = false;
93 }
94
95 // We deliberately do not check alignment of the struct as a whole -- the explicit padding
96 // from slang doesn't force the alignment.
97
98 for (unsigned elementCount = exportedType->getNumElements(), elementIdx = 0;
99 elementIdx < elementCount; ++elementIdx) {
100 if (moduleStructLayout->getElementOffsetInBits(elementIdx) !=
101 targetStructLayout->getElementOffsetInBits(elementIdx)) {
102 ALOGE("%s: getElementOffsetInBits(%u) does not match (%u, %u)",
103 exportedTypeName.c_str(), elementIdx,
104 unsigned(moduleStructLayout->getElementOffsetInBits(elementIdx)),
105 unsigned(targetStructLayout->getElementOffsetInBits(elementIdx)));
106 allOk = false;
107 }
108 }
109 }
110
111 return allOk;
112}
113
114} // end unnamed namespace
115
Zonr Changade92772012-04-13 15:58:24 +0800116using namespace bcc;
Logan Chienda5e0c32011-06-13 03:47:21 +0800117
Zonr Changade92772012-04-13 15:58:24 +0800118const char *Compiler::GetErrorString(enum ErrorCode pErrCode) {
Tobias Grosser5b7f52a2013-07-23 14:57:00 -0700119 switch (pErrCode) {
120 case kSuccess:
121 return "Successfully compiled.";
122 case kInvalidConfigNoTarget:
Chris Wailes900c6c12014-08-13 15:40:00 -0700123 return "Invalid compiler config supplied (getTarget() returns nullptr.) "
Tobias Grosser5b7f52a2013-07-23 14:57:00 -0700124 "(missing call to CompilerConfig::initialize()?)";
125 case kErrCreateTargetMachine:
126 return "Failed to create llvm::TargetMachine.";
127 case kErrSwitchTargetMachine:
128 return "Failed to switch llvm::TargetMachine.";
129 case kErrNoTargetMachine:
130 return "Failed to compile the script since there's no available "
131 "TargetMachine. (missing call to Compiler::config()?)";
Tobias Grosser5b7f52a2013-07-23 14:57:00 -0700132 case kErrMaterialization:
133 return "Failed to materialize the module.";
134 case kErrInvalidOutputFileState:
135 return "Supplied output file was invalid (in the error state.)";
136 case kErrPrepareOutput:
137 return "Failed to prepare file for output.";
138 case kPrepareCodeGenPass:
139 return "Failed to construct pass list for code-generation.";
Chris Wailesb4447cd2014-08-19 16:22:20 -0700140 case kErrCustomPasses:
141 return "Error occurred while adding custom passes.";
Tobias Grosser5b7f52a2013-07-23 14:57:00 -0700142 case kErrInvalidSource:
143 return "Error loading input bitcode";
Pirama Arumuga Nainar1e0557a2014-12-02 15:02:18 -0800144 case kIllegalGlobalFunction:
145 return "Use of undefined external function";
Pirama Arumuga Nainar9e0f8f02016-04-12 14:04:50 -0700146 case kErrInvalidTargetMachine:
147 return "Invalid/unexpected llvm::TargetMachine.";
David Gross97e50992017-03-29 20:52:30 +0000148 case kErrInvalidLayout:
149 return "Invalid layout (RenderScript ABI and native ABI are incompatible)";
Logan1f028c02010-11-27 01:02:48 +0800150 }
Zonr Changfef9a1b2012-04-13 15:58:24 +0800151
Tobias Grosser5b7f52a2013-07-23 14:57:00 -0700152 // This assert should never be reached as the compiler verifies that the
153 // above switch coveres all enum values.
David Grossc2ca7422015-05-29 14:54:33 -0700154 bccAssert(false && "Unknown error code encountered");
Tobias Grosser5b7f52a2013-07-23 14:57:00 -0700155 return "";
Stephen Hines4a68b1c2012-05-03 12:28:14 -0700156}
157
Zonr Changade92772012-04-13 15:58:24 +0800158//===----------------------------------------------------------------------===//
159// Instance Methods
160//===----------------------------------------------------------------------===//
Chris Wailesb4447cd2014-08-19 16:22:20 -0700161Compiler::Compiler() : mTarget(nullptr), mEnableOpt(true) {
Zonr Changfef9a1b2012-04-13 15:58:24 +0800162 return;
Logan1f028c02010-11-27 01:02:48 +0800163}
164
Chris Wailes900c6c12014-08-13 15:40:00 -0700165Compiler::Compiler(const CompilerConfig &pConfig) : mTarget(nullptr),
Chris Wailesb4447cd2014-08-19 16:22:20 -0700166 mEnableOpt(true) {
Zonr Changade92772012-04-13 15:58:24 +0800167 const std::string &triple = pConfig.getTriple();
168
169 enum ErrorCode err = config(pConfig);
170 if (err != kSuccess) {
171 ALOGE("%s (%s, features: %s)", GetErrorString(err),
172 triple.c_str(), pConfig.getFeatureString().c_str());
173 return;
Stephen Hines4a68b1c2012-05-03 12:28:14 -0700174 }
Zonr Changade92772012-04-13 15:58:24 +0800175
176 return;
Stephen Hines4a68b1c2012-05-03 12:28:14 -0700177}
178
Zonr Changade92772012-04-13 15:58:24 +0800179enum Compiler::ErrorCode Compiler::config(const CompilerConfig &pConfig) {
Chris Wailes900c6c12014-08-13 15:40:00 -0700180 if (pConfig.getTarget() == nullptr) {
Zonr Changade92772012-04-13 15:58:24 +0800181 return kInvalidConfigNoTarget;
Daniel Malea094881f2011-12-14 17:39:16 -0500182 }
183
Zonr Changade92772012-04-13 15:58:24 +0800184 llvm::TargetMachine *new_target =
185 (pConfig.getTarget())->createTargetMachine(pConfig.getTriple(),
186 pConfig.getCPU(),
187 pConfig.getFeatureString(),
188 pConfig.getTargetOptions(),
189 pConfig.getRelocationModel(),
190 pConfig.getCodeModel(),
191 pConfig.getOptimizationLevel());
Daniel Malea094881f2011-12-14 17:39:16 -0500192
Chris Wailes900c6c12014-08-13 15:40:00 -0700193 if (new_target == nullptr) {
194 return ((mTarget != nullptr) ? kErrSwitchTargetMachine :
Chris Wailesb4447cd2014-08-19 16:22:20 -0700195 kErrCreateTargetMachine);
Zonr Changade92772012-04-13 15:58:24 +0800196 }
197
198 // Replace the old TargetMachine.
199 delete mTarget;
200 mTarget = new_target;
201
202 // Adjust register allocation policy according to the optimization level.
Daniel Malea094881f2011-12-14 17:39:16 -0500203 // createFastRegisterAllocator: fast but bad quality
204 // createLinearScanRegisterAllocator: not so fast but good quality
Zonr Changade92772012-04-13 15:58:24 +0800205 if ((pConfig.getOptimizationLevel() == llvm::CodeGenOpt::None)) {
206 llvm::RegisterRegAlloc::setDefault(llvm::createFastRegisterAllocator);
207 } else {
208 llvm::RegisterRegAlloc::setDefault(llvm::createGreedyRegisterAllocator);
Logan1f028c02010-11-27 01:02:48 +0800209 }
210
Zonr Changade92772012-04-13 15:58:24 +0800211 return kSuccess;
Logan Chienda5e0c32011-06-13 03:47:21 +0800212}
213
Zonr Changade92772012-04-13 15:58:24 +0800214Compiler::~Compiler() {
215 delete mTarget;
216}
Stephen Hines4a68b1c2012-05-03 12:28:14 -0700217
Pirama Arumuga Nainar1e0557a2014-12-02 15:02:18 -0800218
David Gross5aefc982015-08-04 10:41:33 -0700219// This function has complete responsibility for creating and executing the
220// exact list of compiler passes.
Jean-Luc Brouillet0a2acce2017-02-17 13:29:47 -0800221enum Compiler::ErrorCode Compiler::runPasses(Script &script,
Pirama Arumuga Nainar98137cc2015-05-06 11:18:56 -0700222 llvm::raw_pwrite_stream &pResult) {
Zonr Changade92772012-04-13 15:58:24 +0800223 // Pass manager for link-time optimization
Dean De Leo1e321862015-11-25 12:35:24 +0000224 llvm::legacy::PassManager transformPasses;
Chris Wailesb4447cd2014-08-19 16:22:20 -0700225
226 // Empty MCContext.
227 llvm::MCContext *mc_context = nullptr;
Stephen Hines4a68b1c2012-05-03 12:28:14 -0700228
Dean De Leo1e321862015-11-25 12:35:24 +0000229 transformPasses.add(
230 createTargetTransformInfoWrapperPass(mTarget->getTargetIRAnalysis()));
Tim Murraybb73b742014-11-04 11:20:10 -0800231
David Gross5aefc982015-08-04 10:41:33 -0700232 // Add some initial custom passes.
Dean De Leo1e321862015-11-25 12:35:24 +0000233 addInvokeHelperPass(transformPasses);
234 addExpandKernelPass(transformPasses);
Jean-Luc Brouillet0a2acce2017-02-17 13:29:47 -0800235 addDebugInfoPass(script, transformPasses);
Dean De Leo1e321862015-11-25 12:35:24 +0000236 addInvariantPass(transformPasses);
Dean De Leo7a9a9672015-11-25 12:51:54 +0000237 if (mTarget->getOptLevel() != llvm::CodeGenOpt::None) {
Jean-Luc Brouillet0a2acce2017-02-17 13:29:47 -0800238 if (!addInternalizeSymbolsPass(script, transformPasses))
Dean De Leo7a9a9672015-11-25 12:51:54 +0000239 return kErrCustomPasses;
240 }
Jean-Luc Brouillet0a2acce2017-02-17 13:29:47 -0800241 addGlobalInfoPass(script, transformPasses);
Daniel Malea094881f2011-12-14 17:39:16 -0500242
Zonr Changade92772012-04-13 15:58:24 +0800243 if (mTarget->getOptLevel() == llvm::CodeGenOpt::None) {
Dean De Leo1e321862015-11-25 12:35:24 +0000244 transformPasses.add(llvm::createGlobalOptimizerPass());
245 transformPasses.add(llvm::createConstantMergePass());
Chris Wailesb4447cd2014-08-19 16:22:20 -0700246
Zonr Changade92772012-04-13 15:58:24 +0800247 } else {
Tobias Grosser2f6103b2013-07-01 14:01:06 -0700248 // FIXME: Figure out which passes should be executed.
249 llvm::PassManagerBuilder Builder;
Stephen Hines57936132014-11-25 17:54:59 -0800250 Builder.Inliner = llvm::createFunctionInliningPass();
Dean De Leo1e321862015-11-25 12:35:24 +0000251 Builder.populateLTOPassManager(transformPasses);
Tim Murray50f5eb42014-12-09 17:36:24 -0800252
Tim Murray7f59b5f2015-02-12 14:38:05 -0800253 /* FIXME: Reenable autovectorization after rebase.
254 bug 19324423
Tim Murray50f5eb42014-12-09 17:36:24 -0800255 // Add vectorization passes after LTO passes are in
256 // additional flag: -unroll-runtime
Dean De Leo1e321862015-11-25 12:35:24 +0000257 transformPasses.add(llvm::createLoopUnrollPass(-1, 16, 0, 1));
Tim Murray50f5eb42014-12-09 17:36:24 -0800258 // Need to pass appropriate flags here: -scalarize-load-store
Dean De Leo1e321862015-11-25 12:35:24 +0000259 transformPasses.add(llvm::createScalarizerPass());
260 transformPasses.add(llvm::createCFGSimplificationPass());
261 transformPasses.add(llvm::createScopedNoAliasAAPass());
262 transformPasses.add(llvm::createScalarEvolutionAliasAnalysisPass());
Tim Murray50f5eb42014-12-09 17:36:24 -0800263 // additional flags: -slp-vectorize-hor -slp-vectorize-hor-store (unnecessary?)
Dean De Leo1e321862015-11-25 12:35:24 +0000264 transformPasses.add(llvm::createSLPVectorizerPass());
265 transformPasses.add(llvm::createDeadCodeEliminationPass());
266 transformPasses.add(llvm::createInstructionCombiningPass());
Tim Murray7f59b5f2015-02-12 14:38:05 -0800267 */
Zonr Changade92772012-04-13 15:58:24 +0800268 }
269
Pirama Arumuga Nainar8c24f8d2015-03-17 13:11:25 -0700270 // These passes have to come after LTO, since we don't want to examine
271 // functions that are never actually called.
Lazar Trsic67c67ce2017-05-16 14:42:37 +0200272 if (llvm::Triple(getTargetMachine().getTargetTriple()).getArch() == llvm::Triple::x86_64 ||
273 llvm::Triple(getTargetMachine().getTargetTriple()).getArch() == llvm::Triple::mips64el)
274 transformPasses.add(createRSX86_64CallConvPass()); // Add pass to correct calling convention for X86-64 and mips64.
Dean De Leo1e321862015-11-25 12:35:24 +0000275 transformPasses.add(createRSIsThreadablePass()); // Add pass to mark script as threadable.
Pirama Arumuga Nainar9fe081b2015-01-27 14:09:19 -0800276
277 // RSEmbedInfoPass needs to come after we have scanned for non-threadable
278 // functions.
Pirama Arumuga Nainar9fe081b2015-01-27 14:09:19 -0800279 if (script.getEmbedInfo())
Dean De Leo1e321862015-11-25 12:35:24 +0000280 transformPasses.add(createRSEmbedInfoPass());
281
282 // Execute the passes.
Jean-Luc Brouillet0a2acce2017-02-17 13:29:47 -0800283 transformPasses.run(script.getSource().getModule());
Dean De Leo1e321862015-11-25 12:35:24 +0000284
285 // Run backend separately to avoid interference between debug metadata
286 // generation and backend initialization.
287 llvm::legacy::PassManager codeGenPasses;
Stephen Hines5db508c2015-01-06 01:42:56 -0800288
Zonr Changade92772012-04-13 15:58:24 +0800289 // Add passes to the pass manager to emit machine code through MC layer.
Dean De Leo1e321862015-11-25 12:35:24 +0000290 if (mTarget->addPassesToEmitMC(codeGenPasses, mc_context, pResult,
Zonr Changade92772012-04-13 15:58:24 +0800291 /* DisableVerify */false)) {
292 return kPrepareCodeGenPass;
293 }
294
Chris Wailesb4447cd2014-08-19 16:22:20 -0700295 // Execute the passes.
Jean-Luc Brouillet0a2acce2017-02-17 13:29:47 -0800296 codeGenPasses.run(script.getSource().getModule());
Zonr Changade92772012-04-13 15:58:24 +0800297
298 return kSuccess;
Logan Chienda5e0c32011-06-13 03:47:21 +0800299}
Logan Chienda5e0c32011-06-13 03:47:21 +0800300
Jean-Luc Brouillet0a2acce2017-02-17 13:29:47 -0800301enum Compiler::ErrorCode Compiler::compile(Script &script,
Pirama Arumuga Nainar98137cc2015-05-06 11:18:56 -0700302 llvm::raw_pwrite_stream &pResult,
Tobias Grosser27fb7ed2013-06-21 18:34:56 -0700303 llvm::raw_ostream *IRStream) {
Jean-Luc Brouillet0a2acce2017-02-17 13:29:47 -0800304 llvm::Module &module = script.getSource().getModule();
Zonr Changade92772012-04-13 15:58:24 +0800305 enum ErrorCode err;
Logan Chienda5e0c32011-06-13 03:47:21 +0800306
Chris Wailes900c6c12014-08-13 15:40:00 -0700307 if (mTarget == nullptr) {
Zonr Changade92772012-04-13 15:58:24 +0800308 return kErrNoTargetMachine;
309 }
310
Stephen Hines10ee6af2014-09-09 17:28:23 -0700311 const std::string &triple = module.getTargetTriple();
Pirama Arumuga Nainar8e908932016-03-06 23:05:45 -0800312 const llvm::DataLayout dl = getTargetMachine().createDataLayout();
313 unsigned int pointerSize = dl.getPointerSizeInBits();
Stephen Hines10ee6af2014-09-09 17:28:23 -0700314 if (triple == "armv7-none-linux-gnueabi") {
315 if (pointerSize != 32) {
316 return kErrInvalidSource;
317 }
318 } else if (triple == "aarch64-none-linux-gnueabi") {
319 if (pointerSize != 64) {
320 return kErrInvalidSource;
321 }
322 } else {
323 return kErrInvalidSource;
324 }
325
David Gross97e50992017-03-29 20:52:30 +0000326 if (script.isStructExplicitlyPaddedBySlang()) {
327 if (!validateLayoutOfExportedTypes(module, module.getDataLayout(), dl))
328 return kErrInvalidLayout;
329 } else {
330 if (getTargetMachine().getTargetTriple().getArch() == llvm::Triple::x86) {
331 // Detect and fail if TargetMachine datalayout is different than what we
332 // expect. This is to detect changes in default target layout for x86 and
333 // update X86_CUSTOM_DL_STRING in include/bcc/Config/Config.h appropriately.
334 if (dl.getStringRepresentation().compare(X86_DEFAULT_DL_STRING) != 0) {
335 return kErrInvalidTargetMachine;
336 }
Pirama Arumuga Nainar9e0f8f02016-04-12 14:04:50 -0700337 }
338 }
339
David Grosscf8b2d02015-05-19 11:55:29 -0700340 // Sanitize module's target information.
Pirama Arumuga Nainar8e908932016-03-06 23:05:45 -0800341 module.setTargetTriple(getTargetMachine().getTargetTriple().str());
342 module.setDataLayout(getTargetMachine().createDataLayout());
David Grosscf8b2d02015-05-19 11:55:29 -0700343
Zonr Changade92772012-04-13 15:58:24 +0800344 // Materialize the bitcode module.
Chris Wailes900c6c12014-08-13 15:40:00 -0700345 if (module.getMaterializer() != nullptr) {
Zonr Changade92772012-04-13 15:58:24 +0800346 // A module with non-null materializer means that it is a lazy-load module.
Pirama Arumuga Nainar8e908932016-03-06 23:05:45 -0800347 // Materialize it now. This function returns false when the materialization
348 // is successful.
349 std::error_code ec = module.materializeAll();
Tim Murrayc2074ca2014-04-08 15:39:08 -0700350 if (ec) {
Zonr Changade92772012-04-13 15:58:24 +0800351 ALOGE("Failed to materialize the module `%s'! (%s)",
Tim Murrayc2074ca2014-04-08 15:39:08 -0700352 module.getModuleIdentifier().c_str(), ec.message().c_str());
Zonr Changade92772012-04-13 15:58:24 +0800353 return kErrMaterialization;
354 }
355 }
356
Jean-Luc Brouillet0a2acce2017-02-17 13:29:47 -0800357 if ((err = runPasses(script, pResult)) != kSuccess) {
Zonr Changade92772012-04-13 15:58:24 +0800358 return err;
359 }
360
Chris Wailesb4447cd2014-08-19 16:22:20 -0700361 if (IRStream) {
Tobias Grosser27fb7ed2013-06-21 18:34:56 -0700362 *IRStream << module;
Zonr Changade92772012-04-13 15:58:24 +0800363 }
364
365 return kSuccess;
Logan1f028c02010-11-27 01:02:48 +0800366}
367
Jean-Luc Brouillet0a2acce2017-02-17 13:29:47 -0800368bool Compiler::addInternalizeSymbolsPass(Script &script, llvm::legacy::PassManager &pPM) {
Chris Wailesb4447cd2014-08-19 16:22:20 -0700369 // Add a pass to internalize the symbols that don't need to have global
370 // visibility.
Chris Wailesb4447cd2014-08-19 16:22:20 -0700371 llvm::Module &module = script.getSource().getModule();
372 bcinfo::MetadataExtractor me(&module);
373 if (!me.extract()) {
374 bccAssert(false && "Could not extract metadata for module!");
375 return false;
376 }
377
Pirama Arumuga Nainarf5b49a02016-09-15 23:04:25 -0700378 // Set of symbols that should not be internalized.
379 std::set<std::string> export_symbols;
Chris Wailesb4447cd2014-08-19 16:22:20 -0700380
Stephen Hines107f50d2015-01-19 21:02:13 -0800381 const char *sf[] = {
Stephen Hinesfb81ec12015-05-18 20:04:23 -0700382 kRoot, // Graphics drawing function or compute kernel.
383 kInit, // Initialization routine called implicitly on startup.
384 kRsDtor, // Static global destructor for a script instance.
385 kRsInfo, // Variable containing string of RS metadata info.
386 kRsGlobalEntries, // Optional number of global variables.
387 kRsGlobalNames, // Optional global variable name info.
388 kRsGlobalAddresses, // Optional global variable address info.
389 kRsGlobalSizes, // Optional global variable size info.
390 kRsGlobalProperties, // Optional global variable properties.
391 nullptr // Must be nullptr-terminated.
Stephen Hines107f50d2015-01-19 21:02:13 -0800392 };
393 const char **special_functions = sf;
Chris Wailesb4447cd2014-08-19 16:22:20 -0700394 // Special RS functions should always be global symbols.
Chris Wailesb4447cd2014-08-19 16:22:20 -0700395 while (*special_functions != nullptr) {
Pirama Arumuga Nainarf5b49a02016-09-15 23:04:25 -0700396 export_symbols.insert(*special_functions);
Chris Wailesb4447cd2014-08-19 16:22:20 -0700397 special_functions++;
398 }
399
400 // Visibility of symbols appeared in rs_export_var and rs_export_func should
401 // also be preserved.
402 size_t exportVarCount = me.getExportVarCount();
403 size_t exportFuncCount = me.getExportFuncCount();
404 size_t exportForEachCount = me.getExportForEachSignatureCount();
Matt Wala4e7a5062015-07-30 16:27:51 -0700405 size_t exportReduceCount = me.getExportReduceCount();
Chris Wailesb4447cd2014-08-19 16:22:20 -0700406 const char **exportVarNameList = me.getExportVarNameList();
407 const char **exportFuncNameList = me.getExportFuncNameList();
408 const char **exportForEachNameList = me.getExportForEachNameList();
David Grossa48ea362016-06-02 14:46:55 -0700409 const bcinfo::MetadataExtractor::Reduce *exportReduceList = me.getExportReduceList();
Chris Wailesb4447cd2014-08-19 16:22:20 -0700410 size_t i;
411
412 for (i = 0; i < exportVarCount; ++i) {
Pirama Arumuga Nainarf5b49a02016-09-15 23:04:25 -0700413 export_symbols.insert(exportVarNameList[i]);
Chris Wailesb4447cd2014-08-19 16:22:20 -0700414 }
415
416 for (i = 0; i < exportFuncCount; ++i) {
Pirama Arumuga Nainarf5b49a02016-09-15 23:04:25 -0700417 export_symbols.insert(exportFuncNameList[i]);
Chris Wailesb4447cd2014-08-19 16:22:20 -0700418 }
419
David Grossa48ea362016-06-02 14:46:55 -0700420 // Expanded foreach functions should not be internalized; nor should
421 // general reduction initializer, combiner, and outconverter
422 // functions. keep_funcs keeps the names of these functions around
423 // until createInternalizePass() is finished making its own copy of
424 // the visible symbols.
David Grossc545d6f2016-02-08 13:49:02 -0800425 std::vector<std::string> keep_funcs;
David Grossa48ea362016-06-02 14:46:55 -0700426 keep_funcs.reserve(exportForEachCount + exportReduceCount*4);
Matt Wala4e7a5062015-07-30 16:27:51 -0700427
Chris Wailesb4447cd2014-08-19 16:22:20 -0700428 for (i = 0; i < exportForEachCount; ++i) {
David Grossc545d6f2016-02-08 13:49:02 -0800429 keep_funcs.push_back(std::string(exportForEachNameList[i]) + ".expand");
Matt Wala4e7a5062015-07-30 16:27:51 -0700430 }
David Grossc545d6f2016-02-08 13:49:02 -0800431 auto keepFuncsPushBackIfPresent = [&keep_funcs](const char *Name) {
432 if (Name) keep_funcs.push_back(Name);
433 };
David Grossa48ea362016-06-02 14:46:55 -0700434 for (i = 0; i < exportReduceCount; ++i) {
435 keep_funcs.push_back(std::string(exportReduceList[i].mAccumulatorName) + ".expand");
436 keepFuncsPushBackIfPresent(exportReduceList[i].mInitializerName);
437 if (exportReduceList[i].mCombinerName != nullptr) {
438 keep_funcs.push_back(exportReduceList[i].mCombinerName);
David Gross57fd9f82016-04-08 12:35:41 -0700439 } else {
David Grossa48ea362016-06-02 14:46:55 -0700440 keep_funcs.push_back(nameReduceCombinerFromAccumulator(exportReduceList[i].mAccumulatorName));
David Gross57fd9f82016-04-08 12:35:41 -0700441 }
David Grossa48ea362016-06-02 14:46:55 -0700442 keepFuncsPushBackIfPresent(exportReduceList[i].mOutConverterName);
David Gross79e1a052016-01-11 14:42:51 -0800443 }
Chris Wailesb4447cd2014-08-19 16:22:20 -0700444
David Grossc545d6f2016-02-08 13:49:02 -0800445 for (auto &symbol_name : keep_funcs) {
Pirama Arumuga Nainarf5b49a02016-09-15 23:04:25 -0700446 export_symbols.insert(symbol_name);
Chris Wailesb4447cd2014-08-19 16:22:20 -0700447 }
448
Pirama Arumuga Nainarf5b49a02016-09-15 23:04:25 -0700449 auto IsExportedSymbol = [=](const llvm::GlobalValue &GV) {
450 return export_symbols.count(GV.getName()) > 0;
451 };
452
453 pPM.add(llvm::createInternalizePass(IsExportedSymbol));
Chris Wailesb4447cd2014-08-19 16:22:20 -0700454
455 return true;
456}
457
David Gross5aefc982015-08-04 10:41:33 -0700458void Compiler::addInvokeHelperPass(llvm::legacy::PassManager &pPM) {
Tim Murrayb7bce742014-11-03 16:17:30 -0800459 llvm::Triple arch(getTargetMachine().getTargetTriple());
460 if (arch.isArch64Bit()) {
461 pPM.add(createRSInvokeHelperPass());
462 }
Tim Murrayb7bce742014-11-03 16:17:30 -0800463}
464
Jean-Luc Brouillet0a2acce2017-02-17 13:29:47 -0800465void Compiler::addDebugInfoPass(Script &script, llvm::legacy::PassManager &pPM) {
466 if (script.getSource().getDebugInfoEnabled())
Dean De Leo09c7a412015-11-25 12:45:45 +0000467 pPM.add(createRSAddDebugInfoPass());
468}
469
Matt Wala4e7a5062015-07-30 16:27:51 -0700470void Compiler::addExpandKernelPass(llvm::legacy::PassManager &pPM) {
471 // Expand ForEach and reduce on CPU path to reduce launch overhead.
Chris Wailesb4447cd2014-08-19 16:22:20 -0700472 bool pEnableStepOpt = true;
Matt Wala4e7a5062015-07-30 16:27:51 -0700473 pPM.add(createRSKernelExpandPass(pEnableStepOpt));
Chris Wailesb4447cd2014-08-19 16:22:20 -0700474}
475
Jean-Luc Brouillet0a2acce2017-02-17 13:29:47 -0800476void Compiler::addGlobalInfoPass(Script &script, llvm::legacy::PassManager &pPM) {
Stephen Hines750ee652015-04-16 16:24:18 -0700477 // Add additional information about RS global variables inside the Module.
Stephen Hines750ee652015-04-16 16:24:18 -0700478 if (script.getEmbedGlobalInfo()) {
479 pPM.add(createRSGlobalInfoPass(script.getEmbedGlobalInfoSkipConstant()));
480 }
Stephen Hines750ee652015-04-16 16:24:18 -0700481}
482
David Gross5aefc982015-08-04 10:41:33 -0700483void Compiler::addInvariantPass(llvm::legacy::PassManager &pPM) {
David Gross1d93a192015-03-25 14:59:27 -0700484 // Mark Loads from RsExpandKernelDriverInfo as "load.invariant".
485 // Should run after ExpandForEach and before inlining.
486 pPM.add(createRSInvariantPass());
Pirama Arumuga Nainar8c24f8d2015-03-17 13:11:25 -0700487}
Pirama Arumuga Nainarebff2ea2015-05-21 15:45:05 -0700488
Jean-Luc Brouillet0a2acce2017-02-17 13:29:47 -0800489enum Compiler::ErrorCode Compiler::screenGlobalFunctions(Script &script) {
490 llvm::Module &module = script.getSource().getModule();
Pirama Arumuga Nainarebff2ea2015-05-21 15:45:05 -0700491
492 // Materialize the bitcode module in case this is a lazy-load module. Do not
493 // clear the materializer by calling materializeAllPermanently since the
494 // runtime library has not been merged into the module yet.
495 if (module.getMaterializer() != nullptr) {
496 std::error_code ec = module.materializeAll();
497 if (ec) {
498 ALOGE("Failed to materialize module `%s' when screening globals! (%s)",
499 module.getModuleIdentifier().c_str(), ec.message().c_str());
500 return kErrMaterialization;
501 }
502 }
503
504 // Add pass to check for illegal function calls.
505 llvm::legacy::PassManager pPM;
506 pPM.add(createRSScreenFunctionsPass());
507 pPM.run(module);
508
509 return kSuccess;
510
511}
Pirama Arumuga Nainar9e0f8f02016-04-12 14:04:50 -0700512
Jean-Luc Brouillet0a2acce2017-02-17 13:29:47 -0800513void Compiler::translateGEPs(Script &script) {
Pirama Arumuga Nainar9e0f8f02016-04-12 14:04:50 -0700514 llvm::legacy::PassManager pPM;
515 pPM.add(createRSX86TranslateGEPPass());
516
517 // Materialization done in screenGlobalFunctions above.
Jean-Luc Brouillet0a2acce2017-02-17 13:29:47 -0800518 pPM.run(script.getSource().getModule());
Pirama Arumuga Nainar9e0f8f02016-04-12 14:04:50 -0700519}