RSCompilerDriver.cpp revision b81d697ec617be24494b622a3532f1c465264415
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/Path.h> 20 21#include "bcinfo/BitcodeWrapper.h" 22 23#include "bcc/Renderscript/RSExecutable.h" 24#include "bcc/Renderscript/RSScript.h" 25#include "bcc/Support/CompilerConfig.h" 26#include "bcc/Support/TargetCompilerConfigs.h" 27#include "bcc/Source.h" 28#include "bcc/Support/FileMutex.h" 29#include "bcc/Support/Log.h" 30#include "bcc/Support/InputFile.h" 31#include "bcc/Support/Initialization.h" 32#include "bcc/Support/Sha1Util.h" 33#include "bcc/Support/OutputFile.h" 34 35#ifdef HAVE_ANDROID_OS 36#include <cutils/properties.h> 37#endif 38#include <utils/String8.h> 39#include <utils/StopWatch.h> 40 41using namespace bcc; 42 43namespace { 44 45bool is_force_recompile() { 46#ifndef HAVE_ANDROID_OS 47 return false; 48#else 49 char buf[PROPERTY_VALUE_MAX]; 50 51 // Re-compile if floating point precision has been overridden. 52 property_get("debug.rs.precision", buf, ""); 53 if (buf[0] != '\0') { 54 return true; 55 } 56 57 // Re-compile if debug.rs.forcerecompile is set. 58 property_get("debug.rs.forcerecompile", buf, "0"); 59 if ((::strcmp(buf, "1") == 0) || (::strcmp(buf, "true") == 0)) { 60 return true; 61 } else { 62 return false; 63 } 64#endif 65} 66 67} // end anonymous namespace 68 69RSCompilerDriver::RSCompilerDriver(bool pUseCompilerRT) : 70 mConfig(NULL), mCompiler(), mCompilerRuntime(NULL), mDebugContext(false) { 71 init::Initialize(); 72 // Chain the symbol resolvers for compiler_rt and RS runtimes. 73 if (pUseCompilerRT) { 74 mCompilerRuntime = new CompilerRTSymbolResolver(); 75 mResolver.chainResolver(*mCompilerRuntime); 76 } 77 mResolver.chainResolver(mRSRuntime); 78} 79 80RSCompilerDriver::~RSCompilerDriver() { 81 delete mCompilerRuntime; 82 delete mConfig; 83} 84 85RSExecutable * 86RSCompilerDriver::loadScriptCache(const char *pOutputPath, 87 const RSInfo::DependencyTableTy &pDeps) { 88 //android::StopWatch load_time("bcc: RSCompilerDriver::loadScriptCache time"); 89 RSExecutable *result = NULL; 90 91 if (is_force_recompile()) 92 return NULL; 93 94 //===--------------------------------------------------------------------===// 95 // Acquire the read lock for reading output object file. 96 //===--------------------------------------------------------------------===// 97 FileMutex<FileBase::kReadLock> read_output_mutex(pOutputPath); 98 99 if (read_output_mutex.hasError() || !read_output_mutex.lock()) { 100 ALOGE("Unable to acquire the read lock for %s! (%s)", pOutputPath, 101 read_output_mutex.getErrorMessage().c_str()); 102 return NULL; 103 } 104 105 //===--------------------------------------------------------------------===// 106 // Read the output object file. 107 //===--------------------------------------------------------------------===// 108 InputFile *output_file = new (std::nothrow) InputFile(pOutputPath); 109 110 if ((output_file == NULL) || output_file->hasError()) { 111 // ALOGE("Unable to open the %s for read! (%s)", pOutputPath, 112 // output_file->getErrorMessage().c_str()); 113 delete output_file; 114 return NULL; 115 } 116 117 //===--------------------------------------------------------------------===// 118 // Acquire the read lock on output_file for reading its RS info file. 119 //===--------------------------------------------------------------------===// 120 android::String8 info_path = RSInfo::GetPath(*output_file); 121 122 if (!output_file->lock()) { 123 ALOGE("Unable to acquire the read lock on %s for reading %s! (%s)", 124 pOutputPath, info_path.string(), 125 output_file->getErrorMessage().c_str()); 126 delete output_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, pDeps); 135 136 // Release the lock on output_file. 137 output_file->unlock(); 138 139 if (info == NULL) { 140 delete output_file; 141 return NULL; 142 } 143 144 //===--------------------------------------------------------------------===// 145 // Create the RSExecutable. 146 //===--------------------------------------------------------------------===// 147 result = RSExecutable::Create(*info, *output_file, mResolver); 148 if (result == NULL) { 149 delete output_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 194RSExecutable * 195RSCompilerDriver::compileScript(RSScript &pScript, 196 const char* pScriptName, 197 const char *pOutputPath, 198 const char *pRuntimePath, 199 const RSInfo::DependencyTableTy &pDeps, 200 bool pSkipLoad) { 201 //android::StopWatch compile_time("bcc: RSCompilerDriver::compileScript time"); 202 RSExecutable *result = NULL; 203 RSInfo *info = NULL; 204 205 //===--------------------------------------------------------------------===// 206 // Extract RS-specific information from source bitcode. 207 //===--------------------------------------------------------------------===// 208 // RS info may contains configuration (such as #optimization_level) to the 209 // compiler therefore it should be extracted before compilation. 210 info = RSInfo::ExtractFromSource(pScript.getSource(), pDeps); 211 if (info == NULL) { 212 return NULL; 213 } 214 215 //===--------------------------------------------------------------------===// 216 // Associate script with its info 217 //===--------------------------------------------------------------------===// 218 // This is required since RS compiler may need information in the info file 219 // to do some transformation (e.g., expand foreach-able function.) 220 pScript.setInfo(info); 221 222 //===--------------------------------------------------------------------===// 223 // Link RS script with Renderscript runtime. 224 //===--------------------------------------------------------------------===// 225 if (!RSScript::LinkRuntime(pScript, pRuntimePath)) { 226 ALOGE("Failed to link script '%s' with Renderscript runtime!", pScriptName); 227 return NULL; 228 } 229 230 //===--------------------------------------------------------------------===// 231 // Acquire the write lock for writing output object file. 232 //===--------------------------------------------------------------------===// 233 FileMutex<FileBase::kWriteLock> write_output_mutex(pOutputPath); 234 235 if (write_output_mutex.hasError() || !write_output_mutex.lock()) { 236 ALOGE("Unable to acquire the lock for writing %s! (%s)", 237 pOutputPath, write_output_mutex.getErrorMessage().c_str()); 238 return NULL; 239 } 240 241 //===--------------------------------------------------------------------===// 242 // Open the output file for write. 243 //===--------------------------------------------------------------------===// 244 unsigned flags = FileBase::kTruncate; 245 if (mDebugContext) { 246 // Delete the cache file when we finish up under a debug context. 247 flags |= FileBase::kDeleteOnClose; 248 } 249 OutputFile *output_file = new (std::nothrow) OutputFile(pOutputPath, flags); 250 251 if ((output_file == NULL) || output_file->hasError()) { 252 ALOGE("Unable to open %s for write! (%s)", pOutputPath, 253 output_file->getErrorMessage().c_str()); 254 delete info; 255 delete output_file; 256 return NULL; 257 } 258 259 //===--------------------------------------------------------------------===// 260 // Setup the config to the compiler. 261 //===--------------------------------------------------------------------===// 262 bool compiler_need_reconfigure = setupConfig(pScript); 263 264 if (mConfig == NULL) { 265 ALOGE("Failed to setup config for RS compiler to compile %s!", pOutputPath); 266 delete info; 267 delete output_file; 268 return NULL; 269 } 270 271 // Compiler need to re-config if it's haven't run the config() yet or the 272 // configuration it referenced is changed. 273 if (compiler_need_reconfigure) { 274 Compiler::ErrorCode err = mCompiler.config(*mConfig); 275 if (err != Compiler::kSuccess) { 276 ALOGE("Failed to config the RS compiler for %s! (%s)",pOutputPath, 277 Compiler::GetErrorString(err)); 278 delete info; 279 delete output_file; 280 return NULL; 281 } 282 } 283 284 //===--------------------------------------------------------------------===// 285 // Run the compiler. 286 //===--------------------------------------------------------------------===// 287 Compiler::ErrorCode compile_result = mCompiler.compile(pScript, *output_file); 288 if (compile_result != Compiler::kSuccess) { 289 ALOGE("Unable to compile the source to file %s! (%s)", pOutputPath, 290 Compiler::GetErrorString(compile_result)); 291 delete info; 292 delete output_file; 293 return NULL; 294 } 295 296 // No need to produce an RSExecutable in this case. 297 // TODO: Error handling in this case is nonexistent. 298 if (pSkipLoad) { 299 return NULL; 300 } 301 302 //===--------------------------------------------------------------------===// 303 // Create the RSExecutable. 304 //===--------------------------------------------------------------------===// 305 result = RSExecutable::Create(*info, *output_file, mResolver); 306 if (result == NULL) { 307 delete info; 308 delete output_file; 309 return NULL; 310 } 311 312 //===--------------------------------------------------------------------===// 313 // Dump the disassembly for debug when possible. 314 //===--------------------------------------------------------------------===// 315#if USE_DISASSEMBLER 316 OutputFile *disassembly_output = 317 new (std::nothrow) OutputFile(DEBUG_DISASSEMBLER_FILE, 318 FileBase::kAppend); 319 320 if (disassembly_output != NULL) { 321 result->dumpDisassembly(*disassembly_output); 322 delete disassembly_output; 323 } 324#endif 325 326 //===--------------------------------------------------------------------===// 327 // Write out the RS info file. 328 //===--------------------------------------------------------------------===// 329 // Note that write failure only results in a warning since the source is 330 // successfully compiled and loaded. 331 if (!result->syncInfo(/* pForce */true)) { 332 ALOGW("%s was successfully compiled and loaded but its RS info file failed " 333 "to write out!", pOutputPath); 334 } 335 336 return result; 337} 338 339RSExecutable *RSCompilerDriver::build(BCCContext &pContext, 340 const char *pCacheDir, 341 const char *pResName, 342 const char *pBitcode, 343 size_t pBitcodeSize, 344 const char *pRuntimePath, 345 RSLinkRuntimeCallback pLinkRuntimeCallback) { 346 // android::StopWatch build_time("bcc: RSCompilerDriver::build time"); 347 //===--------------------------------------------------------------------===// 348 // Check parameters. 349 //===--------------------------------------------------------------------===// 350 if ((pCacheDir == NULL) || (pResName == NULL)) { 351 ALOGE("Invalid parameter passed to RSCompilerDriver::build()! (cache dir: " 352 "%s, resource name: %s)", ((pCacheDir) ? pCacheDir : "(null)"), 353 ((pResName) ? pResName : "(null)")); 354 return NULL; 355 } 356 357 if ((pBitcode == NULL) || (pBitcodeSize <= 0)) { 358 ALOGE("No bitcode supplied! (bitcode: %p, size of bitcode: %u)", 359 pBitcode, static_cast<unsigned>(pBitcodeSize)); 360 return NULL; 361 } 362 363 //===--------------------------------------------------------------------===// 364 // Prepare dependency information. 365 //===--------------------------------------------------------------------===// 366 RSInfo::DependencyTableTy dep_info; 367 uint8_t bitcode_sha1[20]; 368 Sha1Util::GetSHA1DigestFromBuffer(bitcode_sha1, pBitcode, pBitcodeSize); 369 dep_info.push(std::make_pair(pResName, bitcode_sha1)); 370 371 //===--------------------------------------------------------------------===// 372 // Construct output path. 373 //===--------------------------------------------------------------------===// 374 llvm::sys::Path output_path(pCacheDir); 375 376 // {pCacheDir}/{pResName} 377 if (!output_path.appendComponent(pResName)) { 378 ALOGE("Failed to construct output path %s/%s!", pCacheDir, pResName); 379 return NULL; 380 } 381 382 // {pCacheDir}/{pResName}.o 383 output_path.appendSuffix("o"); 384 385 //===--------------------------------------------------------------------===// 386 // Load cache. 387 //===--------------------------------------------------------------------===// 388 RSExecutable *result = NULL; 389 390 // Skip loading from the cache if we are using a debug context. 391 if (!mDebugContext) { 392 result = loadScriptCache(output_path.c_str(), dep_info); 393 394 if (result != NULL) { 395 // Cache hit 396 return result; 397 } 398 } 399 400 //===--------------------------------------------------------------------===// 401 // Load the bitcode and create script. 402 //===--------------------------------------------------------------------===// 403 Source *source = Source::CreateFromBuffer(pContext, pResName, 404 pBitcode, pBitcodeSize); 405 if (source == NULL) { 406 return NULL; 407 } 408 409 RSScript *script = new (std::nothrow) RSScript(*source); 410 if (script == NULL) { 411 ALOGE("Out of memory when create Script object for '%s'! (output: %s)", 412 pResName, output_path.c_str()); 413 delete source; 414 return NULL; 415 } 416 417 script->setLinkRuntimeCallback(pLinkRuntimeCallback); 418 419 // Read information from bitcode wrapper. 420 bcinfo::BitcodeWrapper wrapper(pBitcode, pBitcodeSize); 421 script->setCompilerVersion(wrapper.getCompilerVersion()); 422 script->setOptimizationLevel(static_cast<RSScript::OptimizationLevel>( 423 wrapper.getOptimizationLevel())); 424 425 //===--------------------------------------------------------------------===// 426 // Compile the script 427 //===--------------------------------------------------------------------===// 428 result = compileScript(*script, pResName, output_path.c_str(), pRuntimePath, 429 dep_info, false); 430 431 // Script is no longer used. Free it to get more memory. 432 delete script; 433 434 if (result == NULL) { 435 return NULL; 436 } 437 438 return result; 439} 440 441 442RSExecutable *RSCompilerDriver::build(RSScript &pScript, const char *pOut, 443 const char *pRuntimePath) { 444 RSInfo::DependencyTableTy dep_info; 445 RSInfo *info = RSInfo::ExtractFromSource(pScript.getSource(), dep_info); 446 if (info == NULL) { 447 return NULL; 448 } 449 pScript.setInfo(info); 450 451 // Embed the info string directly in the ELF, since this path is for an 452 // offline (host) compilation. 453 pScript.setEmbedInfo(true); 454 455 RSExecutable *result = compileScript(pScript, pOut, pOut, pRuntimePath, 456 dep_info, true); 457 return result; 458} 459 460