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