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