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