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