LTOCodeGenerator.cpp revision b515d75856f58a8b3b71d782eb00916d686329ad
1//===-LTOCodeGenerator.cpp - LLVM Link Time Optimizer ---------------------===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// This file implements the Link Time Optimization library. This library is 11// intended to be used by linker to optimize code at link time. 12// 13//===----------------------------------------------------------------------===// 14 15#include "LTOModule.h" 16#include "LTOCodeGenerator.h" 17 18 19#include "llvm/Constants.h" 20#include "llvm/DerivedTypes.h" 21#include "llvm/Linker.h" 22#include "llvm/LLVMContext.h" 23#include "llvm/Module.h" 24#include "llvm/ModuleProvider.h" 25#include "llvm/PassManager.h" 26#include "llvm/ADT/StringExtras.h" 27#include "llvm/Analysis/Passes.h" 28#include "llvm/Analysis/LoopPass.h" 29#include "llvm/Analysis/Verifier.h" 30#include "llvm/Bitcode/ReaderWriter.h" 31#include "llvm/CodeGen/FileWriters.h" 32#include "llvm/Support/CommandLine.h" 33#include "llvm/Support/FormattedStream.h" 34#include "llvm/Support/Mangler.h" 35#include "llvm/Support/MemoryBuffer.h" 36#include "llvm/Support/StandardPasses.h" 37#include "llvm/Support/SystemUtils.h" 38#include "llvm/System/Host.h" 39#include "llvm/System/Signals.h" 40#include "llvm/Target/SubtargetFeature.h" 41#include "llvm/Target/TargetOptions.h" 42#include "llvm/MC/MCAsmInfo.h" 43#include "llvm/Target/TargetData.h" 44#include "llvm/Target/TargetMachine.h" 45#include "llvm/Target/TargetRegistry.h" 46#include "llvm/Target/TargetSelect.h" 47#include "llvm/Transforms/IPO.h" 48#include "llvm/Transforms/Scalar.h" 49#include "llvm/Config/config.h" 50#include <cstdlib> 51#include <unistd.h> 52#include <fcntl.h> 53 54 55using namespace llvm; 56 57static cl::opt<bool> DisableInline("disable-inlining", 58 cl::desc("Do not run the inliner pass")); 59 60 61const char* LTOCodeGenerator::getVersionString() 62{ 63#ifdef LLVM_VERSION_INFO 64 return PACKAGE_NAME " version " PACKAGE_VERSION ", " LLVM_VERSION_INFO; 65#else 66 return PACKAGE_NAME " version " PACKAGE_VERSION; 67#endif 68} 69 70 71LTOCodeGenerator::LTOCodeGenerator() 72 : _context(getGlobalContext()), 73 _linker("LinkTimeOptimizer", "ld-temp.o", _context), _target(NULL), 74 _emitDwarfDebugInfo(false), _scopeRestrictionsDone(false), 75 _codeModel(LTO_CODEGEN_PIC_MODEL_DYNAMIC), 76 _nativeObjectFile(NULL), _assemblerPath(NULL) 77{ 78 InitializeAllTargets(); 79 InitializeAllAsmPrinters(); 80} 81 82LTOCodeGenerator::~LTOCodeGenerator() 83{ 84 delete _target; 85 delete _nativeObjectFile; 86} 87 88 89 90bool LTOCodeGenerator::addModule(LTOModule* mod, std::string& errMsg) 91{ 92 return _linker.LinkInModule(mod->getLLVVMModule(), &errMsg); 93} 94 95 96bool LTOCodeGenerator::setDebugInfo(lto_debug_model debug, std::string& errMsg) 97{ 98 switch (debug) { 99 case LTO_DEBUG_MODEL_NONE: 100 _emitDwarfDebugInfo = false; 101 return false; 102 103 case LTO_DEBUG_MODEL_DWARF: 104 _emitDwarfDebugInfo = true; 105 return false; 106 } 107 errMsg = "unknown debug format"; 108 return true; 109} 110 111 112bool LTOCodeGenerator::setCodePICModel(lto_codegen_model model, 113 std::string& errMsg) 114{ 115 switch (model) { 116 case LTO_CODEGEN_PIC_MODEL_STATIC: 117 case LTO_CODEGEN_PIC_MODEL_DYNAMIC: 118 case LTO_CODEGEN_PIC_MODEL_DYNAMIC_NO_PIC: 119 _codeModel = model; 120 return false; 121 } 122 errMsg = "unknown pic model"; 123 return true; 124} 125 126void LTOCodeGenerator::setAssemblerPath(const char* path) 127{ 128 if ( _assemblerPath ) 129 delete _assemblerPath; 130 _assemblerPath = new sys::Path(path); 131} 132 133void LTOCodeGenerator::addMustPreserveSymbol(const char* sym) 134{ 135 _mustPreserveSymbols[sym] = 1; 136} 137 138 139bool LTOCodeGenerator::writeMergedModules(const char *path, 140 std::string &errMsg) { 141 if (determineTarget(errMsg)) 142 return true; 143 144 // mark which symbols can not be internalized 145 applyScopeRestrictions(); 146 147 // create output file 148 std::string ErrInfo; 149 raw_fd_ostream Out(path, ErrInfo, 150 raw_fd_ostream::F_Force|raw_fd_ostream::F_Binary); 151 if (!ErrInfo.empty()) { 152 errMsg = "could not open bitcode file for writing: "; 153 errMsg += path; 154 return true; 155 } 156 157 // write bitcode to it 158 WriteBitcodeToFile(_linker.getModule(), Out); 159 160 if (Out.has_error()) { 161 errMsg = "could not write bitcode file: "; 162 errMsg += path; 163 return true; 164 } 165 166 return false; 167} 168 169 170const void* LTOCodeGenerator::compile(size_t* length, std::string& errMsg) 171{ 172 // make unique temp .s file to put generated assembly code 173 sys::Path uniqueAsmPath("lto-llvm.s"); 174 if ( uniqueAsmPath.createTemporaryFileOnDisk(true, &errMsg) ) 175 return NULL; 176 sys::RemoveFileOnSignal(uniqueAsmPath); 177 178 // generate assembly code 179 bool genResult = false; 180 { 181 raw_fd_ostream asmFD(uniqueAsmPath.c_str(), errMsg, 182 raw_fd_ostream::F_Force); 183 formatted_raw_ostream asmFile(asmFD); 184 if (!errMsg.empty()) 185 return NULL; 186 genResult = this->generateAssemblyCode(asmFile, errMsg); 187 } 188 if ( genResult ) { 189 if ( uniqueAsmPath.exists() ) 190 uniqueAsmPath.eraseFromDisk(); 191 return NULL; 192 } 193 194 // make unique temp .o file to put generated object file 195 sys::PathWithStatus uniqueObjPath("lto-llvm.o"); 196 if ( uniqueObjPath.createTemporaryFileOnDisk(true, &errMsg) ) { 197 if ( uniqueAsmPath.exists() ) 198 uniqueAsmPath.eraseFromDisk(); 199 return NULL; 200 } 201 sys::RemoveFileOnSignal(uniqueObjPath); 202 203 // assemble the assembly code 204 const std::string& uniqueObjStr = uniqueObjPath.toString(); 205 bool asmResult = this->assemble(uniqueAsmPath.toString(), 206 uniqueObjStr, errMsg); 207 if ( !asmResult ) { 208 // remove old buffer if compile() called twice 209 delete _nativeObjectFile; 210 211 // read .o file into memory buffer 212 _nativeObjectFile = MemoryBuffer::getFile(uniqueObjStr.c_str(),&errMsg); 213 } 214 215 // remove temp files 216 uniqueAsmPath.eraseFromDisk(); 217 uniqueObjPath.eraseFromDisk(); 218 219 // return buffer, unless error 220 if ( _nativeObjectFile == NULL ) 221 return NULL; 222 *length = _nativeObjectFile->getBufferSize(); 223 return _nativeObjectFile->getBufferStart(); 224} 225 226 227bool LTOCodeGenerator::assemble(const std::string& asmPath, 228 const std::string& objPath, std::string& errMsg) 229{ 230 sys::Path tool; 231 bool needsCompilerOptions = true; 232 if ( _assemblerPath ) { 233 tool = *_assemblerPath; 234 needsCompilerOptions = false; 235 } else { 236 // find compiler driver 237 tool = sys::Program::FindProgramByName("gcc"); 238 if ( tool.isEmpty() ) { 239 errMsg = "can't locate gcc"; 240 return true; 241 } 242 } 243 244 // build argument list 245 std::vector<const char*> args; 246 std::string targetTriple = _linker.getModule()->getTargetTriple(); 247 args.push_back(tool.c_str()); 248 if ( targetTriple.find("darwin") != std::string::npos ) { 249 // darwin specific command line options 250 if (strncmp(targetTriple.c_str(), "i386-apple-", 11) == 0) { 251 args.push_back("-arch"); 252 args.push_back("i386"); 253 } 254 else if (strncmp(targetTriple.c_str(), "x86_64-apple-", 13) == 0) { 255 args.push_back("-arch"); 256 args.push_back("x86_64"); 257 } 258 else if (strncmp(targetTriple.c_str(), "powerpc-apple-", 14) == 0) { 259 args.push_back("-arch"); 260 args.push_back("ppc"); 261 } 262 else if (strncmp(targetTriple.c_str(), "powerpc64-apple-", 16) == 0) { 263 args.push_back("-arch"); 264 args.push_back("ppc64"); 265 } 266 else if (strncmp(targetTriple.c_str(), "arm-apple-", 10) == 0) { 267 args.push_back("-arch"); 268 args.push_back("arm"); 269 } 270 else if ((strncmp(targetTriple.c_str(), "armv4t-apple-", 13) == 0) || 271 (strncmp(targetTriple.c_str(), "thumbv4t-apple-", 15) == 0)) { 272 args.push_back("-arch"); 273 args.push_back("armv4t"); 274 } 275 else if ((strncmp(targetTriple.c_str(), "armv5-apple-", 12) == 0) || 276 (strncmp(targetTriple.c_str(), "armv5e-apple-", 13) == 0) || 277 (strncmp(targetTriple.c_str(), "thumbv5-apple-", 14) == 0) || 278 (strncmp(targetTriple.c_str(), "thumbv5e-apple-", 15) == 0)) { 279 args.push_back("-arch"); 280 args.push_back("armv5"); 281 } 282 else if ((strncmp(targetTriple.c_str(), "armv6-apple-", 12) == 0) || 283 (strncmp(targetTriple.c_str(), "thumbv6-apple-", 14) == 0)) { 284 args.push_back("-arch"); 285 args.push_back("armv6"); 286 } 287 else if ((strncmp(targetTriple.c_str(), "armv7-apple-", 12) == 0) || 288 (strncmp(targetTriple.c_str(), "thumbv7-apple-", 14) == 0)) { 289 args.push_back("-arch"); 290 args.push_back("armv7"); 291 } 292 // add -static to assembler command line when code model requires 293 if ( (_assemblerPath != NULL) && (_codeModel == LTO_CODEGEN_PIC_MODEL_STATIC) ) 294 args.push_back("-static"); 295 } 296 if ( needsCompilerOptions ) { 297 args.push_back("-c"); 298 args.push_back("-x"); 299 args.push_back("assembler"); 300 } 301 args.push_back("-o"); 302 args.push_back(objPath.c_str()); 303 args.push_back(asmPath.c_str()); 304 args.push_back(0); 305 306 // invoke assembler 307 if ( sys::Program::ExecuteAndWait(tool, &args[0], 0, 0, 0, 0, &errMsg) ) { 308 errMsg = "error in assembly"; 309 return true; 310 } 311 return false; // success 312} 313 314 315 316bool LTOCodeGenerator::determineTarget(std::string& errMsg) 317{ 318 if ( _target == NULL ) { 319 std::string Triple = _linker.getModule()->getTargetTriple(); 320 if (Triple.empty()) 321 Triple = sys::getHostTriple(); 322 323 // create target machine from info for merged modules 324 const Target *march = TargetRegistry::lookupTarget(Triple, errMsg); 325 if ( march == NULL ) 326 return true; 327 328 // The relocation model is actually a static member of TargetMachine 329 // and needs to be set before the TargetMachine is instantiated. 330 switch( _codeModel ) { 331 case LTO_CODEGEN_PIC_MODEL_STATIC: 332 TargetMachine::setRelocationModel(Reloc::Static); 333 break; 334 case LTO_CODEGEN_PIC_MODEL_DYNAMIC: 335 TargetMachine::setRelocationModel(Reloc::PIC_); 336 break; 337 case LTO_CODEGEN_PIC_MODEL_DYNAMIC_NO_PIC: 338 TargetMachine::setRelocationModel(Reloc::DynamicNoPIC); 339 break; 340 } 341 342 // construct LTModule, hand over ownership of module and target 343 std::string FeatureStr = getFeatureString(Triple.c_str()); 344 _target = march->createTargetMachine(Triple, FeatureStr); 345 } 346 return false; 347} 348 349void LTOCodeGenerator::applyScopeRestrictions() 350{ 351 if ( !_scopeRestrictionsDone ) { 352 Module* mergedModule = _linker.getModule(); 353 354 // Start off with a verification pass. 355 PassManager passes; 356 passes.add(createVerifierPass()); 357 358 // mark which symbols can not be internalized 359 if ( !_mustPreserveSymbols.empty() ) { 360 Mangler mangler(*mergedModule, 361 _target->getMCAsmInfo()->getGlobalPrefix()); 362 std::vector<const char*> mustPreserveList; 363 for (Module::iterator f = mergedModule->begin(), 364 e = mergedModule->end(); f != e; ++f) { 365 if ( !f->isDeclaration() 366 && _mustPreserveSymbols.count(mangler.getMangledName(f)) ) 367 mustPreserveList.push_back(::strdup(f->getNameStr().c_str())); 368 } 369 for (Module::global_iterator v = mergedModule->global_begin(), 370 e = mergedModule->global_end(); v != e; ++v) { 371 if ( !v->isDeclaration() 372 && _mustPreserveSymbols.count(mangler.getMangledName(v)) ) 373 mustPreserveList.push_back(::strdup(v->getNameStr().c_str())); 374 } 375 passes.add(createInternalizePass(mustPreserveList)); 376 } 377 // apply scope restrictions 378 passes.run(*mergedModule); 379 380 _scopeRestrictionsDone = true; 381 } 382} 383 384/// Optimize merged modules using various IPO passes 385bool LTOCodeGenerator::generateAssemblyCode(formatted_raw_ostream& out, 386 std::string& errMsg) 387{ 388 if ( this->determineTarget(errMsg) ) 389 return true; 390 391 // mark which symbols can not be internalized 392 this->applyScopeRestrictions(); 393 394 Module* mergedModule = _linker.getModule(); 395 396 // If target supports exception handling then enable it now. 397 switch (_target->getMCAsmInfo()->getExceptionHandlingType()) { 398 case ExceptionHandling::Dwarf: 399 llvm::DwarfExceptionHandling = true; 400 break; 401 case ExceptionHandling::SjLj: 402 llvm::SjLjExceptionHandling = true; 403 break; 404 case ExceptionHandling::None: 405 break; 406 default: 407 assert (0 && "Unknown exception handling model!"); 408 } 409 410 // if options were requested, set them 411 if ( !_codegenOptions.empty() ) 412 cl::ParseCommandLineOptions(_codegenOptions.size(), 413 (char**)&_codegenOptions[0]); 414 415 // Instantiate the pass manager to organize the passes. 416 PassManager passes; 417 418 // Start off with a verification pass. 419 passes.add(createVerifierPass()); 420 421 // Add an appropriate TargetData instance for this module... 422 passes.add(new TargetData(*_target->getTargetData())); 423 424 createStandardLTOPasses(&passes, /*Internalize=*/ false, !DisableInline, 425 /*VerifyEach=*/ false); 426 427 // Make sure everything is still good. 428 passes.add(createVerifierPass()); 429 430 FunctionPassManager* codeGenPasses = 431 new FunctionPassManager(new ExistingModuleProvider(mergedModule)); 432 433 codeGenPasses->add(new TargetData(*_target->getTargetData())); 434 435 ObjectCodeEmitter* oce = NULL; 436 437 switch (_target->addPassesToEmitFile(*codeGenPasses, out, 438 TargetMachine::AssemblyFile, 439 CodeGenOpt::Aggressive)) { 440 case FileModel::MachOFile: 441 oce = AddMachOWriter(*codeGenPasses, out, *_target); 442 break; 443 case FileModel::ElfFile: 444 oce = AddELFWriter(*codeGenPasses, out, *_target); 445 break; 446 case FileModel::AsmFile: 447 break; 448 case FileModel::Error: 449 case FileModel::None: 450 errMsg = "target file type not supported"; 451 return true; 452 } 453 454 if (_target->addPassesToEmitFileFinish(*codeGenPasses, oce, 455 CodeGenOpt::Aggressive)) { 456 errMsg = "target does not support generation of this file type"; 457 return true; 458 } 459 460 // Run our queue of passes all at once now, efficiently. 461 passes.run(*mergedModule); 462 463 // Run the code generator, and write assembly file 464 codeGenPasses->doInitialization(); 465 466 for (Module::iterator 467 it = mergedModule->begin(), e = mergedModule->end(); it != e; ++it) 468 if (!it->isDeclaration()) 469 codeGenPasses->run(*it); 470 471 codeGenPasses->doFinalization(); 472 473 out.flush(); 474 475 return false; // success 476} 477 478 479/// Optimize merged modules using various IPO passes 480void LTOCodeGenerator::setCodeGenDebugOptions(const char* options) 481{ 482 std::string ops(options); 483 for (std::string o = getToken(ops); !o.empty(); o = getToken(ops)) { 484 // ParseCommandLineOptions() expects argv[0] to be program name. 485 // Lazily add that. 486 if ( _codegenOptions.empty() ) 487 _codegenOptions.push_back("libLTO"); 488 _codegenOptions.push_back(strdup(o.c_str())); 489 } 490} 491