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/Path.h>
22 #include <llvm/Support/raw_ostream.h>
23 
24 #include "bcinfo/BitcodeWrapper.h"
25 
26 #include "bcc/Compiler.h"
27 #include "bcc/Config/Config.h"
28 #include "bcc/Renderscript/RSExecutable.h"
29 #include "bcc/Renderscript/RSInfo.h"
30 #include "bcc/Renderscript/RSScript.h"
31 #include "bcc/Support/CompilerConfig.h"
32 #include "bcc/Source.h"
33 #include "bcc/Support/FileMutex.h"
34 #include "bcc/Support/Log.h"
35 #include "bcc/Support/InputFile.h"
36 #include "bcc/Support/Initialization.h"
37 #include "bcc/Support/Sha1Util.h"
38 #include "bcc/Support/OutputFile.h"
39 
40 #ifdef HAVE_ANDROID_OS
41 #include <cutils/properties.h>
42 #endif
43 #include <utils/String8.h>
44 #include <utils/StopWatch.h>
45 
46 using namespace bcc;
47 
48 // Get the build fingerprint of the Android device we are running on.
getBuildFingerPrint()49 static std::string getBuildFingerPrint() {
50 #ifdef HAVE_ANDROID_OS
51     char fingerprint[PROPERTY_VALUE_MAX];
52     property_get("ro.build.fingerprint", fingerprint, "");
53     return fingerprint;
54 #else
55     return "HostBuild";
56 #endif
57 }
58 
RSCompilerDriver(bool pUseCompilerRT)59 RSCompilerDriver::RSCompilerDriver(bool pUseCompilerRT) :
60     mConfig(NULL), mCompiler(), mDebugContext(false),
61     mLinkRuntimeCallback(NULL), mEnableGlobalMerge(true) {
62   init::Initialize();
63 }
64 
~RSCompilerDriver()65 RSCompilerDriver::~RSCompilerDriver() {
66   delete mConfig;
67 }
68 
loadScript(const char * pCacheDir,const char * pResName,const char * pBitcode,size_t pBitcodeSize,const char * expectedCompileCommandLine,SymbolResolverProxy & pResolver)69 RSExecutable* RSCompilerDriver::loadScript(const char* pCacheDir, const char* pResName,
70                                            const char* pBitcode, size_t pBitcodeSize,
71                                            const char* expectedCompileCommandLine,
72                                            SymbolResolverProxy& pResolver) {
73   // android::StopWatch load_time("bcc: RSCompilerDriver::loadScript time");
74   if ((pCacheDir == NULL) || (pResName == NULL)) {
75     ALOGE("Missing pCacheDir and/or pResName");
76     return NULL;
77   }
78 
79   if ((pBitcode == NULL) || (pBitcodeSize <= 0)) {
80     ALOGE("No bitcode supplied! (bitcode: %p, size of bitcode: %zu)",
81           pBitcode, pBitcodeSize);
82     return NULL;
83   }
84 
85   // {pCacheDir}/{pResName}.o
86   llvm::SmallString<80> output_path(pCacheDir);
87   llvm::sys::path::append(output_path, pResName);
88   llvm::sys::path::replace_extension(output_path, ".o");
89 
90   //===--------------------------------------------------------------------===//
91   // Acquire the read lock for reading the Script object file.
92   //===--------------------------------------------------------------------===//
93   FileMutex<FileBase::kReadLock> read_output_mutex(output_path.c_str());
94 
95   if (read_output_mutex.hasError() || !read_output_mutex.lock()) {
96     ALOGE("Unable to acquire the read lock for %s! (%s)", output_path.c_str(),
97           read_output_mutex.getErrorMessage().c_str());
98     return NULL;
99   }
100 
101   //===--------------------------------------------------------------------===//
102   // Read the output object file.
103   //===--------------------------------------------------------------------===//
104   InputFile *object_file = new (std::nothrow) InputFile(output_path.c_str());
105 
106   if ((object_file == NULL) || object_file->hasError()) {
107       //      ALOGE("Unable to open the %s for read! (%s)", output_path.c_str(),
108       //            object_file->getErrorMessage().c_str());
109     delete object_file;
110     return NULL;
111   }
112 
113   //===--------------------------------------------------------------------===//
114   // Acquire the read lock on object_file for reading its RS info file.
115   //===--------------------------------------------------------------------===//
116   android::String8 info_path = RSInfo::GetPath(output_path.c_str());
117 
118   if (!object_file->lock()) {
119     ALOGE("Unable to acquire the read lock on %s for reading %s! (%s)",
120           output_path.c_str(), info_path.string(),
121           object_file->getErrorMessage().c_str());
122     delete object_file;
123     return NULL;
124   }
125 
126   //===---------------------------------------------------------------------===//
127   // Open and load the RS info file.
128   //===--------------------------------------------------------------------===//
129   InputFile info_file(info_path.string());
130   RSInfo *info = RSInfo::ReadFromFile(info_file);
131 
132   // Release the lock on object_file.
133   object_file->unlock();
134 
135   if (info == NULL) {
136     delete object_file;
137     return NULL;
138   }
139 
140   //===---------------------------------------------------------------------===//
141   // Check that the info in the RS info file is consistent we what we want.
142   //===--------------------------------------------------------------------===//
143 
144   uint8_t expectedSourceHash[SHA1_DIGEST_LENGTH];
145   Sha1Util::GetSHA1DigestFromBuffer(expectedSourceHash, pBitcode, pBitcodeSize);
146 
147   std::string expectedBuildFingerprint = getBuildFingerPrint();
148 
149   // If the info file contains different hash for the source than what we are
150   // looking for, bail.  Do the same if the command line used when compiling or the
151   // build fingerprint of Android has changed.  The compiled code found on disk is
152   // out of date and needs to be recompiled first.
153   if (!info->IsConsistent(output_path.c_str(), expectedSourceHash, expectedCompileCommandLine,
154                           expectedBuildFingerprint.c_str())) {
155       delete object_file;
156       delete info;
157       return NULL;
158   }
159 
160   //===--------------------------------------------------------------------===//
161   // Create the RSExecutable.
162   //===--------------------------------------------------------------------===//
163   RSExecutable *executable = RSExecutable::Create(*info, *object_file, pResolver);
164   if (executable == NULL) {
165     delete object_file;
166     delete info;
167     return NULL;
168   }
169 
170   return executable;
171 }
172 
173 #if defined(PROVIDE_ARM_CODEGEN)
174 extern llvm::cl::opt<bool> EnableGlobalMerge;
175 #endif
176 
setupConfig(const RSScript & pScript)177 bool RSCompilerDriver::setupConfig(const RSScript &pScript) {
178   bool changed = false;
179 
180   const llvm::CodeGenOpt::Level script_opt_level =
181       static_cast<llvm::CodeGenOpt::Level>(pScript.getOptimizationLevel());
182 
183 #if defined(PROVIDE_ARM_CODEGEN)
184   EnableGlobalMerge = mEnableGlobalMerge;
185 #endif
186 
187   if (mConfig != NULL) {
188     // Renderscript bitcode may have their optimization flag configuration
189     // different than the previous run of RS compilation.
190     if (mConfig->getOptimizationLevel() != script_opt_level) {
191       mConfig->setOptimizationLevel(script_opt_level);
192       changed = true;
193     }
194   } else {
195     // Haven't run the compiler ever.
196     mConfig = new (std::nothrow) CompilerConfig(DEFAULT_TARGET_TRIPLE_STRING);
197     if (mConfig == NULL) {
198       // Return false since mConfig remains NULL and out-of-memory.
199       return false;
200     }
201     mConfig->setOptimizationLevel(script_opt_level);
202     changed = true;
203   }
204 
205 #if defined(PROVIDE_ARM_CODEGEN)
206   assert((pScript.getInfo() != NULL) && "NULL RS info!");
207   bool script_full_prec = (pScript.getInfo()->getFloatPrecisionRequirement() ==
208                            RSInfo::FP_Full);
209   if (mConfig->getFullPrecision() != script_full_prec) {
210     mConfig->setFullPrecision(script_full_prec);
211     changed = true;
212   }
213 #endif
214 
215   return changed;
216 }
217 
compileScript(RSScript & pScript,const char * pScriptName,const char * pOutputPath,const char * pRuntimePath,const RSInfo::DependencyHashTy & pSourceHash,const char * compileCommandLineToEmbed,bool saveInfoFile,bool pDumpIR)218 Compiler::ErrorCode RSCompilerDriver::compileScript(RSScript& pScript, const char* pScriptName,
219                                                     const char* pOutputPath,
220                                                     const char* pRuntimePath,
221                                                     const RSInfo::DependencyHashTy& pSourceHash,
222                                                     const char* compileCommandLineToEmbed,
223                                                     bool saveInfoFile, bool pDumpIR) {
224   // android::StopWatch compile_time("bcc: RSCompilerDriver::compileScript time");
225   RSInfo *info = NULL;
226 
227   //===--------------------------------------------------------------------===//
228   // Extract RS-specific information from source bitcode.
229   //===--------------------------------------------------------------------===//
230   // RS info may contains configuration (such as #optimization_level) to the
231   // compiler therefore it should be extracted before compilation.
232   info = RSInfo::ExtractFromSource(pScript.getSource(), pSourceHash, compileCommandLineToEmbed,
233                                    getBuildFingerPrint().c_str());
234   if (info == NULL) {
235     return Compiler::kErrInvalidSource;
236   }
237 
238   //===--------------------------------------------------------------------===//
239   // Associate script with its info
240   //===--------------------------------------------------------------------===//
241   // This is required since RS compiler may need information in the info file
242   // to do some transformation (e.g., expand foreach-able function.)
243   pScript.setInfo(info);
244 
245   //===--------------------------------------------------------------------===//
246   // Link RS script with Renderscript runtime.
247   //===--------------------------------------------------------------------===//
248   if (!RSScript::LinkRuntime(pScript, pRuntimePath)) {
249     ALOGE("Failed to link script '%s' with Renderscript runtime!", pScriptName);
250     return Compiler::kErrInvalidSource;
251   }
252 
253   {
254     // FIXME(srhines): Windows compilation can't use locking like this, but
255     // we also don't need to worry about concurrent writers of the same file.
256 #ifndef USE_MINGW
257     //===------------------------------------------------------------------===//
258     // Acquire the write lock for writing output object file.
259     //===------------------------------------------------------------------===//
260     FileMutex<FileBase::kWriteLock> write_output_mutex(pOutputPath);
261 
262     if (write_output_mutex.hasError() || !write_output_mutex.lock()) {
263       ALOGE("Unable to acquire the lock for writing %s! (%s)",
264             pOutputPath, write_output_mutex.getErrorMessage().c_str());
265       return Compiler::kErrInvalidSource;
266     }
267 #endif
268 
269     // Open the output file for write.
270     OutputFile output_file(pOutputPath,
271                            FileBase::kTruncate | FileBase::kBinary);
272 
273     if (output_file.hasError()) {
274         ALOGE("Unable to open %s for write! (%s)", pOutputPath,
275               output_file.getErrorMessage().c_str());
276       return Compiler::kErrInvalidSource;
277     }
278 
279     // Setup the config to the compiler.
280     bool compiler_need_reconfigure = setupConfig(pScript);
281 
282     if (mConfig == NULL) {
283       ALOGE("Failed to setup config for RS compiler to compile %s!",
284             pOutputPath);
285       return Compiler::kErrInvalidSource;
286     }
287 
288     if (compiler_need_reconfigure) {
289       Compiler::ErrorCode err = mCompiler.config(*mConfig);
290       if (err != Compiler::kSuccess) {
291         ALOGE("Failed to config the RS compiler for %s! (%s)",pOutputPath,
292               Compiler::GetErrorString(err));
293         return Compiler::kErrInvalidSource;
294       }
295     }
296 
297     OutputFile *ir_file = NULL;
298     llvm::raw_fd_ostream *IRStream = NULL;
299     if (pDumpIR) {
300       android::String8 path(pOutputPath);
301       path.append(".ll");
302       ir_file = new OutputFile(path.string(), FileBase::kTruncate);
303       IRStream = ir_file->dup();
304     }
305 
306     // Run the compiler.
307     Compiler::ErrorCode compile_result = mCompiler.compile(pScript,
308                                                            output_file, IRStream);
309 
310     if (ir_file) {
311       ir_file->close();
312       delete ir_file;
313     }
314 
315     if (compile_result != Compiler::kSuccess) {
316       ALOGE("Unable to compile the source to file %s! (%s)", pOutputPath,
317             Compiler::GetErrorString(compile_result));
318       return Compiler::kErrInvalidSource;
319     }
320   }
321 
322   if (saveInfoFile) {
323     android::String8 info_path = RSInfo::GetPath(pOutputPath);
324     OutputFile info_file(info_path.string(), FileBase::kTruncate);
325 
326     if (info_file.hasError()) {
327       ALOGE("Failed to open the info file %s for write! (%s)",
328             info_path.string(), info_file.getErrorMessage().c_str());
329       return Compiler::kErrInvalidSource;
330     }
331 
332     FileMutex<FileBase::kWriteLock> write_info_mutex(info_path.string());
333     if (write_info_mutex.hasError() || !write_info_mutex.lock()) {
334       ALOGE("Unable to acquire the lock for writing %s! (%s)",
335             info_path.string(), write_info_mutex.getErrorMessage().c_str());
336       return Compiler::kErrInvalidSource;
337     }
338 
339     // Perform the write.
340     if (!info->write(info_file)) {
341       ALOGE("Failed to sync the RS info file %s!", info_path.string());
342       return Compiler::kErrInvalidSource;
343     }
344   }
345 
346   return Compiler::kSuccess;
347 }
348 
build(BCCContext & pContext,const char * pCacheDir,const char * pResName,const char * pBitcode,size_t pBitcodeSize,const char * commandLine,const char * pRuntimePath,RSLinkRuntimeCallback pLinkRuntimeCallback,bool pDumpIR)349 bool RSCompilerDriver::build(BCCContext &pContext,
350                              const char *pCacheDir,
351                              const char *pResName,
352                              const char *pBitcode,
353                              size_t pBitcodeSize,
354                              const char *commandLine,
355                              const char *pRuntimePath,
356                              RSLinkRuntimeCallback pLinkRuntimeCallback,
357                              bool pDumpIR) {
358     //  android::StopWatch build_time("bcc: RSCompilerDriver::build time");
359   //===--------------------------------------------------------------------===//
360   // Check parameters.
361   //===--------------------------------------------------------------------===//
362   if ((pCacheDir == NULL) || (pResName == NULL)) {
363     ALOGE("Invalid parameter passed to RSCompilerDriver::build()! (cache dir: "
364           "%s, resource name: %s)", ((pCacheDir) ? pCacheDir : "(null)"),
365                                     ((pResName) ? pResName : "(null)"));
366     return false;
367   }
368 
369   if ((pBitcode == NULL) || (pBitcodeSize <= 0)) {
370     ALOGE("No bitcode supplied! (bitcode: %p, size of bitcode: %u)",
371           pBitcode, static_cast<unsigned>(pBitcodeSize));
372     return false;
373   }
374 
375   //===--------------------------------------------------------------------===//
376   // Prepare dependency information.
377   //===--------------------------------------------------------------------===//
378   uint8_t bitcode_sha1[SHA1_DIGEST_LENGTH];
379   Sha1Util::GetSHA1DigestFromBuffer(bitcode_sha1, pBitcode, pBitcodeSize);
380 
381   //===--------------------------------------------------------------------===//
382   // Construct output path.
383   // {pCacheDir}/{pResName}.o
384   //===--------------------------------------------------------------------===//
385   llvm::SmallString<80> output_path(pCacheDir);
386   llvm::sys::path::append(output_path, pResName);
387   llvm::sys::path::replace_extension(output_path, ".o");
388 
389   //===--------------------------------------------------------------------===//
390   // Load the bitcode and create script.
391   //===--------------------------------------------------------------------===//
392   Source *source = Source::CreateFromBuffer(pContext, pResName,
393                                             pBitcode, pBitcodeSize);
394   if (source == NULL) {
395     return false;
396   }
397 
398   RSScript script(*source);
399   if (pLinkRuntimeCallback) {
400     setLinkRuntimeCallback(pLinkRuntimeCallback);
401   }
402 
403   script.setLinkRuntimeCallback(getLinkRuntimeCallback());
404 
405   // Read information from bitcode wrapper.
406   bcinfo::BitcodeWrapper wrapper(pBitcode, pBitcodeSize);
407   script.setCompilerVersion(wrapper.getCompilerVersion());
408   script.setOptimizationLevel(static_cast<RSScript::OptimizationLevel>(
409                               wrapper.getOptimizationLevel()));
410 
411   //===--------------------------------------------------------------------===//
412   // Compile the script
413   //===--------------------------------------------------------------------===//
414   Compiler::ErrorCode status = compileScript(script, pResName,
415                                              output_path.c_str(),
416                                              pRuntimePath, bitcode_sha1, commandLine,
417                                              true, pDumpIR);
418 
419   return status == Compiler::kSuccess;
420 }
421 
422 
buildForCompatLib(RSScript & pScript,const char * pOut,const char * pRuntimePath)423 bool RSCompilerDriver::buildForCompatLib(RSScript &pScript, const char *pOut,
424                                          const char *pRuntimePath) {
425   // For compat lib, we don't check the RS info file so we don't need the source hash,
426   // compile command, and build fingerprint.
427   // TODO We may want to make them optional or embed real values.
428   uint8_t bitcode_sha1[SHA1_DIGEST_LENGTH] = {0};
429   const char* compileCommandLineToEmbed = "";
430   const char* buildFingerprintToEmbed = "";
431 
432   RSInfo* info = RSInfo::ExtractFromSource(pScript.getSource(), bitcode_sha1,
433                                            compileCommandLineToEmbed, buildFingerprintToEmbed);
434   if (info == NULL) {
435     return false;
436   }
437   pScript.setInfo(info);
438 
439   // Embed the info string directly in the ELF, since this path is for an
440   // offline (host) compilation.
441   pScript.setEmbedInfo(true);
442 
443   Compiler::ErrorCode status = compileScript(pScript, pOut, pOut, pRuntimePath, bitcode_sha1,
444                                              compileCommandLineToEmbed, false, false);
445   if (status != Compiler::kSuccess) {
446     return false;
447   }
448 
449   return true;
450 }
451 
452