RSCompilerDriver.cpp revision b39557ea3f72e1854581aa1f859b2323499389b1
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/Path.h> 22#include <llvm/Support/raw_ostream.h> 23 24#include "bcinfo/BitcodeWrapper.h" 25 26#include "bcc/Compiler.h" 27#include "bcc/Config/Config.h" 28#include "bcc/Renderscript/RSExecutable.h" 29#include "bcc/Renderscript/RSScript.h" 30#include "bcc/Support/CompilerConfig.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(), mDebugContext(false), 49 mLinkRuntimeCallback(NULL), mEnableGlobalMerge(true) { 50 init::Initialize(); 51} 52 53RSCompilerDriver::~RSCompilerDriver() { 54 delete mConfig; 55} 56 57RSExecutable * 58RSCompilerDriver::loadScript(const char *pCacheDir, const char *pResName, 59 const char *pBitcode, size_t pBitcodeSize, 60 SymbolResolverProxy &pResolver) { 61 //android::StopWatch load_time("bcc: RSCompilerDriver::loadScript time"); 62 if ((pCacheDir == NULL) || (pResName == NULL)) { 63 ALOGE("Missing pCacheDir and/or pResName"); 64 return NULL; 65 } 66 67 if ((pBitcode == NULL) || (pBitcodeSize <= 0)) { 68 ALOGE("No bitcode supplied! (bitcode: %p, size of bitcode: %zu)", 69 pBitcode, pBitcodeSize); 70 return NULL; 71 } 72 73 RSInfo::DependencyTableTy dep_info; 74 uint8_t bitcode_sha1[20]; 75 Sha1Util::GetSHA1DigestFromBuffer(bitcode_sha1, pBitcode, pBitcodeSize); 76 77 // {pCacheDir}/{pResName}.o 78 llvm::SmallString<80> output_path(pCacheDir); 79 llvm::sys::path::append(output_path, pResName); 80 llvm::sys::path::replace_extension(output_path, ".o"); 81 82 dep_info.push(std::make_pair(output_path.c_str(), bitcode_sha1)); 83 84 //===--------------------------------------------------------------------===// 85 // Acquire the read lock for reading the Script object file. 86 //===--------------------------------------------------------------------===// 87 FileMutex<FileBase::kReadLock> read_output_mutex(output_path.c_str()); 88 89 if (read_output_mutex.hasError() || !read_output_mutex.lock()) { 90 ALOGE("Unable to acquire the read lock for %s! (%s)", output_path.c_str(), 91 read_output_mutex.getErrorMessage().c_str()); 92 return NULL; 93 } 94 95 //===--------------------------------------------------------------------===// 96 // Read the output object file. 97 //===--------------------------------------------------------------------===// 98 InputFile *object_file = new (std::nothrow) InputFile(output_path.c_str()); 99 100 if ((object_file == NULL) || object_file->hasError()) { 101 // ALOGE("Unable to open the %s for read! (%s)", output_path.c_str(), 102 // object_file->getErrorMessage().c_str()); 103 delete object_file; 104 return NULL; 105 } 106 107 //===--------------------------------------------------------------------===// 108 // Acquire the read lock on object_file for reading its RS info file. 109 //===--------------------------------------------------------------------===// 110 android::String8 info_path = RSInfo::GetPath(output_path.c_str()); 111 112 if (!object_file->lock()) { 113 ALOGE("Unable to acquire the read lock on %s for reading %s! (%s)", 114 output_path.c_str(), info_path.string(), 115 object_file->getErrorMessage().c_str()); 116 delete object_file; 117 return NULL; 118 } 119 120 //===---------------------------------------------------------------------===// 121 // Open and load the RS info file. 122 //===--------------------------------------------------------------------===// 123 InputFile info_file(info_path.string()); 124 RSInfo *info = RSInfo::ReadFromFile(info_file, dep_info); 125 126 // Release the lock on object_file. 127 object_file->unlock(); 128 129 if (info == NULL) { 130 delete object_file; 131 return NULL; 132 } 133 134 //===--------------------------------------------------------------------===// 135 // Create the RSExecutable. 136 //===--------------------------------------------------------------------===// 137 RSExecutable *result = RSExecutable::Create(*info, *object_file, pResolver); 138 if (result == NULL) { 139 delete object_file; 140 delete info; 141 return NULL; 142 } 143 144 return result; 145} 146 147#if defined(PROVIDE_ARM_CODEGEN) 148extern llvm::cl::opt<bool> EnableGlobalMerge; 149#endif 150 151bool RSCompilerDriver::setupConfig(const RSScript &pScript) { 152 bool changed = false; 153 154 const llvm::CodeGenOpt::Level script_opt_level = 155 static_cast<llvm::CodeGenOpt::Level>(pScript.getOptimizationLevel()); 156 157#if defined(PROVIDE_ARM_CODEGEN) 158 EnableGlobalMerge = mEnableGlobalMerge; 159#endif 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) CompilerConfig(DEFAULT_TARGET_TRIPLE_STRING); 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(PROVIDE_ARM_CODEGEN) 180 assert((pScript.getInfo() != NULL) && "NULL RS info!"); 181 bool script_full_prec = (pScript.getInfo()->getFloatPrecisionRequirement() == 182 RSInfo::FP_Full); 183 if (mConfig->getFullPrecision() != script_full_prec) { 184 mConfig->setFullPrecision(script_full_prec); 185 changed = true; 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, bool pDumpIR) { 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 // FIXME(srhines): Windows compilation can't use locking like this, but 229 // we also don't need to worry about concurrent writers of the same file. 230#ifndef USE_MINGW 231 //===------------------------------------------------------------------===// 232 // Acquire the write lock for writing output object file. 233 //===------------------------------------------------------------------===// 234 FileMutex<FileBase::kWriteLock> write_output_mutex(pOutputPath); 235 236 if (write_output_mutex.hasError() || !write_output_mutex.lock()) { 237 ALOGE("Unable to acquire the lock for writing %s! (%s)", 238 pOutputPath, write_output_mutex.getErrorMessage().c_str()); 239 return Compiler::kErrInvalidSource; 240 } 241#endif 242 243 // Open the output file for write. 244 OutputFile output_file(pOutputPath, 245 FileBase::kTruncate | FileBase::kBinary); 246 247 if (output_file.hasError()) { 248 ALOGE("Unable to open %s for write! (%s)", pOutputPath, 249 output_file.getErrorMessage().c_str()); 250 return Compiler::kErrInvalidSource; 251 } 252 253 // Setup the config to the compiler. 254 bool compiler_need_reconfigure = setupConfig(pScript); 255 256 if (mConfig == NULL) { 257 ALOGE("Failed to setup config for RS compiler to compile %s!", 258 pOutputPath); 259 return Compiler::kErrInvalidSource; 260 } 261 262 if (compiler_need_reconfigure) { 263 Compiler::ErrorCode err = mCompiler.config(*mConfig); 264 if (err != Compiler::kSuccess) { 265 ALOGE("Failed to config the RS compiler for %s! (%s)",pOutputPath, 266 Compiler::GetErrorString(err)); 267 return Compiler::kErrInvalidSource; 268 } 269 } 270 271 OutputFile *ir_file = NULL; 272 llvm::raw_fd_ostream *IRStream = NULL; 273 if (pDumpIR) { 274 android::String8 path(pOutputPath); 275 path.append(".ll"); 276 ir_file = new OutputFile(path.string(), FileBase::kTruncate); 277 IRStream = ir_file->dup(); 278 } 279 280 // Run the compiler. 281 Compiler::ErrorCode compile_result = mCompiler.compile(pScript, 282 output_file, IRStream); 283 284 if (ir_file) { 285 ir_file->close(); 286 delete ir_file; 287 } 288 289 if (compile_result != Compiler::kSuccess) { 290 ALOGE("Unable to compile the source to file %s! (%s)", pOutputPath, 291 Compiler::GetErrorString(compile_result)); 292 return Compiler::kErrInvalidSource; 293 } 294 } 295 296 // No need to produce an RSExecutable in this case. 297 // TODO: Error handling in this case is nonexistent. 298 if (pSkipLoad) { 299 return Compiler::kSuccess; 300 } 301 302 { 303 android::String8 info_path = RSInfo::GetPath(pOutputPath); 304 OutputFile info_file(info_path.string(), FileBase::kTruncate); 305 306 if (info_file.hasError()) { 307 ALOGE("Failed to open the info file %s for write! (%s)", 308 info_path.string(), info_file.getErrorMessage().c_str()); 309 return Compiler::kErrInvalidSource; 310 } 311 312 FileMutex<FileBase::kWriteLock> write_info_mutex(info_path.string()); 313 if (write_info_mutex.hasError() || !write_info_mutex.lock()) { 314 ALOGE("Unable to acquire the lock for writing %s! (%s)", 315 info_path.string(), write_info_mutex.getErrorMessage().c_str()); 316 return Compiler::kErrInvalidSource; 317 } 318 319 // Perform the write. 320 if (!info->write(info_file)) { 321 ALOGE("Failed to sync the RS info file %s!", info_path.string()); 322 return Compiler::kErrInvalidSource; 323 } 324 } 325 326 return Compiler::kSuccess; 327} 328 329bool RSCompilerDriver::build(BCCContext &pContext, 330 const char *pCacheDir, 331 const char *pResName, 332 const char *pBitcode, 333 size_t pBitcodeSize, 334 const char *pRuntimePath, 335 RSLinkRuntimeCallback pLinkRuntimeCallback, 336 bool pDumpIR) { 337 // android::StopWatch build_time("bcc: RSCompilerDriver::build time"); 338 //===--------------------------------------------------------------------===// 339 // Check parameters. 340 //===--------------------------------------------------------------------===// 341 if ((pCacheDir == NULL) || (pResName == NULL)) { 342 ALOGE("Invalid parameter passed to RSCompilerDriver::build()! (cache dir: " 343 "%s, resource name: %s)", ((pCacheDir) ? pCacheDir : "(null)"), 344 ((pResName) ? pResName : "(null)")); 345 return false; 346 } 347 348 if ((pBitcode == NULL) || (pBitcodeSize <= 0)) { 349 ALOGE("No bitcode supplied! (bitcode: %p, size of bitcode: %u)", 350 pBitcode, static_cast<unsigned>(pBitcodeSize)); 351 return false; 352 } 353 354 //===--------------------------------------------------------------------===// 355 // Prepare dependency information. 356 //===--------------------------------------------------------------------===// 357 RSInfo::DependencyTableTy dep_info; 358 uint8_t bitcode_sha1[20]; 359 Sha1Util::GetSHA1DigestFromBuffer(bitcode_sha1, pBitcode, pBitcodeSize); 360 361 //===--------------------------------------------------------------------===// 362 // Construct output path. 363 // {pCacheDir}/{pResName}.o 364 //===--------------------------------------------------------------------===// 365 llvm::SmallString<80> output_path(pCacheDir); 366 llvm::sys::path::append(output_path, pResName); 367 llvm::sys::path::replace_extension(output_path, ".o"); 368 369 dep_info.push(std::make_pair(output_path.c_str(), bitcode_sha1)); 370 371 //===--------------------------------------------------------------------===// 372 // Load the bitcode and create script. 373 //===--------------------------------------------------------------------===// 374 Source *source = Source::CreateFromBuffer(pContext, pResName, 375 pBitcode, pBitcodeSize); 376 if (source == NULL) { 377 return false; 378 } 379 380 RSScript *script = new (std::nothrow) RSScript(*source); 381 if (script == NULL) { 382 ALOGE("Out of memory when create Script object for '%s'! (output: %s)", 383 pResName, output_path.c_str()); 384 delete source; 385 return false; 386 } 387 if (pLinkRuntimeCallback) { 388 setLinkRuntimeCallback(pLinkRuntimeCallback); 389 } 390 391 script->setLinkRuntimeCallback(getLinkRuntimeCallback()); 392 393 // Read information from bitcode wrapper. 394 bcinfo::BitcodeWrapper wrapper(pBitcode, pBitcodeSize); 395 script->setCompilerVersion(wrapper.getCompilerVersion()); 396 script->setOptimizationLevel(static_cast<RSScript::OptimizationLevel>( 397 wrapper.getOptimizationLevel())); 398 399 //===--------------------------------------------------------------------===// 400 // Compile the script 401 //===--------------------------------------------------------------------===// 402 Compiler::ErrorCode status = compileScript(*script, pResName, 403 output_path.c_str(), 404 pRuntimePath, dep_info, false, 405 pDumpIR); 406 407 // Script is no longer used. Free it to get more memory. 408 delete script; 409 410 if (status != Compiler::kSuccess) { 411 return false; 412 } 413 414 return true; 415} 416 417 418bool RSCompilerDriver::build(RSScript &pScript, const char *pOut, 419 const char *pRuntimePath) { 420 RSInfo::DependencyTableTy dep_info; 421 RSInfo *info = RSInfo::ExtractFromSource(pScript.getSource(), dep_info); 422 if (info == NULL) { 423 return false; 424 } 425 pScript.setInfo(info); 426 427 // Embed the info string directly in the ELF, since this path is for an 428 // offline (host) compilation. 429 pScript.setEmbedInfo(true); 430 431 Compiler::ErrorCode status = compileScript(pScript, pOut, pOut, pRuntimePath, 432 dep_info, true); 433 if (status != Compiler::kSuccess) { 434 return false; 435 } 436 437 return true; 438} 439 440