blob: 31d38070a5547ebe79a6ce5c8a578cd7fa1ae384 [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
63RSCompilerDriver::RSCompilerDriver() : mConfig(NULL), mCompiler() {
64 init::Initialize();
65 // Chain the symbol resolvers for BCC runtimes and RS runtimes.
66 mResolver.chainResolver(mBCCRuntime);
67 mResolver.chainResolver(mRSRuntime);
68}
69
70RSCompilerDriver::~RSCompilerDriver() {
71 delete mConfig;
72}
73
Shih-wei Liao7bcec852012-04-25 04:07:09 -070074RSExecutable *
75RSCompilerDriver::loadScriptCache(const char *pOutputPath,
76 const RSInfo::DependencyTableTy &pDeps) {
77 android::StopWatch load_time("bcc: RSCompilerDriver::loadScriptCache time");
Zonr Chang0fffa7e2012-04-12 19:43:53 +080078 RSExecutable *result = NULL;
79
80 if (is_force_recompile())
81 return NULL;
82
83 //===--------------------------------------------------------------------===//
84 // Acquire the read lock for reading output object file.
85 //===--------------------------------------------------------------------===//
86 FileMutex<FileBase::kReadLock> read_output_mutex(pOutputPath);
87
88 if (read_output_mutex.hasError() || !read_output_mutex.lock()) {
Shih-wei Liao7bcec852012-04-25 04:07:09 -070089 ALOGE("Unable to acquire the read lock for %s! (%s)", pOutputPath,
Zonr Chang0fffa7e2012-04-12 19:43:53 +080090 read_output_mutex.getErrorMessage().c_str());
91 return NULL;
92 }
93
94 //===--------------------------------------------------------------------===//
95 // Read the output object file.
96 //===--------------------------------------------------------------------===//
97 InputFile *output_file = new (std::nothrow) InputFile(pOutputPath);
98
99 if ((output_file == NULL) || output_file->hasError()) {
Shih-wei Liao7bcec852012-04-25 04:07:09 -0700100 ALOGE("Unable to open the %s for read! (%s)", pOutputPath,
Zonr Chang0fffa7e2012-04-12 19:43:53 +0800101 output_file->getErrorMessage().c_str());
102 delete output_file;
103 return NULL;
104 }
105
106 //===--------------------------------------------------------------------===//
107 // Acquire the read lock on output_file for reading its RS info file.
108 //===--------------------------------------------------------------------===//
109 android::String8 info_path = RSInfo::GetPath(*output_file);
110
111 if (!output_file->lock()) {
112 ALOGE("Unable to acquire the read lock on %s for reading %s! (%s)",
Shih-wei Liao7bcec852012-04-25 04:07:09 -0700113 pOutputPath, info_path.string(),
Zonr Chang0fffa7e2012-04-12 19:43:53 +0800114 output_file->getErrorMessage().c_str());
115 delete output_file;
116 return NULL;
117 }
118
119 //===---------------------------------------------------------------------===//
120 // Open and load the RS info file.
121 //===--------------------------------------------------------------------===//
122 InputFile info_file(info_path.string());
Shih-wei Liao7bcec852012-04-25 04:07:09 -0700123 RSInfo *info = RSInfo::ReadFromFile(info_file, pDeps);
Zonr Chang0fffa7e2012-04-12 19:43:53 +0800124
125 // Release the lock on output_file.
126 output_file->unlock();
127
128 if (info == NULL) {
129 delete output_file;
130 return NULL;
131 }
132
133 //===--------------------------------------------------------------------===//
134 // Create the RSExecutable.
135 //===--------------------------------------------------------------------===//
136 result = RSExecutable::Create(*info, *output_file, mResolver);
137 if (result == NULL) {
138 delete output_file;
139 delete info;
140 return NULL;
141 }
142
Zonr Chang0fffa7e2012-04-12 19:43:53 +0800143 return result;
144}
145
146bool RSCompilerDriver::setupConfig(const RSScript &pScript) {
147 bool changed = false;
148
149 const llvm::CodeGenOpt::Level script_opt_level =
150 static_cast<llvm::CodeGenOpt::Level>(pScript.getOptimizationLevel());
151
152 if (mConfig != NULL) {
153 // Renderscript bitcode may have their optimization flag configuration
154 // different than the previous run of RS compilation.
155 if (mConfig->getOptimizationLevel() != script_opt_level) {
156 mConfig->setOptimizationLevel(script_opt_level);
157 changed = true;
158 }
159 } else {
160 // Haven't run the compiler ever.
161 mConfig = new (std::nothrow) DefaultCompilerConfig();
162 if (mConfig == NULL) {
163 // Return false since mConfig remains NULL and out-of-memory.
164 return false;
165 }
166 mConfig->setOptimizationLevel(script_opt_level);
167 changed = true;
168 }
169
170#if defined(DEFAULT_ARM_CODEGEN)
171 // NEON should be disable when full-precision floating point is required.
172 assert((pScript.getInfo() != NULL) && "NULL RS info!");
Shih-wei Liaoed7fffb2012-06-30 11:27:59 -0700173 if (pScript.getInfo()->getFloatPrecisionRequirement() == RSInfo::FP_Full) {
Zonr Chang0fffa7e2012-04-12 19:43:53 +0800174 // Must be ARMCompilerConfig.
175 ARMCompilerConfig *arm_config = static_cast<ARMCompilerConfig *>(mConfig);
176 changed |= arm_config->enableNEON(/* pEnable */false);
177 }
178#endif
179
180 return changed;
181}
182
Shih-wei Liao7bcec852012-04-25 04:07:09 -0700183RSExecutable *
184RSCompilerDriver::compileScript(RSScript &pScript,
Shih-wei Liaoba420642012-06-30 11:27:37 -0700185 const char* pScriptName,
Shih-wei Liao7bcec852012-04-25 04:07:09 -0700186 const char *pOutputPath,
Stephen Hines331310e2012-10-26 19:27:55 -0700187 const char *pRuntimePath,
188 const RSInfo::DependencyTableTy &pDeps,
189 bool pSkipLoad) {
Shih-wei Liao7bcec852012-04-25 04:07:09 -0700190 android::StopWatch compile_time("bcc: RSCompilerDriver::compileScript time");
Zonr Chang0fffa7e2012-04-12 19:43:53 +0800191 RSExecutable *result = NULL;
192 RSInfo *info = NULL;
193
194 //===--------------------------------------------------------------------===//
195 // Extract RS-specific information from source bitcode.
196 //===--------------------------------------------------------------------===//
197 // RS info may contains configuration (such as #optimization_level) to the
198 // compiler therefore it should be extracted before compilation.
Shih-wei Liao7bcec852012-04-25 04:07:09 -0700199 info = RSInfo::ExtractFromSource(pScript.getSource(), pDeps);
Zonr Chang0fffa7e2012-04-12 19:43:53 +0800200 if (info == NULL) {
201 return NULL;
202 }
203
204 //===--------------------------------------------------------------------===//
205 // Associate script with its info
206 //===--------------------------------------------------------------------===//
207 // This is required since RS compiler may need information in the info file
208 // to do some transformation (e.g., expand foreach-able function.)
209 pScript.setInfo(info);
210
211 //===--------------------------------------------------------------------===//
Stephen Hinese198abe2012-07-27 18:05:41 -0700212 // Link RS script with Renderscript runtime.
Shih-wei Liaoba420642012-06-30 11:27:37 -0700213 //===--------------------------------------------------------------------===//
Stephen Hines331310e2012-10-26 19:27:55 -0700214 if (!RSScript::LinkRuntime(pScript, pRuntimePath)) {
Stephen Hinese198abe2012-07-27 18:05:41 -0700215 ALOGE("Failed to link script '%s' with Renderscript runtime!", pScriptName);
Shih-wei Liaoba420642012-06-30 11:27:37 -0700216 return NULL;
217 }
218
219 //===--------------------------------------------------------------------===//
Zonr Chang0fffa7e2012-04-12 19:43:53 +0800220 // Acquire the write lock for writing output object file.
221 //===--------------------------------------------------------------------===//
222 FileMutex<FileBase::kWriteLock> write_output_mutex(pOutputPath);
223
224 if (write_output_mutex.hasError() || !write_output_mutex.lock()) {
225 ALOGE("Unable to acquire the lock for writing %s! (%s)",
Shih-wei Liao7bcec852012-04-25 04:07:09 -0700226 pOutputPath, write_output_mutex.getErrorMessage().c_str());
Zonr Chang0fffa7e2012-04-12 19:43:53 +0800227 return NULL;
228 }
229
230 //===--------------------------------------------------------------------===//
231 // Open the output file for write.
232 //===--------------------------------------------------------------------===//
Shih-wei Liaoc02eae62012-07-22 16:23:32 -0700233 OutputFile *output_file =
234 new (std::nothrow) OutputFile(pOutputPath, FileBase::kTruncate);
Zonr Chang0fffa7e2012-04-12 19:43:53 +0800235
236 if ((output_file == NULL) || output_file->hasError()) {
Shih-wei Liao7bcec852012-04-25 04:07:09 -0700237 ALOGE("Unable to open the %s for write! (%s)", pOutputPath,
Zonr Chang0fffa7e2012-04-12 19:43:53 +0800238 output_file->getErrorMessage().c_str());
239 delete info;
240 delete output_file;
241 return NULL;
242 }
243
244 //===--------------------------------------------------------------------===//
245 // Setup the config to the compiler.
246 //===--------------------------------------------------------------------===//
247 bool compiler_need_reconfigure = setupConfig(pScript);
248
249 if (mConfig == NULL) {
Shih-wei Liao7bcec852012-04-25 04:07:09 -0700250 ALOGE("Failed to setup config for RS compiler to compile %s!", pOutputPath);
Zonr Chang0fffa7e2012-04-12 19:43:53 +0800251 delete info;
252 delete output_file;
253 return NULL;
254 }
255
256 // Compiler need to re-config if it's haven't run the config() yet or the
257 // configuration it referenced is changed.
258 if (compiler_need_reconfigure) {
259 Compiler::ErrorCode err = mCompiler.config(*mConfig);
260 if (err != Compiler::kSuccess) {
Shih-wei Liao7bcec852012-04-25 04:07:09 -0700261 ALOGE("Failed to config the RS compiler for %s! (%s)",pOutputPath,
Zonr Chang0fffa7e2012-04-12 19:43:53 +0800262 Compiler::GetErrorString(err));
263 delete info;
264 delete output_file;
265 return NULL;
266 }
267 }
268
269 //===--------------------------------------------------------------------===//
270 // Run the compiler.
271 //===--------------------------------------------------------------------===//
272 Compiler::ErrorCode compile_result = mCompiler.compile(pScript, *output_file);
273 if (compile_result != Compiler::kSuccess) {
Shih-wei Liao7bcec852012-04-25 04:07:09 -0700274 ALOGE("Unable to compile the source to file %s! (%s)", pOutputPath,
Zonr Chang0fffa7e2012-04-12 19:43:53 +0800275 Compiler::GetErrorString(compile_result));
276 delete info;
277 delete output_file;
278 return NULL;
279 }
280
Stephen Hines331310e2012-10-26 19:27:55 -0700281 // No need to produce an RSExecutable in this case.
282 // TODO: Error handling in this case is nonexistent.
283 if (pSkipLoad) {
284 return NULL;
285 }
286
Zonr Chang0fffa7e2012-04-12 19:43:53 +0800287 //===--------------------------------------------------------------------===//
288 // Create the RSExecutable.
289 //===--------------------------------------------------------------------===//
290 result = RSExecutable::Create(*info, *output_file, mResolver);
291 if (result == NULL) {
292 delete info;
293 delete output_file;
294 return NULL;
295 }
296
Zonr Chang0fffa7e2012-04-12 19:43:53 +0800297 //===--------------------------------------------------------------------===//
Shih-wei Liao6d01af62012-07-22 16:26:22 -0700298 // Dump the disassembly for debug when possible.
299 //===--------------------------------------------------------------------===//
Shih-wei Liaod7f1bd62012-07-23 23:14:34 -0700300#if USE_DISASSEMBLER
Shih-wei Liao6d01af62012-07-22 16:26:22 -0700301 OutputFile *disassembly_output =
Shih-wei Liaod7f1bd62012-07-23 23:14:34 -0700302 new (std::nothrow) OutputFile(DEBUG_DISASSEMBLER_FILE,
Shih-wei Liao6d01af62012-07-22 16:26:22 -0700303 FileBase::kAppend);
304
305 if (disassembly_output != NULL) {
306 result->dumpDisassembly(*disassembly_output);
307 delete disassembly_output;
308 }
309#endif
310
311 //===--------------------------------------------------------------------===//
Zonr Chang0fffa7e2012-04-12 19:43:53 +0800312 // Write out the RS info file.
313 //===--------------------------------------------------------------------===//
314 // Note that write failure only results in a warning since the source is
315 // successfully compiled and loaded.
316 if (!result->syncInfo(/* pForce */true)) {
317 ALOGW("%s was successfully compiled and loaded but its RS info file failed "
Shih-wei Liao7bcec852012-04-25 04:07:09 -0700318 "to write out!", pOutputPath);
Zonr Chang0fffa7e2012-04-12 19:43:53 +0800319 }
320
321 return result;
322}
323
Shih-wei Liao7bcec852012-04-25 04:07:09 -0700324RSExecutable *RSCompilerDriver::build(BCCContext &pContext,
325 const char *pCacheDir,
326 const char *pResName,
327 const char *pBitcode,
Stephen Hines331310e2012-10-26 19:27:55 -0700328 size_t pBitcodeSize,
329 const char *pRuntimePath) {
Shih-wei Liao7bcec852012-04-25 04:07:09 -0700330 android::StopWatch build_time("bcc: RSCompilerDriver::build time");
331 //===--------------------------------------------------------------------===//
332 // Check parameters.
333 //===--------------------------------------------------------------------===//
334 if ((pCacheDir == NULL) || (pResName == NULL)) {
335 ALOGE("Invalid parameter passed to RSCompilerDriver::build()! (cache dir: "
336 "%s, resource name: %s)", ((pCacheDir) ? pCacheDir : "(null)"),
337 ((pResName) ? pResName : "(null)"));
338 return NULL;
339 }
340
341 if ((pBitcode == NULL) || (pBitcodeSize <= 0)) {
342 ALOGE("No bitcode supplied! (bitcode: %p, size of bitcode: %u)",
343 pBitcode, static_cast<unsigned>(pBitcodeSize));
344 return NULL;
345 }
346
347 //===--------------------------------------------------------------------===//
348 // Prepare dependency information.
349 //===--------------------------------------------------------------------===//
350 RSInfo::DependencyTableTy dep_info;
351 uint8_t bitcode_sha1[20];
352 Sha1Util::GetSHA1DigestFromBuffer(bitcode_sha1, pBitcode, pBitcodeSize);
353 dep_info.push(std::make_pair(pResName, bitcode_sha1));
354
355 //===--------------------------------------------------------------------===//
356 // Construct output path.
357 //===--------------------------------------------------------------------===//
358 llvm::sys::Path output_path(pCacheDir);
359
360 // {pCacheDir}/{pResName}
361 if (!output_path.appendComponent(pResName)) {
362 ALOGE("Failed to construct output path %s/%s!", pCacheDir, pResName);
363 return NULL;
364 }
365
366 // {pCacheDir}/{pResName}.o
367 output_path.appendSuffix("o");
368
369 //===--------------------------------------------------------------------===//
370 // Load cache.
371 //===--------------------------------------------------------------------===//
372 RSExecutable *result = loadScriptCache(output_path.c_str(), dep_info);
Zonr Chang0fffa7e2012-04-12 19:43:53 +0800373
374 if (result != NULL) {
375 // Cache hit
376 return result;
377 }
378
Shih-wei Liao7bcec852012-04-25 04:07:09 -0700379 //===--------------------------------------------------------------------===//
380 // Load the bitcode and create script.
381 //===--------------------------------------------------------------------===//
382 Source *source = Source::CreateFromBuffer(pContext, pResName,
383 pBitcode, pBitcodeSize);
384 if (source == NULL) {
385 return NULL;
386 }
387
388 RSScript *script = new (std::nothrow) RSScript(*source);
389 if (script == NULL) {
390 ALOGE("Out of memory when create Script object for '%s'! (output: %s)",
391 pResName, output_path.c_str());
392 delete source;
393 return NULL;
394 }
395
Shih-wei Liao7bcec852012-04-25 04:07:09 -0700396 // Read information from bitcode wrapper.
397 bcinfo::BitcodeWrapper wrapper(pBitcode, pBitcodeSize);
398 script->setCompilerVersion(wrapper.getCompilerVersion());
399 script->setOptimizationLevel(static_cast<RSScript::OptimizationLevel>(
400 wrapper.getOptimizationLevel()));
401
402 //===--------------------------------------------------------------------===//
403 // Compile the script
404 //===--------------------------------------------------------------------===//
Stephen Hines331310e2012-10-26 19:27:55 -0700405 result = compileScript(*script, pResName, output_path.c_str(), pRuntimePath,
406 dep_info, false);
Shih-wei Liao7bcec852012-04-25 04:07:09 -0700407
408 // Script is no longer used. Free it to get more memory.
409 delete script;
410
411 if (result == NULL) {
412 return NULL;
413 }
414
415 return result;
Zonr Chang0fffa7e2012-04-12 19:43:53 +0800416}
Stephen Hines331310e2012-10-26 19:27:55 -0700417
418
419RSExecutable *RSCompilerDriver::build(RSScript &pScript, const char *pOut,
420 const char *pRuntimePath) {
421 RSInfo::DependencyTableTy dep_info;
422 RSInfo *info = RSInfo::ExtractFromSource(pScript.getSource(), dep_info);
423 if (info == NULL) {
424 return NULL;
425 }
426 pScript.setInfo(info);
427
428 RSExecutable *result = compileScript(pScript, pOut, pOut, pRuntimePath,
429 dep_info, true);
430 return result;
431}
432