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