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