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