RSCompilerDriver.cpp revision b81d697ec617be24494b622a3532f1c465264415
1/*
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
17#include "bcc/Renderscript/RSCompilerDriver.h"
18
19#include <llvm/Support/Path.h>
20
21#include "bcinfo/BitcodeWrapper.h"
22
23#include "bcc/Renderscript/RSExecutable.h"
24#include "bcc/Renderscript/RSScript.h"
25#include "bcc/Support/CompilerConfig.h"
26#include "bcc/Support/TargetCompilerConfigs.h"
27#include "bcc/Source.h"
28#include "bcc/Support/FileMutex.h"
29#include "bcc/Support/Log.h"
30#include "bcc/Support/InputFile.h"
31#include "bcc/Support/Initialization.h"
32#include "bcc/Support/Sha1Util.h"
33#include "bcc/Support/OutputFile.h"
34
35#ifdef HAVE_ANDROID_OS
36#include <cutils/properties.h>
37#endif
38#include <utils/String8.h>
39#include <utils/StopWatch.h>
40
41using namespace bcc;
42
43namespace {
44
45bool is_force_recompile() {
46#ifndef HAVE_ANDROID_OS
47  return false;
48#else
49  char buf[PROPERTY_VALUE_MAX];
50
51  // Re-compile if floating point precision has been overridden.
52  property_get("debug.rs.precision", buf, "");
53  if (buf[0] != '\0') {
54    return true;
55  }
56
57  // Re-compile if debug.rs.forcerecompile is set.
58  property_get("debug.rs.forcerecompile", buf, "0");
59  if ((::strcmp(buf, "1") == 0) || (::strcmp(buf, "true") == 0)) {
60    return true;
61  } else {
62    return false;
63  }
64#endif
65}
66
67} // end anonymous namespace
68
69RSCompilerDriver::RSCompilerDriver(bool pUseCompilerRT) :
70    mConfig(NULL), mCompiler(), mCompilerRuntime(NULL), mDebugContext(false) {
71  init::Initialize();
72  // Chain the symbol resolvers for compiler_rt and RS runtimes.
73  if (pUseCompilerRT) {
74    mCompilerRuntime = new CompilerRTSymbolResolver();
75    mResolver.chainResolver(*mCompilerRuntime);
76  }
77  mResolver.chainResolver(mRSRuntime);
78}
79
80RSCompilerDriver::~RSCompilerDriver() {
81  delete mCompilerRuntime;
82  delete mConfig;
83}
84
85RSExecutable *
86RSCompilerDriver::loadScriptCache(const char *pOutputPath,
87                                  const RSInfo::DependencyTableTy &pDeps) {
88  //android::StopWatch load_time("bcc: RSCompilerDriver::loadScriptCache time");
89  RSExecutable *result = NULL;
90
91  if (is_force_recompile())
92    return NULL;
93
94  //===--------------------------------------------------------------------===//
95  // Acquire the read lock for reading output object file.
96  //===--------------------------------------------------------------------===//
97  FileMutex<FileBase::kReadLock> read_output_mutex(pOutputPath);
98
99  if (read_output_mutex.hasError() || !read_output_mutex.lock()) {
100    ALOGE("Unable to acquire the read lock for %s! (%s)", pOutputPath,
101          read_output_mutex.getErrorMessage().c_str());
102    return NULL;
103  }
104
105  //===--------------------------------------------------------------------===//
106  // Read the output object file.
107  //===--------------------------------------------------------------------===//
108  InputFile *output_file = new (std::nothrow) InputFile(pOutputPath);
109
110  if ((output_file == NULL) || output_file->hasError()) {
111      //      ALOGE("Unable to open the %s for read! (%s)", pOutputPath,
112      //            output_file->getErrorMessage().c_str());
113    delete output_file;
114    return NULL;
115  }
116
117  //===--------------------------------------------------------------------===//
118  // Acquire the read lock on output_file for reading its RS info file.
119  //===--------------------------------------------------------------------===//
120  android::String8 info_path = RSInfo::GetPath(*output_file);
121
122  if (!output_file->lock()) {
123    ALOGE("Unable to acquire the read lock on %s for reading %s! (%s)",
124          pOutputPath, info_path.string(),
125          output_file->getErrorMessage().c_str());
126    delete output_file;
127    return NULL;
128  }
129
130 //===---------------------------------------------------------------------===//
131  // Open and load the RS info file.
132  //===--------------------------------------------------------------------===//
133  InputFile info_file(info_path.string());
134  RSInfo *info = RSInfo::ReadFromFile(info_file, pDeps);
135
136  // Release the lock on output_file.
137  output_file->unlock();
138
139  if (info == NULL) {
140    delete output_file;
141    return NULL;
142  }
143
144  //===--------------------------------------------------------------------===//
145  // Create the RSExecutable.
146  //===--------------------------------------------------------------------===//
147  result = RSExecutable::Create(*info, *output_file, mResolver);
148  if (result == NULL) {
149    delete output_file;
150    delete info;
151    return NULL;
152  }
153
154  return result;
155}
156
157bool RSCompilerDriver::setupConfig(const RSScript &pScript) {
158  bool changed = false;
159
160  const llvm::CodeGenOpt::Level script_opt_level =
161      static_cast<llvm::CodeGenOpt::Level>(pScript.getOptimizationLevel());
162
163  if (mConfig != NULL) {
164    // Renderscript bitcode may have their optimization flag configuration
165    // different than the previous run of RS compilation.
166    if (mConfig->getOptimizationLevel() != script_opt_level) {
167      mConfig->setOptimizationLevel(script_opt_level);
168      changed = true;
169    }
170  } else {
171    // Haven't run the compiler ever.
172    mConfig = new (std::nothrow) DefaultCompilerConfig();
173    if (mConfig == NULL) {
174      // Return false since mConfig remains NULL and out-of-memory.
175      return false;
176    }
177    mConfig->setOptimizationLevel(script_opt_level);
178    changed = true;
179  }
180
181#if defined(DEFAULT_ARM_CODEGEN)
182  // NEON should be disable when full-precision floating point is required.
183  assert((pScript.getInfo() != NULL) && "NULL RS info!");
184  if (pScript.getInfo()->getFloatPrecisionRequirement() == RSInfo::FP_Full) {
185    // Must be ARMCompilerConfig.
186    ARMCompilerConfig *arm_config = static_cast<ARMCompilerConfig *>(mConfig);
187    changed |= arm_config->enableNEON(/* pEnable */false);
188  }
189#endif
190
191  return changed;
192}
193
194RSExecutable *
195RSCompilerDriver::compileScript(RSScript &pScript,
196                                const char* pScriptName,
197                                const char *pOutputPath,
198                                const char *pRuntimePath,
199                                const RSInfo::DependencyTableTy &pDeps,
200                                bool pSkipLoad) {
201  //android::StopWatch compile_time("bcc: RSCompilerDriver::compileScript time");
202  RSExecutable *result = NULL;
203  RSInfo *info = NULL;
204
205  //===--------------------------------------------------------------------===//
206  // Extract RS-specific information from source bitcode.
207  //===--------------------------------------------------------------------===//
208  // RS info may contains configuration (such as #optimization_level) to the
209  // compiler therefore it should be extracted before compilation.
210  info = RSInfo::ExtractFromSource(pScript.getSource(), pDeps);
211  if (info == NULL) {
212    return NULL;
213  }
214
215  //===--------------------------------------------------------------------===//
216  // Associate script with its info
217  //===--------------------------------------------------------------------===//
218  // This is required since RS compiler may need information in the info file
219  // to do some transformation (e.g., expand foreach-able function.)
220  pScript.setInfo(info);
221
222  //===--------------------------------------------------------------------===//
223  // Link RS script with Renderscript runtime.
224  //===--------------------------------------------------------------------===//
225  if (!RSScript::LinkRuntime(pScript, pRuntimePath)) {
226    ALOGE("Failed to link script '%s' with Renderscript runtime!", pScriptName);
227    return NULL;
228  }
229
230  //===--------------------------------------------------------------------===//
231  // Acquire the write lock for writing output object file.
232  //===--------------------------------------------------------------------===//
233  FileMutex<FileBase::kWriteLock> write_output_mutex(pOutputPath);
234
235  if (write_output_mutex.hasError() || !write_output_mutex.lock()) {
236    ALOGE("Unable to acquire the lock for writing %s! (%s)",
237          pOutputPath, write_output_mutex.getErrorMessage().c_str());
238    return NULL;
239  }
240
241  //===--------------------------------------------------------------------===//
242  // Open the output file for write.
243  //===--------------------------------------------------------------------===//
244  unsigned flags = FileBase::kTruncate;
245  if (mDebugContext) {
246    // Delete the cache file when we finish up under a debug context.
247    flags |= FileBase::kDeleteOnClose;
248  }
249  OutputFile *output_file = new (std::nothrow) OutputFile(pOutputPath, flags);
250
251  if ((output_file == NULL) || output_file->hasError()) {
252      ALOGE("Unable to open %s for write! (%s)", pOutputPath,
253            output_file->getErrorMessage().c_str());
254    delete info;
255    delete output_file;
256    return NULL;
257  }
258
259  //===--------------------------------------------------------------------===//
260  // Setup the config to the compiler.
261  //===--------------------------------------------------------------------===//
262  bool compiler_need_reconfigure = setupConfig(pScript);
263
264  if (mConfig == NULL) {
265    ALOGE("Failed to setup config for RS compiler to compile %s!", pOutputPath);
266    delete info;
267    delete output_file;
268    return NULL;
269  }
270
271  // Compiler need to re-config if it's haven't run the config() yet or the
272  // configuration it referenced is changed.
273  if (compiler_need_reconfigure) {
274    Compiler::ErrorCode err = mCompiler.config(*mConfig);
275    if (err != Compiler::kSuccess) {
276      ALOGE("Failed to config the RS compiler for %s! (%s)",pOutputPath,
277            Compiler::GetErrorString(err));
278      delete info;
279      delete output_file;
280      return NULL;
281    }
282  }
283
284  //===--------------------------------------------------------------------===//
285  // Run the compiler.
286  //===--------------------------------------------------------------------===//
287  Compiler::ErrorCode compile_result = mCompiler.compile(pScript, *output_file);
288  if (compile_result != Compiler::kSuccess) {
289    ALOGE("Unable to compile the source to file %s! (%s)", pOutputPath,
290          Compiler::GetErrorString(compile_result));
291    delete info;
292    delete output_file;
293    return NULL;
294  }
295
296  // No need to produce an RSExecutable in this case.
297  // TODO: Error handling in this case is nonexistent.
298  if (pSkipLoad) {
299    return NULL;
300  }
301
302  //===--------------------------------------------------------------------===//
303  // Create the RSExecutable.
304  //===--------------------------------------------------------------------===//
305  result = RSExecutable::Create(*info, *output_file, mResolver);
306  if (result == NULL) {
307    delete info;
308    delete output_file;
309    return NULL;
310  }
311
312  //===--------------------------------------------------------------------===//
313  // Dump the disassembly for debug when possible.
314  //===--------------------------------------------------------------------===//
315#if USE_DISASSEMBLER
316  OutputFile *disassembly_output =
317      new (std::nothrow) OutputFile(DEBUG_DISASSEMBLER_FILE,
318                                    FileBase::kAppend);
319
320  if (disassembly_output != NULL) {
321    result->dumpDisassembly(*disassembly_output);
322    delete disassembly_output;
323  }
324#endif
325
326  //===--------------------------------------------------------------------===//
327  // Write out the RS info file.
328  //===--------------------------------------------------------------------===//
329  // Note that write failure only results in a warning since the source is
330  // successfully compiled and loaded.
331  if (!result->syncInfo(/* pForce */true)) {
332    ALOGW("%s was successfully compiled and loaded but its RS info file failed "
333          "to write out!", pOutputPath);
334  }
335
336  return result;
337}
338
339RSExecutable *RSCompilerDriver::build(BCCContext &pContext,
340                                      const char *pCacheDir,
341                                      const char *pResName,
342                                      const char *pBitcode,
343                                      size_t pBitcodeSize,
344                                      const char *pRuntimePath,
345                                      RSLinkRuntimeCallback pLinkRuntimeCallback) {
346    //  android::StopWatch build_time("bcc: RSCompilerDriver::build time");
347  //===--------------------------------------------------------------------===//
348  // Check parameters.
349  //===--------------------------------------------------------------------===//
350  if ((pCacheDir == NULL) || (pResName == NULL)) {
351    ALOGE("Invalid parameter passed to RSCompilerDriver::build()! (cache dir: "
352          "%s, resource name: %s)", ((pCacheDir) ? pCacheDir : "(null)"),
353                                    ((pResName) ? pResName : "(null)"));
354    return NULL;
355  }
356
357  if ((pBitcode == NULL) || (pBitcodeSize <= 0)) {
358    ALOGE("No bitcode supplied! (bitcode: %p, size of bitcode: %u)",
359          pBitcode, static_cast<unsigned>(pBitcodeSize));
360    return NULL;
361  }
362
363  //===--------------------------------------------------------------------===//
364  // Prepare dependency information.
365  //===--------------------------------------------------------------------===//
366  RSInfo::DependencyTableTy dep_info;
367  uint8_t bitcode_sha1[20];
368  Sha1Util::GetSHA1DigestFromBuffer(bitcode_sha1, pBitcode, pBitcodeSize);
369  dep_info.push(std::make_pair(pResName, bitcode_sha1));
370
371  //===--------------------------------------------------------------------===//
372  // Construct output path.
373  //===--------------------------------------------------------------------===//
374  llvm::sys::Path output_path(pCacheDir);
375
376  // {pCacheDir}/{pResName}
377  if (!output_path.appendComponent(pResName)) {
378    ALOGE("Failed to construct output path %s/%s!", pCacheDir, pResName);
379    return NULL;
380  }
381
382  // {pCacheDir}/{pResName}.o
383  output_path.appendSuffix("o");
384
385  //===--------------------------------------------------------------------===//
386  // Load cache.
387  //===--------------------------------------------------------------------===//
388  RSExecutable *result = NULL;
389
390  // Skip loading from the cache if we are using a debug context.
391  if (!mDebugContext) {
392    result = loadScriptCache(output_path.c_str(), dep_info);
393
394    if (result != NULL) {
395      // Cache hit
396      return result;
397    }
398  }
399
400  //===--------------------------------------------------------------------===//
401  // Load the bitcode and create script.
402  //===--------------------------------------------------------------------===//
403  Source *source = Source::CreateFromBuffer(pContext, pResName,
404                                            pBitcode, pBitcodeSize);
405  if (source == NULL) {
406    return NULL;
407  }
408
409  RSScript *script = new (std::nothrow) RSScript(*source);
410  if (script == NULL) {
411    ALOGE("Out of memory when create Script object for '%s'! (output: %s)",
412          pResName, output_path.c_str());
413    delete source;
414    return NULL;
415  }
416
417  script->setLinkRuntimeCallback(pLinkRuntimeCallback);
418
419  // Read information from bitcode wrapper.
420  bcinfo::BitcodeWrapper wrapper(pBitcode, pBitcodeSize);
421  script->setCompilerVersion(wrapper.getCompilerVersion());
422  script->setOptimizationLevel(static_cast<RSScript::OptimizationLevel>(
423                                   wrapper.getOptimizationLevel()));
424
425  //===--------------------------------------------------------------------===//
426  // Compile the script
427  //===--------------------------------------------------------------------===//
428  result = compileScript(*script, pResName, output_path.c_str(), pRuntimePath,
429                         dep_info, false);
430
431  // Script is no longer used. Free it to get more memory.
432  delete script;
433
434  if (result == NULL) {
435    return NULL;
436  }
437
438  return result;
439}
440
441
442RSExecutable *RSCompilerDriver::build(RSScript &pScript, const char *pOut,
443                                      const char *pRuntimePath) {
444  RSInfo::DependencyTableTy dep_info;
445  RSInfo *info = RSInfo::ExtractFromSource(pScript.getSource(), dep_info);
446  if (info == NULL) {
447    return NULL;
448  }
449  pScript.setInfo(info);
450
451  // Embed the info string directly in the ELF, since this path is for an
452  // offline (host) compilation.
453  pScript.setEmbedInfo(true);
454
455  RSExecutable *result = compileScript(pScript, pOut, pOut, pRuntimePath,
456                                       dep_info, true);
457  return result;
458}
459
460