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