RSCompilerDriver.cpp revision f2ac3176c351cd80bce77fe1488f3de2d0789c1b
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 46using namespace bcc; 47 48// Get the build fingerprint of the Android device we are running on. 49static 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 59RSCompilerDriver::RSCompilerDriver(bool pUseCompilerRT) : 60 mConfig(NULL), mCompiler(), mDebugContext(false), 61 mLinkRuntimeCallback(NULL), mEnableGlobalMerge(true) { 62 init::Initialize(); 63} 64 65RSCompilerDriver::~RSCompilerDriver() { 66 delete mConfig; 67} 68 69RSExecutable* 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) 174extern llvm::cl::opt<bool> EnableGlobalMerge; 175#endif 176 177bool 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 218Compiler::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 349bool 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 423bool 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