RSCompilerDriver.cpp revision d0304d59215f8b065332facf6db11d2aec0eb97c
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
81  llvm::sys::Path output_path(pCacheDir);
82
83  // {pCacheDir}/{pResName}
84  if (!output_path.appendComponent(pResName)) {
85    ALOGE("Failed to construct output path %s/%s!", pCacheDir, pResName);
86    return NULL;
87  }
88
89  // {pCacheDir}/{pResName}.o
90  output_path.appendSuffix("o");
91
92  dep_info.push(std::make_pair(output_path.c_str(), bitcode_sha1));
93
94  //===--------------------------------------------------------------------===//
95  // Acquire the read lock for reading the Script object file.
96  //===--------------------------------------------------------------------===//
97  FileMutex<FileBase::kReadLock> read_output_mutex(output_path.c_str());
98
99  if (read_output_mutex.hasError() || !read_output_mutex.lock()) {
100    ALOGE("Unable to acquire the read lock for %s! (%s)", output_path.c_str(),
101          read_output_mutex.getErrorMessage().c_str());
102    return NULL;
103  }
104
105  //===--------------------------------------------------------------------===//
106  // Read the output object file.
107  //===--------------------------------------------------------------------===//
108  InputFile *object_file = new (std::nothrow) InputFile(output_path.c_str());
109
110  if ((object_file == NULL) || object_file->hasError()) {
111      //      ALOGE("Unable to open the %s for read! (%s)", output_path.c_str(),
112      //            object_file->getErrorMessage().c_str());
113    delete object_file;
114    return NULL;
115  }
116
117  //===--------------------------------------------------------------------===//
118  // Acquire the read lock on object_file for reading its RS info file.
119  //===--------------------------------------------------------------------===//
120  android::String8 info_path = RSInfo::GetPath(output_path.c_str());
121
122  if (!object_file->lock()) {
123    ALOGE("Unable to acquire the read lock on %s for reading %s! (%s)",
124          output_path.c_str(), info_path.string(),
125          object_file->getErrorMessage().c_str());
126    delete object_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, dep_info);
135
136  // Release the lock on object_file.
137  object_file->unlock();
138
139  if (info == NULL) {
140    delete object_file;
141    return NULL;
142  }
143
144  //===--------------------------------------------------------------------===//
145  // Create the RSExecutable.
146  //===--------------------------------------------------------------------===//
147  RSExecutable *result = RSExecutable::Create(*info, *object_file, mResolver);
148  if (result == NULL) {
149    delete object_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
194Compiler::ErrorCode
195RSCompilerDriver::compileScript(RSScript &pScript,
196                                const char* pScriptName,
197                                const char *pOutputPath,
198                                const char *pRuntimePath,
199                                const RSInfo::DependencyTableTy &pDeps,
200                                bool pSkipLoad, bool pDumpIR) {
201  //android::StopWatch compile_time("bcc: RSCompilerDriver::compileScript time");
202  RSInfo *info = NULL;
203
204  //===--------------------------------------------------------------------===//
205  // Extract RS-specific information from source bitcode.
206  //===--------------------------------------------------------------------===//
207  // RS info may contains configuration (such as #optimization_level) to the
208  // compiler therefore it should be extracted before compilation.
209  info = RSInfo::ExtractFromSource(pScript.getSource(), pDeps);
210  if (info == NULL) {
211    return Compiler::kErrInvalidSource;
212  }
213
214  //===--------------------------------------------------------------------===//
215  // Associate script with its info
216  //===--------------------------------------------------------------------===//
217  // This is required since RS compiler may need information in the info file
218  // to do some transformation (e.g., expand foreach-able function.)
219  pScript.setInfo(info);
220
221  //===--------------------------------------------------------------------===//
222  // Link RS script with Renderscript runtime.
223  //===--------------------------------------------------------------------===//
224  if (!RSScript::LinkRuntime(pScript, pRuntimePath)) {
225    ALOGE("Failed to link script '%s' with Renderscript runtime!", pScriptName);
226    return Compiler::kErrInvalidSource;
227  }
228
229  {
230    // Acquire the write lock for writing output object file.
231    FileMutex<FileBase::kWriteLock> write_output_mutex(pOutputPath);
232
233    if (write_output_mutex.hasError() || !write_output_mutex.lock()) {
234      ALOGE("Unable to acquire the lock for writing %s! (%s)",
235            pOutputPath, write_output_mutex.getErrorMessage().c_str());
236      return Compiler::kErrInvalidSource;
237    }
238
239    // Open the output file for write.
240    OutputFile output_file(pOutputPath, FileBase::kTruncate);
241
242    if (output_file.hasError()) {
243        ALOGE("Unable to open %s for write! (%s)", pOutputPath,
244              output_file.getErrorMessage().c_str());
245      return Compiler::kErrInvalidSource;
246    }
247
248    // Setup the config to the compiler.
249    bool compiler_need_reconfigure = setupConfig(pScript);
250
251    if (mConfig == NULL) {
252      ALOGE("Failed to setup config for RS compiler to compile %s!",
253            pOutputPath);
254      return Compiler::kErrInvalidSource;
255    }
256
257    if (compiler_need_reconfigure) {
258      Compiler::ErrorCode err = mCompiler.config(*mConfig);
259      if (err != Compiler::kSuccess) {
260        ALOGE("Failed to config the RS compiler for %s! (%s)",pOutputPath,
261              Compiler::GetErrorString(err));
262        return Compiler::kErrInvalidSource;
263      }
264    }
265
266    // Run the compiler.
267    Compiler::ErrorCode compile_result = mCompiler.compile(pScript, output_file);
268
269    if (compile_result != Compiler::kSuccess) {
270      ALOGE("Unable to compile the source to file %s! (%s)", pOutputPath,
271            Compiler::GetErrorString(compile_result));
272      return Compiler::kErrInvalidSource;
273    }
274  }
275
276  // No need to produce an RSExecutable in this case.
277  // TODO: Error handling in this case is nonexistent.
278  if (pSkipLoad) {
279    return Compiler::kSuccess;
280  }
281
282  {
283    android::String8 info_path = RSInfo::GetPath(pOutputPath);
284    OutputFile info_file(info_path.string(), FileBase::kTruncate);
285
286    if (info_file.hasError()) {
287      ALOGE("Failed to open the info file %s for write! (%s)",
288            info_path.string(), info_file.getErrorMessage().c_str());
289      return Compiler::kErrInvalidSource;
290    }
291
292    FileMutex<FileBase::kWriteLock> write_info_mutex(info_path.string());
293    if (write_info_mutex.hasError() || !write_info_mutex.lock()) {
294      ALOGE("Unable to acquire the lock for writing %s! (%s)",
295            info_path.string(), write_info_mutex.getErrorMessage().c_str());
296      return Compiler::kErrInvalidSource;
297    }
298
299    // Perform the write.
300    if (!info->write(info_file)) {
301      ALOGE("Failed to sync the RS info file %s!", info_path.string());
302      return Compiler::kErrInvalidSource;
303    }
304  }
305
306  if (pDumpIR) {
307    android::String8 path(pOutputPath);
308    path.append(".ll");
309    OutputFile ir_file(path.string(), FileBase::kTruncate);
310    llvm::Module &module = pScript.getSource().getModule();
311    llvm::raw_fd_ostream &out = *ir_file.dup();
312    out << module;
313    ir_file.close();
314  }
315
316  return Compiler::kSuccess;
317}
318
319bool RSCompilerDriver::build(BCCContext &pContext,
320                             const char *pCacheDir,
321                             const char *pResName,
322                             const char *pBitcode,
323                             size_t pBitcodeSize,
324                             const char *pRuntimePath,
325                             RSLinkRuntimeCallback pLinkRuntimeCallback,
326                             bool pDumpIR) {
327    //  android::StopWatch build_time("bcc: RSCompilerDriver::build time");
328  //===--------------------------------------------------------------------===//
329  // Check parameters.
330  //===--------------------------------------------------------------------===//
331  if ((pCacheDir == NULL) || (pResName == NULL)) {
332    ALOGE("Invalid parameter passed to RSCompilerDriver::build()! (cache dir: "
333          "%s, resource name: %s)", ((pCacheDir) ? pCacheDir : "(null)"),
334                                    ((pResName) ? pResName : "(null)"));
335    return false;
336  }
337
338  if ((pBitcode == NULL) || (pBitcodeSize <= 0)) {
339    ALOGE("No bitcode supplied! (bitcode: %p, size of bitcode: %u)",
340          pBitcode, static_cast<unsigned>(pBitcodeSize));
341    return false;
342  }
343
344  //===--------------------------------------------------------------------===//
345  // Prepare dependency information.
346  //===--------------------------------------------------------------------===//
347  RSInfo::DependencyTableTy dep_info;
348  uint8_t bitcode_sha1[20];
349  Sha1Util::GetSHA1DigestFromBuffer(bitcode_sha1, pBitcode, pBitcodeSize);
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  dep_info.push(std::make_pair(output_path.c_str(), bitcode_sha1));
366
367  //===--------------------------------------------------------------------===//
368  // Load the bitcode and create script.
369  //===--------------------------------------------------------------------===//
370  Source *source = Source::CreateFromBuffer(pContext, pResName,
371                                            pBitcode, pBitcodeSize);
372  if (source == NULL) {
373    return false;
374  }
375
376  RSScript *script = new (std::nothrow) RSScript(*source);
377  if (script == NULL) {
378    ALOGE("Out of memory when create Script object for '%s'! (output: %s)",
379          pResName, output_path.c_str());
380    delete source;
381    return false;
382  }
383
384  script->setLinkRuntimeCallback(pLinkRuntimeCallback);
385
386  // Read information from bitcode wrapper.
387  bcinfo::BitcodeWrapper wrapper(pBitcode, pBitcodeSize);
388  script->setCompilerVersion(wrapper.getCompilerVersion());
389  script->setOptimizationLevel(static_cast<RSScript::OptimizationLevel>(
390                                   wrapper.getOptimizationLevel()));
391
392  //===--------------------------------------------------------------------===//
393  // Compile the script
394  //===--------------------------------------------------------------------===//
395  Compiler::ErrorCode status = compileScript(*script, pResName,
396                                             output_path.c_str(),
397                                             pRuntimePath, dep_info, false,
398                                             pDumpIR);
399
400  // Script is no longer used. Free it to get more memory.
401  delete script;
402
403  if (status != Compiler::kSuccess) {
404    return false;
405  }
406
407  return true;
408}
409
410
411bool RSCompilerDriver::build(RSScript &pScript, const char *pOut,
412                             const char *pRuntimePath) {
413  RSInfo::DependencyTableTy dep_info;
414  RSInfo *info = RSInfo::ExtractFromSource(pScript.getSource(), dep_info);
415  if (info == NULL) {
416    return false;
417  }
418  pScript.setInfo(info);
419
420  // Embed the info string directly in the ELF, since this path is for an
421  // offline (host) compilation.
422  pScript.setEmbedInfo(true);
423
424  Compiler::ErrorCode status = compileScript(pScript, pOut, pOut, pRuntimePath,
425                                             dep_info, true);
426  if (status != Compiler::kSuccess) {
427    return false;
428  }
429
430  return true;
431}
432
433