blob: bf1866700e88db4ca5c870f5fd1cb32b0171d698 [file] [log] [blame]
Zonr Chang0fffa7e2012-04-12 19:43:53 +08001/*
2 * Copyright 2012, The Android Open Source Project
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
Stephen Hinese198abe2012-07-27 18:05:41 -070017#include "bcc/Renderscript/RSCompilerDriver.h"
Zonr Chang0fffa7e2012-04-12 19:43:53 +080018
Shih-wei Liao7bcec852012-04-25 04:07:09 -070019#include <llvm/Support/Path.h>
20
21#include "bcinfo/BitcodeWrapper.h"
22
Stephen Hinese198abe2012-07-27 18:05:41 -070023#include "bcc/Renderscript/RSExecutable.h"
24#include "bcc/Renderscript/RSScript.h"
Zonr Changc72c4dd2012-04-12 15:38:53 +080025#include "bcc/Support/CompilerConfig.h"
26#include "bcc/Support/TargetCompilerConfigs.h"
Shih-wei Liao7bcec852012-04-25 04:07:09 -070027#include "bcc/Source.h"
Zonr Changc72c4dd2012-04-12 15:38:53 +080028#include "bcc/Support/FileMutex.h"
Zonr Changef73a242012-04-12 16:44:01 +080029#include "bcc/Support/Log.h"
Zonr Changc72c4dd2012-04-12 15:38:53 +080030#include "bcc/Support/InputFile.h"
31#include "bcc/Support/Initialization.h"
Shih-wei Liao7bcec852012-04-25 04:07:09 -070032#include "bcc/Support/Sha1Util.h"
Zonr Changc72c4dd2012-04-12 15:38:53 +080033#include "bcc/Support/OutputFile.h"
Zonr Chang0fffa7e2012-04-12 19:43:53 +080034
35#include <cutils/properties.h>
36#include <utils/String8.h>
Shih-wei Liao7bcec852012-04-25 04:07:09 -070037#include <utils/StopWatch.h>
Zonr Chang0fffa7e2012-04-12 19:43:53 +080038
39using namespace bcc;
40
41namespace {
42
43bool is_force_recompile() {
44 char buf[PROPERTY_VALUE_MAX];
45
Shih-wei Liaoed7fffb2012-06-30 11:27:59 -070046 // Re-compile if floating point precision has been overridden.
47 property_get("debug.rs.precision", buf, "");
48 if (buf[0] != '\0') {
49 return true;
50 }
51
52 // Re-compile if debug.rs.forcerecompile is set.
Zonr Chang0fffa7e2012-04-12 19:43:53 +080053 property_get("debug.rs.forcerecompile", buf, "0");
54 if ((::strcmp(buf, "1") == 0) || (::strcmp(buf, "true") == 0)) {
55 return true;
56 } else {
57 return false;
58 }
59}
60
61} // end anonymous namespace
62
Stephen Hines3ab9da12013-02-01 18:39:15 -080063RSCompilerDriver::RSCompilerDriver(bool pUseCompilerRT) :
Stephen Hines1d4a9e42013-04-18 01:03:59 -070064 mConfig(NULL), mCompiler(), mCompilerRuntime(NULL), mDebugContext(false) {
Zonr Chang0fffa7e2012-04-12 19:43:53 +080065 init::Initialize();
Stephen Hines3ab9da12013-02-01 18:39:15 -080066 // Chain the symbol resolvers for compiler_rt and RS runtimes.
67 if (pUseCompilerRT) {
68 mCompilerRuntime = new CompilerRTSymbolResolver();
69 mResolver.chainResolver(*mCompilerRuntime);
70 }
Zonr Chang0fffa7e2012-04-12 19:43:53 +080071 mResolver.chainResolver(mRSRuntime);
72}
73
74RSCompilerDriver::~RSCompilerDriver() {
Stephen Hines3ab9da12013-02-01 18:39:15 -080075 delete mCompilerRuntime;
Zonr Chang0fffa7e2012-04-12 19:43:53 +080076 delete mConfig;
77}
78
Shih-wei Liao7bcec852012-04-25 04:07:09 -070079RSExecutable *
80RSCompilerDriver::loadScriptCache(const char *pOutputPath,
81 const RSInfo::DependencyTableTy &pDeps) {
Tim Murrayc89f78b2013-05-09 11:57:12 -070082 //android::StopWatch load_time("bcc: RSCompilerDriver::loadScriptCache time");
Zonr Chang0fffa7e2012-04-12 19:43:53 +080083 RSExecutable *result = NULL;
84
85 if (is_force_recompile())
86 return NULL;
87
88 //===--------------------------------------------------------------------===//
89 // Acquire the read lock for reading output object file.
90 //===--------------------------------------------------------------------===//
91 FileMutex<FileBase::kReadLock> read_output_mutex(pOutputPath);
92
93 if (read_output_mutex.hasError() || !read_output_mutex.lock()) {
Shih-wei Liao7bcec852012-04-25 04:07:09 -070094 ALOGE("Unable to acquire the read lock for %s! (%s)", pOutputPath,
Zonr Chang0fffa7e2012-04-12 19:43:53 +080095 read_output_mutex.getErrorMessage().c_str());
96 return NULL;
97 }
98
99 //===--------------------------------------------------------------------===//
100 // Read the output object file.
101 //===--------------------------------------------------------------------===//
102 InputFile *output_file = new (std::nothrow) InputFile(pOutputPath);
103
104 if ((output_file == NULL) || output_file->hasError()) {
Tim Murrayc89f78b2013-05-09 11:57:12 -0700105 // ALOGE("Unable to open the %s for read! (%s)", pOutputPath,
106 // output_file->getErrorMessage().c_str());
Zonr Chang0fffa7e2012-04-12 19:43:53 +0800107 delete output_file;
108 return NULL;
109 }
110
111 //===--------------------------------------------------------------------===//
112 // Acquire the read lock on output_file for reading its RS info file.
113 //===--------------------------------------------------------------------===//
114 android::String8 info_path = RSInfo::GetPath(*output_file);
115
116 if (!output_file->lock()) {
117 ALOGE("Unable to acquire the read lock on %s for reading %s! (%s)",
Shih-wei Liao7bcec852012-04-25 04:07:09 -0700118 pOutputPath, info_path.string(),
Zonr Chang0fffa7e2012-04-12 19:43:53 +0800119 output_file->getErrorMessage().c_str());
120 delete output_file;
121 return NULL;
122 }
123
124 //===---------------------------------------------------------------------===//
125 // Open and load the RS info file.
126 //===--------------------------------------------------------------------===//
127 InputFile info_file(info_path.string());
Shih-wei Liao7bcec852012-04-25 04:07:09 -0700128 RSInfo *info = RSInfo::ReadFromFile(info_file, pDeps);
Zonr Chang0fffa7e2012-04-12 19:43:53 +0800129
130 // Release the lock on output_file.
131 output_file->unlock();
132
133 if (info == NULL) {
134 delete output_file;
135 return NULL;
136 }
137
138 //===--------------------------------------------------------------------===//
139 // Create the RSExecutable.
140 //===--------------------------------------------------------------------===//
141 result = RSExecutable::Create(*info, *output_file, mResolver);
142 if (result == NULL) {
143 delete output_file;
144 delete info;
145 return NULL;
146 }
147
Zonr Chang0fffa7e2012-04-12 19:43:53 +0800148 return result;
149}
150
151bool RSCompilerDriver::setupConfig(const RSScript &pScript) {
152 bool changed = false;
153
154 const llvm::CodeGenOpt::Level script_opt_level =
155 static_cast<llvm::CodeGenOpt::Level>(pScript.getOptimizationLevel());
156
157 if (mConfig != NULL) {
158 // Renderscript bitcode may have their optimization flag configuration
159 // different than the previous run of RS compilation.
160 if (mConfig->getOptimizationLevel() != script_opt_level) {
161 mConfig->setOptimizationLevel(script_opt_level);
162 changed = true;
163 }
164 } else {
165 // Haven't run the compiler ever.
166 mConfig = new (std::nothrow) DefaultCompilerConfig();
167 if (mConfig == NULL) {
168 // Return false since mConfig remains NULL and out-of-memory.
169 return false;
170 }
171 mConfig->setOptimizationLevel(script_opt_level);
172 changed = true;
173 }
174
175#if defined(DEFAULT_ARM_CODEGEN)
176 // NEON should be disable when full-precision floating point is required.
177 assert((pScript.getInfo() != NULL) && "NULL RS info!");
Shih-wei Liaoed7fffb2012-06-30 11:27:59 -0700178 if (pScript.getInfo()->getFloatPrecisionRequirement() == RSInfo::FP_Full) {
Zonr Chang0fffa7e2012-04-12 19:43:53 +0800179 // Must be ARMCompilerConfig.
180 ARMCompilerConfig *arm_config = static_cast<ARMCompilerConfig *>(mConfig);
181 changed |= arm_config->enableNEON(/* pEnable */false);
182 }
183#endif
184
185 return changed;
186}
187
Shih-wei Liao7bcec852012-04-25 04:07:09 -0700188RSExecutable *
189RSCompilerDriver::compileScript(RSScript &pScript,
Shih-wei Liaoba420642012-06-30 11:27:37 -0700190 const char* pScriptName,
Shih-wei Liao7bcec852012-04-25 04:07:09 -0700191 const char *pOutputPath,
Stephen Hines331310e2012-10-26 19:27:55 -0700192 const char *pRuntimePath,
193 const RSInfo::DependencyTableTy &pDeps,
194 bool pSkipLoad) {
Tim Murrayc89f78b2013-05-09 11:57:12 -0700195 //android::StopWatch compile_time("bcc: RSCompilerDriver::compileScript time");
Zonr Chang0fffa7e2012-04-12 19:43:53 +0800196 RSExecutable *result = NULL;
197 RSInfo *info = NULL;
198
199 //===--------------------------------------------------------------------===//
200 // Extract RS-specific information from source bitcode.
201 //===--------------------------------------------------------------------===//
202 // RS info may contains configuration (such as #optimization_level) to the
203 // compiler therefore it should be extracted before compilation.
Shih-wei Liao7bcec852012-04-25 04:07:09 -0700204 info = RSInfo::ExtractFromSource(pScript.getSource(), pDeps);
Zonr Chang0fffa7e2012-04-12 19:43:53 +0800205 if (info == NULL) {
206 return NULL;
207 }
208
209 //===--------------------------------------------------------------------===//
210 // Associate script with its info
211 //===--------------------------------------------------------------------===//
212 // This is required since RS compiler may need information in the info file
213 // to do some transformation (e.g., expand foreach-able function.)
214 pScript.setInfo(info);
215
216 //===--------------------------------------------------------------------===//
Stephen Hinese198abe2012-07-27 18:05:41 -0700217 // Link RS script with Renderscript runtime.
Shih-wei Liaoba420642012-06-30 11:27:37 -0700218 //===--------------------------------------------------------------------===//
Stephen Hines331310e2012-10-26 19:27:55 -0700219 if (!RSScript::LinkRuntime(pScript, pRuntimePath)) {
Stephen Hinese198abe2012-07-27 18:05:41 -0700220 ALOGE("Failed to link script '%s' with Renderscript runtime!", pScriptName);
Shih-wei Liaoba420642012-06-30 11:27:37 -0700221 return NULL;
222 }
223
224 //===--------------------------------------------------------------------===//
Zonr Chang0fffa7e2012-04-12 19:43:53 +0800225 // Acquire the write lock for writing output object file.
226 //===--------------------------------------------------------------------===//
227 FileMutex<FileBase::kWriteLock> write_output_mutex(pOutputPath);
228
229 if (write_output_mutex.hasError() || !write_output_mutex.lock()) {
230 ALOGE("Unable to acquire the lock for writing %s! (%s)",
Shih-wei Liao7bcec852012-04-25 04:07:09 -0700231 pOutputPath, write_output_mutex.getErrorMessage().c_str());
Zonr Chang0fffa7e2012-04-12 19:43:53 +0800232 return NULL;
233 }
234
235 //===--------------------------------------------------------------------===//
236 // Open the output file for write.
237 //===--------------------------------------------------------------------===//
Stephen Hines1d4a9e42013-04-18 01:03:59 -0700238 unsigned flags = FileBase::kTruncate;
239 if (mDebugContext) {
240 // Delete the cache file when we finish up under a debug context.
241 flags |= FileBase::kDeleteOnClose;
242 }
243 OutputFile *output_file = new (std::nothrow) OutputFile(pOutputPath, flags);
Zonr Chang0fffa7e2012-04-12 19:43:53 +0800244
245 if ((output_file == NULL) || output_file->hasError()) {
Tim Murrayc89f78b2013-05-09 11:57:12 -0700246 ALOGE("Unable to open %s for write! (%s)", pOutputPath,
247 output_file->getErrorMessage().c_str());
Zonr Chang0fffa7e2012-04-12 19:43:53 +0800248 delete info;
249 delete output_file;
250 return NULL;
251 }
252
253 //===--------------------------------------------------------------------===//
254 // Setup the config to the compiler.
255 //===--------------------------------------------------------------------===//
256 bool compiler_need_reconfigure = setupConfig(pScript);
257
258 if (mConfig == NULL) {
Shih-wei Liao7bcec852012-04-25 04:07:09 -0700259 ALOGE("Failed to setup config for RS compiler to compile %s!", pOutputPath);
Zonr Chang0fffa7e2012-04-12 19:43:53 +0800260 delete info;
261 delete output_file;
262 return NULL;
263 }
264
265 // Compiler need to re-config if it's haven't run the config() yet or the
266 // configuration it referenced is changed.
267 if (compiler_need_reconfigure) {
268 Compiler::ErrorCode err = mCompiler.config(*mConfig);
269 if (err != Compiler::kSuccess) {
Shih-wei Liao7bcec852012-04-25 04:07:09 -0700270 ALOGE("Failed to config the RS compiler for %s! (%s)",pOutputPath,
Zonr Chang0fffa7e2012-04-12 19:43:53 +0800271 Compiler::GetErrorString(err));
272 delete info;
273 delete output_file;
274 return NULL;
275 }
276 }
277
278 //===--------------------------------------------------------------------===//
279 // Run the compiler.
280 //===--------------------------------------------------------------------===//
281 Compiler::ErrorCode compile_result = mCompiler.compile(pScript, *output_file);
282 if (compile_result != Compiler::kSuccess) {
Shih-wei Liao7bcec852012-04-25 04:07:09 -0700283 ALOGE("Unable to compile the source to file %s! (%s)", pOutputPath,
Zonr Chang0fffa7e2012-04-12 19:43:53 +0800284 Compiler::GetErrorString(compile_result));
285 delete info;
286 delete output_file;
287 return NULL;
288 }
289
Stephen Hines331310e2012-10-26 19:27:55 -0700290 // No need to produce an RSExecutable in this case.
291 // TODO: Error handling in this case is nonexistent.
292 if (pSkipLoad) {
293 return NULL;
294 }
295
Zonr Chang0fffa7e2012-04-12 19:43:53 +0800296 //===--------------------------------------------------------------------===//
297 // Create the RSExecutable.
298 //===--------------------------------------------------------------------===//
299 result = RSExecutable::Create(*info, *output_file, mResolver);
300 if (result == NULL) {
301 delete info;
302 delete output_file;
303 return NULL;
304 }
305
Zonr Chang0fffa7e2012-04-12 19:43:53 +0800306 //===--------------------------------------------------------------------===//
Shih-wei Liao6d01af62012-07-22 16:26:22 -0700307 // Dump the disassembly for debug when possible.
308 //===--------------------------------------------------------------------===//
Shih-wei Liaod7f1bd62012-07-23 23:14:34 -0700309#if USE_DISASSEMBLER
Shih-wei Liao6d01af62012-07-22 16:26:22 -0700310 OutputFile *disassembly_output =
Shih-wei Liaod7f1bd62012-07-23 23:14:34 -0700311 new (std::nothrow) OutputFile(DEBUG_DISASSEMBLER_FILE,
Shih-wei Liao6d01af62012-07-22 16:26:22 -0700312 FileBase::kAppend);
313
314 if (disassembly_output != NULL) {
315 result->dumpDisassembly(*disassembly_output);
316 delete disassembly_output;
317 }
318#endif
319
320 //===--------------------------------------------------------------------===//
Zonr Chang0fffa7e2012-04-12 19:43:53 +0800321 // Write out the RS info file.
322 //===--------------------------------------------------------------------===//
323 // Note that write failure only results in a warning since the source is
324 // successfully compiled and loaded.
325 if (!result->syncInfo(/* pForce */true)) {
326 ALOGW("%s was successfully compiled and loaded but its RS info file failed "
Shih-wei Liao7bcec852012-04-25 04:07:09 -0700327 "to write out!", pOutputPath);
Zonr Chang0fffa7e2012-04-12 19:43:53 +0800328 }
329
330 return result;
331}
332
Shih-wei Liao7bcec852012-04-25 04:07:09 -0700333RSExecutable *RSCompilerDriver::build(BCCContext &pContext,
334 const char *pCacheDir,
335 const char *pResName,
336 const char *pBitcode,
Stephen Hines331310e2012-10-26 19:27:55 -0700337 size_t pBitcodeSize,
Stephen Hines06731a62013-02-12 19:29:42 -0800338 const char *pRuntimePath,
339 RSLinkRuntimeCallback pLinkRuntimeCallback) {
Tim Murrayc89f78b2013-05-09 11:57:12 -0700340 // android::StopWatch build_time("bcc: RSCompilerDriver::build time");
Shih-wei Liao7bcec852012-04-25 04:07:09 -0700341 //===--------------------------------------------------------------------===//
342 // Check parameters.
343 //===--------------------------------------------------------------------===//
344 if ((pCacheDir == NULL) || (pResName == NULL)) {
345 ALOGE("Invalid parameter passed to RSCompilerDriver::build()! (cache dir: "
346 "%s, resource name: %s)", ((pCacheDir) ? pCacheDir : "(null)"),
347 ((pResName) ? pResName : "(null)"));
348 return NULL;
349 }
350
351 if ((pBitcode == NULL) || (pBitcodeSize <= 0)) {
352 ALOGE("No bitcode supplied! (bitcode: %p, size of bitcode: %u)",
353 pBitcode, static_cast<unsigned>(pBitcodeSize));
354 return NULL;
355 }
356
357 //===--------------------------------------------------------------------===//
358 // Prepare dependency information.
359 //===--------------------------------------------------------------------===//
360 RSInfo::DependencyTableTy dep_info;
361 uint8_t bitcode_sha1[20];
362 Sha1Util::GetSHA1DigestFromBuffer(bitcode_sha1, pBitcode, pBitcodeSize);
363 dep_info.push(std::make_pair(pResName, bitcode_sha1));
364
365 //===--------------------------------------------------------------------===//
366 // Construct output path.
367 //===--------------------------------------------------------------------===//
368 llvm::sys::Path output_path(pCacheDir);
369
370 // {pCacheDir}/{pResName}
371 if (!output_path.appendComponent(pResName)) {
372 ALOGE("Failed to construct output path %s/%s!", pCacheDir, pResName);
373 return NULL;
374 }
375
376 // {pCacheDir}/{pResName}.o
377 output_path.appendSuffix("o");
378
379 //===--------------------------------------------------------------------===//
380 // Load cache.
381 //===--------------------------------------------------------------------===//
Stephen Hines1d4a9e42013-04-18 01:03:59 -0700382 RSExecutable *result = NULL;
Zonr Chang0fffa7e2012-04-12 19:43:53 +0800383
Stephen Hines1d4a9e42013-04-18 01:03:59 -0700384 // Skip loading from the cache if we are using a debug context.
385 if (!mDebugContext) {
386 result = loadScriptCache(output_path.c_str(), dep_info);
387
388 if (result != NULL) {
389 // Cache hit
390 return result;
391 }
Zonr Chang0fffa7e2012-04-12 19:43:53 +0800392 }
393
Shih-wei Liao7bcec852012-04-25 04:07:09 -0700394 //===--------------------------------------------------------------------===//
395 // Load the bitcode and create script.
396 //===--------------------------------------------------------------------===//
397 Source *source = Source::CreateFromBuffer(pContext, pResName,
398 pBitcode, pBitcodeSize);
399 if (source == NULL) {
400 return NULL;
401 }
402
403 RSScript *script = new (std::nothrow) RSScript(*source);
404 if (script == NULL) {
405 ALOGE("Out of memory when create Script object for '%s'! (output: %s)",
406 pResName, output_path.c_str());
407 delete source;
408 return NULL;
409 }
410
Stephen Hines06731a62013-02-12 19:29:42 -0800411 script->setLinkRuntimeCallback(pLinkRuntimeCallback);
412
Shih-wei Liao7bcec852012-04-25 04:07:09 -0700413 // Read information from bitcode wrapper.
414 bcinfo::BitcodeWrapper wrapper(pBitcode, pBitcodeSize);
415 script->setCompilerVersion(wrapper.getCompilerVersion());
416 script->setOptimizationLevel(static_cast<RSScript::OptimizationLevel>(
417 wrapper.getOptimizationLevel()));
418
419 //===--------------------------------------------------------------------===//
420 // Compile the script
421 //===--------------------------------------------------------------------===//
Stephen Hines331310e2012-10-26 19:27:55 -0700422 result = compileScript(*script, pResName, output_path.c_str(), pRuntimePath,
423 dep_info, false);
Shih-wei Liao7bcec852012-04-25 04:07:09 -0700424
425 // Script is no longer used. Free it to get more memory.
426 delete script;
427
428 if (result == NULL) {
429 return NULL;
430 }
431
432 return result;
Zonr Chang0fffa7e2012-04-12 19:43:53 +0800433}
Stephen Hines331310e2012-10-26 19:27:55 -0700434
435
436RSExecutable *RSCompilerDriver::build(RSScript &pScript, const char *pOut,
437 const char *pRuntimePath) {
438 RSInfo::DependencyTableTy dep_info;
439 RSInfo *info = RSInfo::ExtractFromSource(pScript.getSource(), dep_info);
440 if (info == NULL) {
441 return NULL;
442 }
443 pScript.setInfo(info);
444
Stephen Hines86a0b792012-11-06 20:04:47 -0800445 // Embed the info string directly in the ELF, since this path is for an
446 // offline (host) compilation.
447 pScript.setEmbedInfo(true);
448
Stephen Hines331310e2012-10-26 19:27:55 -0700449 RSExecutable *result = compileScript(pScript, pOut, pOut, pRuntimePath,
450 dep_info, true);
451 return result;
452}
453