blob: 0ccb6257a834323cd24c1ae86e0413375d8896a6 [file] [log] [blame]
Zonr Chang64a2af12012-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
Zonr Chang80232dd2012-04-12 15:38:53 +080017#include "bcc/RenderScript/RSCompilerDriver.h"
Zonr Chang64a2af12012-04-12 19:43:53 +080018
Shih-wei Liao170d4202012-04-25 04:07:09 -070019#include <llvm/Support/Path.h>
20
21#include "bcinfo/BitcodeWrapper.h"
22
Zonr Chang80232dd2012-04-12 15:38:53 +080023#include "bcc/RenderScript/RSExecutable.h"
Shih-wei Liao170d4202012-04-25 04:07:09 -070024#include "bcc/RenderScript/RSScript.h"
Zonr Chang80232dd2012-04-12 15:38:53 +080025#include "bcc/Support/CompilerConfig.h"
26#include "bcc/Support/TargetCompilerConfigs.h"
Shih-wei Liao170d4202012-04-25 04:07:09 -070027#include "bcc/Source.h"
Zonr Chang80232dd2012-04-12 15:38:53 +080028#include "bcc/Support/FileMutex.h"
Zonr Changb519fe32012-04-12 16:44:01 +080029#include "bcc/Support/Log.h"
Zonr Chang80232dd2012-04-12 15:38:53 +080030#include "bcc/Support/InputFile.h"
31#include "bcc/Support/Initialization.h"
Shih-wei Liao170d4202012-04-25 04:07:09 -070032#include "bcc/Support/Sha1Util.h"
Zonr Chang80232dd2012-04-12 15:38:53 +080033#include "bcc/Support/OutputFile.h"
Zonr Chang64a2af12012-04-12 19:43:53 +080034
35#include <cutils/properties.h>
36#include <utils/String8.h>
Shih-wei Liao170d4202012-04-25 04:07:09 -070037#include <utils/StopWatch.h>
Zonr Chang64a2af12012-04-12 19:43:53 +080038
39using namespace bcc;
40
41namespace {
42
43bool is_force_recompile() {
44 char buf[PROPERTY_VALUE_MAX];
45
46 property_get("debug.rs.forcerecompile", buf, "0");
47 if ((::strcmp(buf, "1") == 0) || (::strcmp(buf, "true") == 0)) {
48 return true;
49 } else {
50 return false;
51 }
52}
53
54} // end anonymous namespace
55
56RSCompilerDriver::RSCompilerDriver() : mConfig(NULL), mCompiler() {
57 init::Initialize();
58 // Chain the symbol resolvers for BCC runtimes and RS runtimes.
59 mResolver.chainResolver(mBCCRuntime);
60 mResolver.chainResolver(mRSRuntime);
61}
62
63RSCompilerDriver::~RSCompilerDriver() {
64 delete mConfig;
65}
66
Shih-wei Liao170d4202012-04-25 04:07:09 -070067RSExecutable *
68RSCompilerDriver::loadScriptCache(const char *pOutputPath,
69 const RSInfo::DependencyTableTy &pDeps) {
70 android::StopWatch load_time("bcc: RSCompilerDriver::loadScriptCache time");
Zonr Chang64a2af12012-04-12 19:43:53 +080071 RSExecutable *result = NULL;
72
73 if (is_force_recompile())
74 return NULL;
75
76 //===--------------------------------------------------------------------===//
77 // Acquire the read lock for reading output object file.
78 //===--------------------------------------------------------------------===//
79 FileMutex<FileBase::kReadLock> read_output_mutex(pOutputPath);
80
81 if (read_output_mutex.hasError() || !read_output_mutex.lock()) {
Shih-wei Liao170d4202012-04-25 04:07:09 -070082 ALOGE("Unable to acquire the read lock for %s! (%s)", pOutputPath,
Zonr Chang64a2af12012-04-12 19:43:53 +080083 read_output_mutex.getErrorMessage().c_str());
84 return NULL;
85 }
86
87 //===--------------------------------------------------------------------===//
88 // Read the output object file.
89 //===--------------------------------------------------------------------===//
90 InputFile *output_file = new (std::nothrow) InputFile(pOutputPath);
91
92 if ((output_file == NULL) || output_file->hasError()) {
Shih-wei Liao170d4202012-04-25 04:07:09 -070093 ALOGE("Unable to open the %s for read! (%s)", pOutputPath,
Zonr Chang64a2af12012-04-12 19:43:53 +080094 output_file->getErrorMessage().c_str());
95 delete output_file;
96 return NULL;
97 }
98
99 //===--------------------------------------------------------------------===//
100 // Acquire the read lock on output_file for reading its RS info file.
101 //===--------------------------------------------------------------------===//
102 android::String8 info_path = RSInfo::GetPath(*output_file);
103
104 if (!output_file->lock()) {
105 ALOGE("Unable to acquire the read lock on %s for reading %s! (%s)",
Shih-wei Liao170d4202012-04-25 04:07:09 -0700106 pOutputPath, info_path.string(),
Zonr Chang64a2af12012-04-12 19:43:53 +0800107 output_file->getErrorMessage().c_str());
108 delete output_file;
109 return NULL;
110 }
111
112 //===---------------------------------------------------------------------===//
113 // Open and load the RS info file.
114 //===--------------------------------------------------------------------===//
115 InputFile info_file(info_path.string());
Shih-wei Liao170d4202012-04-25 04:07:09 -0700116 RSInfo *info = RSInfo::ReadFromFile(info_file, pDeps);
Zonr Chang64a2af12012-04-12 19:43:53 +0800117
118 // Release the lock on output_file.
119 output_file->unlock();
120
121 if (info == NULL) {
122 delete output_file;
123 return NULL;
124 }
125
126 //===--------------------------------------------------------------------===//
127 // Create the RSExecutable.
128 //===--------------------------------------------------------------------===//
129 result = RSExecutable::Create(*info, *output_file, mResolver);
130 if (result == NULL) {
131 delete output_file;
132 delete info;
133 return NULL;
134 }
135
Zonr Chang64a2af12012-04-12 19:43:53 +0800136 return result;
137}
138
139bool RSCompilerDriver::setupConfig(const RSScript &pScript) {
140 bool changed = false;
141
142 const llvm::CodeGenOpt::Level script_opt_level =
143 static_cast<llvm::CodeGenOpt::Level>(pScript.getOptimizationLevel());
144
145 if (mConfig != NULL) {
146 // Renderscript bitcode may have their optimization flag configuration
147 // different than the previous run of RS compilation.
148 if (mConfig->getOptimizationLevel() != script_opt_level) {
149 mConfig->setOptimizationLevel(script_opt_level);
150 changed = true;
151 }
152 } else {
153 // Haven't run the compiler ever.
154 mConfig = new (std::nothrow) DefaultCompilerConfig();
155 if (mConfig == NULL) {
156 // Return false since mConfig remains NULL and out-of-memory.
157 return false;
158 }
159 mConfig->setOptimizationLevel(script_opt_level);
160 changed = true;
161 }
162
163#if defined(DEFAULT_ARM_CODEGEN)
164 // NEON should be disable when full-precision floating point is required.
165 assert((pScript.getInfo() != NULL) && "NULL RS info!");
166 if (pScript.getInfo()->getFloatPrecisionRequirement() == RSInfo::Full) {
167 // Must be ARMCompilerConfig.
168 ARMCompilerConfig *arm_config = static_cast<ARMCompilerConfig *>(mConfig);
169 changed |= arm_config->enableNEON(/* pEnable */false);
170 }
171#endif
172
173 return changed;
174}
175
Shih-wei Liao170d4202012-04-25 04:07:09 -0700176RSExecutable *
177RSCompilerDriver::compileScript(RSScript &pScript,
178 const char *pOutputPath,
179 const RSInfo::DependencyTableTy &pDeps) {
180 android::StopWatch compile_time("bcc: RSCompilerDriver::compileScript time");
Zonr Chang64a2af12012-04-12 19:43:53 +0800181 RSExecutable *result = NULL;
182 RSInfo *info = NULL;
183
184 //===--------------------------------------------------------------------===//
185 // Extract RS-specific information from source bitcode.
186 //===--------------------------------------------------------------------===//
187 // RS info may contains configuration (such as #optimization_level) to the
188 // compiler therefore it should be extracted before compilation.
Shih-wei Liao170d4202012-04-25 04:07:09 -0700189 info = RSInfo::ExtractFromSource(pScript.getSource(), pDeps);
Zonr Chang64a2af12012-04-12 19:43:53 +0800190 if (info == NULL) {
191 return NULL;
192 }
193
194 //===--------------------------------------------------------------------===//
195 // Associate script with its info
196 //===--------------------------------------------------------------------===//
197 // This is required since RS compiler may need information in the info file
198 // to do some transformation (e.g., expand foreach-able function.)
199 pScript.setInfo(info);
200
201 //===--------------------------------------------------------------------===//
202 // Acquire the write lock for writing output object file.
203 //===--------------------------------------------------------------------===//
204 FileMutex<FileBase::kWriteLock> write_output_mutex(pOutputPath);
205
206 if (write_output_mutex.hasError() || !write_output_mutex.lock()) {
207 ALOGE("Unable to acquire the lock for writing %s! (%s)",
Shih-wei Liao170d4202012-04-25 04:07:09 -0700208 pOutputPath, write_output_mutex.getErrorMessage().c_str());
Zonr Chang64a2af12012-04-12 19:43:53 +0800209 return NULL;
210 }
211
212 //===--------------------------------------------------------------------===//
213 // Open the output file for write.
214 //===--------------------------------------------------------------------===//
215 OutputFile *output_file = new (std::nothrow) OutputFile(pOutputPath);
216
217 if ((output_file == NULL) || output_file->hasError()) {
Shih-wei Liao170d4202012-04-25 04:07:09 -0700218 ALOGE("Unable to open the %s for write! (%s)", pOutputPath,
Zonr Chang64a2af12012-04-12 19:43:53 +0800219 output_file->getErrorMessage().c_str());
220 delete info;
221 delete output_file;
222 return NULL;
223 }
224
225 //===--------------------------------------------------------------------===//
226 // Setup the config to the compiler.
227 //===--------------------------------------------------------------------===//
228 bool compiler_need_reconfigure = setupConfig(pScript);
229
230 if (mConfig == NULL) {
Shih-wei Liao170d4202012-04-25 04:07:09 -0700231 ALOGE("Failed to setup config for RS compiler to compile %s!", pOutputPath);
Zonr Chang64a2af12012-04-12 19:43:53 +0800232 delete info;
233 delete output_file;
234 return NULL;
235 }
236
237 // Compiler need to re-config if it's haven't run the config() yet or the
238 // configuration it referenced is changed.
239 if (compiler_need_reconfigure) {
240 Compiler::ErrorCode err = mCompiler.config(*mConfig);
241 if (err != Compiler::kSuccess) {
Shih-wei Liao170d4202012-04-25 04:07:09 -0700242 ALOGE("Failed to config the RS compiler for %s! (%s)",pOutputPath,
Zonr Chang64a2af12012-04-12 19:43:53 +0800243 Compiler::GetErrorString(err));
244 delete info;
245 delete output_file;
246 return NULL;
247 }
248 }
249
250 //===--------------------------------------------------------------------===//
251 // Run the compiler.
252 //===--------------------------------------------------------------------===//
253 Compiler::ErrorCode compile_result = mCompiler.compile(pScript, *output_file);
254 if (compile_result != Compiler::kSuccess) {
Shih-wei Liao170d4202012-04-25 04:07:09 -0700255 ALOGE("Unable to compile the source to file %s! (%s)", pOutputPath,
Zonr Chang64a2af12012-04-12 19:43:53 +0800256 Compiler::GetErrorString(compile_result));
257 delete info;
258 delete output_file;
259 return NULL;
260 }
261
262 //===--------------------------------------------------------------------===//
263 // Create the RSExecutable.
264 //===--------------------------------------------------------------------===//
265 result = RSExecutable::Create(*info, *output_file, mResolver);
266 if (result == NULL) {
267 delete info;
268 delete output_file;
269 return NULL;
270 }
271
Zonr Chang64a2af12012-04-12 19:43:53 +0800272 //===--------------------------------------------------------------------===//
273 // Write out the RS info file.
274 //===--------------------------------------------------------------------===//
275 // Note that write failure only results in a warning since the source is
276 // successfully compiled and loaded.
277 if (!result->syncInfo(/* pForce */true)) {
278 ALOGW("%s was successfully compiled and loaded but its RS info file failed "
Shih-wei Liao170d4202012-04-25 04:07:09 -0700279 "to write out!", pOutputPath);
Zonr Chang64a2af12012-04-12 19:43:53 +0800280 }
281
282 return result;
283}
284
Shih-wei Liao170d4202012-04-25 04:07:09 -0700285RSExecutable *RSCompilerDriver::build(BCCContext &pContext,
286 const char *pCacheDir,
287 const char *pResName,
288 const char *pBitcode,
289 size_t pBitcodeSize) {
290 android::StopWatch build_time("bcc: RSCompilerDriver::build time");
291 //===--------------------------------------------------------------------===//
292 // Check parameters.
293 //===--------------------------------------------------------------------===//
294 if ((pCacheDir == NULL) || (pResName == NULL)) {
295 ALOGE("Invalid parameter passed to RSCompilerDriver::build()! (cache dir: "
296 "%s, resource name: %s)", ((pCacheDir) ? pCacheDir : "(null)"),
297 ((pResName) ? pResName : "(null)"));
298 return NULL;
299 }
300
301 if ((pBitcode == NULL) || (pBitcodeSize <= 0)) {
302 ALOGE("No bitcode supplied! (bitcode: %p, size of bitcode: %u)",
303 pBitcode, static_cast<unsigned>(pBitcodeSize));
304 return NULL;
305 }
306
307 //===--------------------------------------------------------------------===//
308 // Prepare dependency information.
309 //===--------------------------------------------------------------------===//
310 RSInfo::DependencyTableTy dep_info;
311 uint8_t bitcode_sha1[20];
312 Sha1Util::GetSHA1DigestFromBuffer(bitcode_sha1, pBitcode, pBitcodeSize);
313 dep_info.push(std::make_pair(pResName, bitcode_sha1));
314
315 //===--------------------------------------------------------------------===//
316 // Construct output path.
317 //===--------------------------------------------------------------------===//
318 llvm::sys::Path output_path(pCacheDir);
319
320 // {pCacheDir}/{pResName}
321 if (!output_path.appendComponent(pResName)) {
322 ALOGE("Failed to construct output path %s/%s!", pCacheDir, pResName);
323 return NULL;
324 }
325
326 // {pCacheDir}/{pResName}.o
327 output_path.appendSuffix("o");
328
329 //===--------------------------------------------------------------------===//
330 // Load cache.
331 //===--------------------------------------------------------------------===//
332 RSExecutable *result = loadScriptCache(output_path.c_str(), dep_info);
Zonr Chang64a2af12012-04-12 19:43:53 +0800333
334 if (result != NULL) {
335 // Cache hit
336 return result;
337 }
338
Shih-wei Liao170d4202012-04-25 04:07:09 -0700339 //===--------------------------------------------------------------------===//
340 // Load the bitcode and create script.
341 //===--------------------------------------------------------------------===//
342 Source *source = Source::CreateFromBuffer(pContext, pResName,
343 pBitcode, pBitcodeSize);
344 if (source == NULL) {
345 return NULL;
346 }
347
348 RSScript *script = new (std::nothrow) RSScript(*source);
349 if (script == NULL) {
350 ALOGE("Out of memory when create Script object for '%s'! (output: %s)",
351 pResName, output_path.c_str());
352 delete source;
353 return NULL;
354 }
355
356 // Link RS script with RenderScript runtime.
357 if (!RSScript::LinkRuntime(*script)) {
358 ALOGE("Failed to link script '%s' with RenderScript runtime!", pResName);
359 delete script;
360 return NULL;
361 }
362
363 // Read information from bitcode wrapper.
364 bcinfo::BitcodeWrapper wrapper(pBitcode, pBitcodeSize);
365 script->setCompilerVersion(wrapper.getCompilerVersion());
366 script->setOptimizationLevel(static_cast<RSScript::OptimizationLevel>(
367 wrapper.getOptimizationLevel()));
368
369 //===--------------------------------------------------------------------===//
370 // Compile the script
371 //===--------------------------------------------------------------------===//
372 result = compileScript(*script, output_path.c_str(), dep_info);
373
374 // Script is no longer used. Free it to get more memory.
375 delete script;
376
377 if (result == NULL) {
378 return NULL;
379 }
380
381 return result;
Zonr Chang64a2af12012-04-12 19:43:53 +0800382}