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