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