Exemplo n.º 1
0
LTOModule *LTOModule::makeLTOModule(MemoryBuffer *buffer,
                                    std::string &errMsg) {
  static bool Initialized = false;
  if (!Initialized) {
    InitializeAllTargets();
    InitializeAllTargetMCs();
    InitializeAllAsmParsers();
    Initialized = true;
  }

  // parse bitcode buffer
  OwningPtr<Module> m(ParseBitcodeFile(buffer, getGlobalContext(), // @LOCALMOD
                                           &errMsg));
  if (!m) {
    delete buffer;
    return NULL;
  }

  std::string TripleStr = m->getTargetTriple();
  // @LOCALMOD-BEGIN
  // Pretend that we are ARM for name mangling and assembly conventions.
  // https://code.google.com/p/nativeclient/issues/detail?id=2554
  if (TripleStr == "le32-unknown-nacl") {
    TripleStr = "armv7a-none-nacl-gnueabi";
  }
  // @LOCALMOD-END
  if (TripleStr.empty())
    TripleStr = sys::getDefaultTargetTriple();
  llvm::Triple Triple(TripleStr);

  // find machine architecture for this module
  const Target *march = TargetRegistry::lookupTarget(TripleStr, errMsg);
  if (!march)
    return NULL;

  // construct LTOModule, hand over ownership of module and target
  SubtargetFeatures Features;
  Features.getDefaultSubtargetFeatures(Triple);
  std::string FeatureStr = Features.getString();
  // Set a default CPU for Darwin triples.
  std::string CPU;
  if (Triple.isOSDarwin()) {
    if (Triple.getArch() == llvm::Triple::x86_64)
      CPU = "core2";
    else if (Triple.getArch() == llvm::Triple::x86)
      CPU = "yonah";
  }
  TargetOptions Options;
  getTargetOptions(Options);
  TargetMachine *target = march->createTargetMachine(TripleStr, CPU, FeatureStr,
                                                     Options);
  LTOModule *Ret = new LTOModule(m.take(), target);
  if (Ret->parseSymbols(errMsg)) {
    delete Ret;
    return NULL;
  }

  return Ret;
}
Exemplo n.º 2
0
LTOModule *LTOModule::makeLTOModule(std::unique_ptr<MemoryBuffer> Buffer,
                                    TargetOptions options,
                                    std::string &errMsg) {
  ErrorOr<Module *> MOrErr =
      getLazyBitcodeModule(Buffer.get(), getGlobalContext());
  if (std::error_code EC = MOrErr.getError()) {
    errMsg = EC.message();
    return nullptr;
  }
  std::unique_ptr<Module> M(MOrErr.get());

  std::string TripleStr = M->getTargetTriple();
  if (TripleStr.empty())
    TripleStr = sys::getDefaultTargetTriple();
  llvm::Triple Triple(TripleStr);

  // find machine architecture for this module
  const Target *march = TargetRegistry::lookupTarget(TripleStr, errMsg);
  if (!march)
    return nullptr;

  // construct LTOModule, hand over ownership of module and target
  SubtargetFeatures Features;
  Features.getDefaultSubtargetFeatures(Triple);
  std::string FeatureStr = Features.getString();
  // Set a default CPU for Darwin triples.
  std::string CPU;
  if (Triple.isOSDarwin()) {
    if (Triple.getArch() == llvm::Triple::x86_64)
      CPU = "core2";
    else if (Triple.getArch() == llvm::Triple::x86)
      CPU = "yonah";
    else if (Triple.getArch() == llvm::Triple::arm64 ||
             Triple.getArch() == llvm::Triple::aarch64)
      CPU = "cyclone";
  }

  TargetMachine *target = march->createTargetMachine(TripleStr, CPU, FeatureStr,
                                                     options);
  M->materializeAllPermanently(true);
  M->setDataLayout(target->getDataLayout());

  std::unique_ptr<object::IRObjectFile> IRObj(
      new object::IRObjectFile(std::move(Buffer), std::move(M)));

  LTOModule *Ret = new LTOModule(std::move(IRObj), target);

  if (Ret->parseSymbols(errMsg)) {
    delete Ret;
    return nullptr;
  }

  Ret->parseMetadata();

  return Ret;
}
Exemplo n.º 3
0
LTOModule *LTOModule::makeLTOModule(MemoryBuffer *buffer,
                                    std::string &errMsg) {
    static bool Initialized = false;
    if (!Initialized) {
        InitializeAllTargets();
        InitializeAllTargetMCs();
        InitializeAllAsmParsers();
        Initialized = true;
    }

    // parse bitcode buffer
    OwningPtr<Module> m(getLazyBitcodeModule(buffer, getGlobalContext(),
                        &errMsg));
    if (!m) {
        delete buffer;
        return NULL;
    }

    std::string TripleStr = m->getTargetTriple();
    if (TripleStr.empty())
        TripleStr = sys::getDefaultTargetTriple();
    llvm::Triple Triple(TripleStr);

    // find machine architecture for this module
    const Target *march = TargetRegistry::lookupTarget(TripleStr, errMsg);
    if (!march)
        return NULL;

    // construct LTOModule, hand over ownership of module and target
    SubtargetFeatures Features;
    Features.getDefaultSubtargetFeatures(Triple);
    std::string FeatureStr = Features.getString();
    // Set a default CPU for Darwin triples.
    std::string CPU;
    if (Triple.isOSDarwin()) {
        if (Triple.getArch() == llvm::Triple::x86_64)
            CPU = "core2";
        else if (Triple.getArch() == llvm::Triple::x86)
            CPU = "yonah";
    }
    TargetOptions Options;
    getTargetOptions(Options);
    TargetMachine *target = march->createTargetMachine(TripleStr, CPU, FeatureStr,
                            Options);
    LTOModule *Ret = new LTOModule(m.take(), target);
    if (Ret->parseSymbols(errMsg)) {
        delete Ret;
        return NULL;
    }

    return Ret;
}
Exemplo n.º 4
0
LTOModule *LTOModule::makeLTOModule(MemoryBuffer *buffer,
                                    TargetOptions options,
                                    std::string &errMsg) {
  // parse bitcode buffer
  ErrorOr<Module *> ModuleOrErr =
      getLazyBitcodeModule(buffer, getGlobalContext());
  if (error_code EC = ModuleOrErr.getError()) {
    errMsg = EC.message();
    delete buffer;
    return NULL;
  }
  OwningPtr<Module> m(ModuleOrErr.get());

  std::string TripleStr = m->getTargetTriple();
  if (TripleStr.empty())
    TripleStr = sys::getDefaultTargetTriple();
  llvm::Triple Triple(TripleStr);

  // find machine architecture for this module
  const Target *march = TargetRegistry::lookupTarget(TripleStr, errMsg);
  if (!march)
    return NULL;

  // construct LTOModule, hand over ownership of module and target
  SubtargetFeatures Features;
  Features.getDefaultSubtargetFeatures(Triple);
  std::string FeatureStr = Features.getString();
  // Set a default CPU for Darwin triples.
  std::string CPU;
  if (Triple.isOSDarwin()) {
    if (Triple.getArch() == llvm::Triple::x86_64)
      CPU = "core2";
    else if (Triple.getArch() == llvm::Triple::x86)
      CPU = "yonah";
  }

  TargetMachine *target = march->createTargetMachine(TripleStr, CPU, FeatureStr,
                                                     options);
  m->materializeAllPermanently();

  LTOModule *Ret = new LTOModule(m.take(), target);
  if (Ret->parseSymbols(errMsg)) {
    delete Ret;
    return NULL;
  }

  Ret->parseMetadata();

  return Ret;
}
Exemplo n.º 5
0
LTOModule *LTOModule::makeLTOModule(MemoryBuffer *buffer,
                                    std::string &errMsg) {
  static bool Initialized = false;
  if (!Initialized) {
    InitializeAllTargets();
    InitializeAllTargetMCs();
    InitializeAllAsmParsers();
    Initialized = true;
  }

  // parse bitcode buffer
  OwningPtr<Module> m(getLazyBitcodeModule(buffer, getGlobalContext(),
                                           &errMsg));
  if (!m) {
    delete buffer;
    return NULL;
  }

  std::string Triple = m->getTargetTriple();
  if (Triple.empty())
    Triple = sys::getDefaultTargetTriple();

  // find machine architecture for this module
  const Target *march = TargetRegistry::lookupTarget(Triple, errMsg);
  if (!march)
    return NULL;

  // construct LTOModule, hand over ownership of module and target
  SubtargetFeatures Features;
  Features.getDefaultSubtargetFeatures(llvm::Triple(Triple));
  std::string FeatureStr = Features.getString();
  std::string CPU;
  TargetMachine *target = march->createTargetMachine(Triple, CPU, FeatureStr);
  LTOModule *Ret = new LTOModule(m.take(), target);
  if (Ret->ParseSymbols(errMsg)) {
    delete Ret;
    return NULL;
  }

  return Ret;
}
Exemplo n.º 6
0
LTOModule *LTOModule::makeLTOModule(MemoryBuffer *buffer,
                                    TargetOptions options,
                                    std::string &errMsg) {
  // parse bitcode buffer
  ErrorOr<Module *> ModuleOrErr =
      getLazyBitcodeModule(buffer, getGlobalContext());
  if (std::error_code EC = ModuleOrErr.getError()) {
    errMsg = EC.message();
    delete buffer;
    return nullptr;
  }
  std::unique_ptr<Module> m(ModuleOrErr.get());

  std::string TripleStr = m->getTargetTriple();
  if (TripleStr.empty())
    TripleStr = sys::getDefaultTargetTriple();
  llvm::Triple Triple(TripleStr);

  // find machine architecture for this module
  const Target *march = TargetRegistry::lookupTarget(TripleStr, errMsg);
  if (!march)
    return nullptr;

  // construct LTOModule, hand over ownership of module and target
  SubtargetFeatures Features;
  Features.getDefaultSubtargetFeatures(Triple);
  std::string FeatureStr = Features.getString();
  // Set a default CPU for Darwin triples.
  std::string CPU;
  if (Triple.isOSDarwin()) {
    if (Triple.getArch() == llvm::Triple::x86_64)
      CPU = "core2";
    else if (Triple.getArch() == llvm::Triple::x86)
      CPU = "yonah";
    else if (Triple.getArch() == llvm::Triple::arm64 ||
             Triple.getArch() == llvm::Triple::aarch64)
      CPU = "cyclone";
  }

  TargetMachine *target = march->createTargetMachine(TripleStr, CPU, FeatureStr,
                                                     options);
  m->materializeAllPermanently();

  LTOModule *Ret = new LTOModule(m.release(), target);

  // We need a MCContext set up in order to get mangled names of private
  // symbols. It is a bit odd that we need to report uses and definitions
  // of private symbols, but it does look like ld64 expects to be informed
  // of at least the ones with an 'l' prefix.
  MCContext &Context = Ret->_context;
  const TargetLoweringObjectFile &TLOF =
      target->getTargetLowering()->getObjFileLowering();
  const_cast<TargetLoweringObjectFile &>(TLOF).Initialize(Context, *target);

  if (Ret->parseSymbols(errMsg)) {
    delete Ret;
    return nullptr;
  }

  Ret->parseMetadata();

  return Ret;
}
Exemplo n.º 7
0
/// claim_file_hook - called by gold to see whether this file is one that
/// our plugin can handle. We'll try to open it and register all the symbols
/// with add_symbol if possible.
static ld_plugin_status claim_file_hook(const ld_plugin_input_file *file,
                                        int *claimed) {
  LTOModule *M;
  const void *view;
  std::unique_ptr<MemoryBuffer> buffer;
  if (get_view) {
    if (get_view(file->handle, &view) != LDPS_OK) {
      (*message)(LDPL_ERROR, "Failed to get a view of %s", file->name);
      return LDPS_ERR;
    }
  } else {
    int64_t offset = 0;
    // Gold has found what might be IR part-way inside of a file, such as
    // an .a archive.
    if (file->offset) {
      offset = file->offset;
    }
    if (std::error_code ec = MemoryBuffer::getOpenFileSlice(
            file->fd, file->name, buffer, file->filesize, offset)) {
      (*message)(LDPL_ERROR, ec.message().c_str());
      return LDPS_ERR;
    }
    view = buffer->getBufferStart();
  }

  if (!LTOModule::isBitcodeFile(view, file->filesize))
    return LDPS_OK;

  std::string Error;
  M = LTOModule::makeLTOModule(view, file->filesize, TargetOpts, Error);
  if (!M) {
    (*message)(LDPL_ERROR,
               "LLVM gold plugin has failed to create LTO module: %s",
               Error.c_str());
    return LDPS_OK;
  }

  *claimed = 1;
  Modules.resize(Modules.size() + 1);
  claimed_file &cf = Modules.back();

  if (!options::triple.empty())
    M->setTargetTriple(options::triple.c_str());

  cf.handle = file->handle;
  unsigned sym_count = M->getSymbolCount();
  cf.syms.reserve(sym_count);

  for (unsigned i = 0; i != sym_count; ++i) {
    lto_symbol_attributes attrs = M->getSymbolAttributes(i);
    if ((attrs & LTO_SYMBOL_SCOPE_MASK) == LTO_SYMBOL_SCOPE_INTERNAL)
      continue;

    cf.syms.push_back(ld_plugin_symbol());
    ld_plugin_symbol &sym = cf.syms.back();
    sym.name = strdup(M->getSymbolName(i));
    sym.version = NULL;

    int scope = attrs & LTO_SYMBOL_SCOPE_MASK;
    bool CanBeHidden = scope == LTO_SYMBOL_SCOPE_DEFAULT_CAN_BE_HIDDEN;
    if (!CanBeHidden)
      CannotBeHidden.insert(sym.name);
    switch (scope) {
      case LTO_SYMBOL_SCOPE_HIDDEN:
        sym.visibility = LDPV_HIDDEN;
        break;
      case LTO_SYMBOL_SCOPE_PROTECTED:
        sym.visibility = LDPV_PROTECTED;
        break;
      case 0: // extern
      case LTO_SYMBOL_SCOPE_DEFAULT:
      case LTO_SYMBOL_SCOPE_DEFAULT_CAN_BE_HIDDEN:
        sym.visibility = LDPV_DEFAULT;
        break;
      default:
        (*message)(LDPL_ERROR, "Unknown scope attribute: %d", scope);
        return LDPS_ERR;
    }

    int definition = attrs & LTO_SYMBOL_DEFINITION_MASK;
    sym.comdat_key = NULL;
    switch (definition) {
      case LTO_SYMBOL_DEFINITION_REGULAR:
        sym.def = LDPK_DEF;
        break;
      case LTO_SYMBOL_DEFINITION_UNDEFINED:
        sym.def = LDPK_UNDEF;
        break;
      case LTO_SYMBOL_DEFINITION_TENTATIVE:
        sym.def = LDPK_COMMON;
        break;
      case LTO_SYMBOL_DEFINITION_WEAK:
        sym.comdat_key = sym.name;
        sym.def = LDPK_WEAKDEF;
        break;
      case LTO_SYMBOL_DEFINITION_WEAKUNDEF:
        sym.def = LDPK_WEAKUNDEF;
        break;
      default:
        (*message)(LDPL_ERROR, "Unknown definition attribute: %d", definition);
        return LDPS_ERR;
    }

    sym.size = 0;

    sym.resolution = LDPR_UNKNOWN;
  }

  cf.syms.reserve(cf.syms.size());

  if (!cf.syms.empty()) {
    if ((*add_symbols)(cf.handle, cf.syms.size(), &cf.syms[0]) != LDPS_OK) {
      (*message)(LDPL_ERROR, "Unable to add symbols!");
      return LDPS_ERR;
    }
  }

  if (CodeGen) {
    std::string Error;
    if (!CodeGen->addModule(M, Error)) {
      (*message)(LDPL_ERROR, "Error linking module: %s", Error.c_str());
      return LDPS_ERR;
    }
  }

  delete M;

  return LDPS_OK;
}
Exemplo n.º 8
0
LTOModule *LTOModule::makeLTOModule(MemoryBufferRef Buffer,
                                    TargetOptions options, std::string &errMsg,
                                    LLVMContext *Context) {
  std::unique_ptr<LLVMContext> OwnedContext;
  if (!Context) {
    OwnedContext = llvm::make_unique<LLVMContext>();
    Context = OwnedContext.get();
  }

  ErrorOr<MemoryBufferRef> MBOrErr =
      IRObjectFile::findBitcodeInMemBuffer(Buffer);
  if (std::error_code EC = MBOrErr.getError()) {
    errMsg = EC.message();
    return nullptr;
  }
  ErrorOr<Module *> MOrErr = parseBitcodeFile(*MBOrErr, *Context);
  if (std::error_code EC = MOrErr.getError()) {
    errMsg = EC.message();
    return nullptr;
  }
  std::unique_ptr<Module> M(MOrErr.get());

  std::string TripleStr = M->getTargetTriple();
  if (TripleStr.empty())
    TripleStr = sys::getDefaultTargetTriple();
  llvm::Triple Triple(TripleStr);

  // find machine architecture for this module
  const Target *march = TargetRegistry::lookupTarget(TripleStr, errMsg);
  if (!march)
    return nullptr;

  // construct LTOModule, hand over ownership of module and target
  SubtargetFeatures Features;
  Features.getDefaultSubtargetFeatures(Triple);
  std::string FeatureStr = Features.getString();
  // Set a default CPU for Darwin triples.
  std::string CPU;
  if (Triple.isOSDarwin()) {
    if (Triple.getArch() == llvm::Triple::x86_64)
      CPU = "core2";
    else if (Triple.getArch() == llvm::Triple::x86)
      CPU = "yonah";
    else if (Triple.getArch() == llvm::Triple::aarch64)
      CPU = "cyclone";
  }

  TargetMachine *target = march->createTargetMachine(TripleStr, CPU, FeatureStr,
                                                     options);
  M->setDataLayout(target->getSubtargetImpl()->getDataLayout());

  std::unique_ptr<object::IRObjectFile> IRObj(
      new object::IRObjectFile(Buffer, std::move(M)));

  LTOModule *Ret;
  if (OwnedContext)
    Ret = new LTOModule(std::move(IRObj), target, std::move(OwnedContext));
  else
    Ret = new LTOModule(std::move(IRObj), target);

  if (Ret->parseSymbols(errMsg)) {
    delete Ret;
    return nullptr;
  }

  Ret->parseMetadata();

  return Ret;
}
Exemplo n.º 9
0
LTOModule *LTOModule::makeLTOModule(MemoryBufferRef Buffer,
                                    TargetOptions options, std::string &errMsg,
                                    LLVMContext *Context) {
  std::unique_ptr<LLVMContext> OwnedContext;
  if (!Context) {
    OwnedContext = llvm::make_unique<LLVMContext>();
    Context = OwnedContext.get();
  }

  // If we own a context, we know this is being used only for symbol
  // extraction, not linking.  Be lazy in that case.
  std::unique_ptr<Module> M = parseBitcodeFileImpl(
      Buffer, *Context,
      /* ShouldBeLazy */ static_cast<bool>(OwnedContext), errMsg);
  if (!M)
    return nullptr;

  std::string TripleStr = M->getTargetTriple();
  if (TripleStr.empty())
    TripleStr = sys::getDefaultTargetTriple();
  llvm::Triple Triple(TripleStr);

  // find machine architecture for this module
  const Target *march = TargetRegistry::lookupTarget(TripleStr, errMsg);
  if (!march)
    return nullptr;

  // construct LTOModule, hand over ownership of module and target
  SubtargetFeatures Features;
  Features.getDefaultSubtargetFeatures(Triple);
  std::string FeatureStr = Features.getString();
  // Set a default CPU for Darwin triples.
  std::string CPU;
  if (Triple.isOSDarwin()) {
    if (Triple.getArch() == llvm::Triple::x86_64)
      CPU = "core2";
    else if (Triple.getArch() == llvm::Triple::x86)
      CPU = "yonah";
    else if (Triple.getArch() == llvm::Triple::aarch64)
      CPU = "cyclone";
  }

  TargetMachine *target = march->createTargetMachine(TripleStr, CPU, FeatureStr,
                                                     options);
  M->setDataLayout(*target->getDataLayout());

  std::unique_ptr<object::IRObjectFile> IRObj(
      new object::IRObjectFile(Buffer, std::move(M)));

  LTOModule *Ret;
  if (OwnedContext)
    Ret = new LTOModule(std::move(IRObj), target, std::move(OwnedContext));
  else
    Ret = new LTOModule(std::move(IRObj), target);

  if (Ret->parseSymbols(errMsg)) {
    delete Ret;
    return nullptr;
  }

  Ret->parseMetadata();

  return Ret;
}
Exemplo n.º 10
0
int main(int argc, char **argv) {
    // Print a stack trace if we signal out.
    sys::PrintStackTraceOnErrorSignal();
    PrettyStackTraceProgram X(argc, argv);

    llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
    cl::ParseCommandLineOptions(argc, argv, "llvm LTO linker\n");

    if (OptLevel < '0' || OptLevel > '3') {
        errs() << argv[0] << ": optimization level must be between 0 and 3\n";
        return 1;
    }

    // Initialize the configured targets.
    InitializeAllTargets();
    InitializeAllTargetMCs();
    InitializeAllAsmPrinters();
    InitializeAllAsmParsers();

    // set up the TargetOptions for the machine
    TargetOptions Options = InitTargetOptionsFromCodeGenFlags();

    if (ListSymbolsOnly)
        return listSymbols(argv[0], Options);

    unsigned BaseArg = 0;

    LTOCodeGenerator CodeGen;

    if (UseDiagnosticHandler)
        CodeGen.setDiagnosticHandler(handleDiagnostics, nullptr);

    switch (RelocModel) {
    case Reloc::Static:
        CodeGen.setCodePICModel(LTO_CODEGEN_PIC_MODEL_STATIC);
        break;
    case Reloc::PIC_:
        CodeGen.setCodePICModel(LTO_CODEGEN_PIC_MODEL_DYNAMIC);
        break;
    case Reloc::DynamicNoPIC:
        CodeGen.setCodePICModel(LTO_CODEGEN_PIC_MODEL_DYNAMIC_NO_PIC);
        break;
    default:
        CodeGen.setCodePICModel(LTO_CODEGEN_PIC_MODEL_DEFAULT);
    }

    CodeGen.setDebugInfo(LTO_DEBUG_MODEL_DWARF);
    CodeGen.setTargetOptions(Options);

    llvm::StringSet<llvm::MallocAllocator> DSOSymbolsSet;
    for (unsigned i = 0; i < DSOSymbols.size(); ++i)
        DSOSymbolsSet.insert(DSOSymbols[i]);

    std::vector<std::string> KeptDSOSyms;

    for (unsigned i = BaseArg; i < InputFilenames.size(); ++i) {
        std::string error;
        std::unique_ptr<LTOModule> Module(
            LTOModule::createFromFile(InputFilenames[i].c_str(), Options, error));
        if (!error.empty()) {
            errs() << argv[0] << ": error loading file '" << InputFilenames[i]
                   << "': " << error << "\n";
            return 1;
        }

        LTOModule *LTOMod = Module.get();

        // We use the first input module as the destination module when
        // SetMergedModule is true.
        if (SetMergedModule && i == BaseArg) {
            // Transfer ownership to the code generator.
            CodeGen.setModule(Module.release());
        } else if (!CodeGen.addModule(Module.get())) {
            // Print a message here so that we know addModule() did not abort.
            errs() << argv[0] << ": error adding file '" << InputFilenames[i] << "'\n";
            return 1;
        }

        unsigned NumSyms = LTOMod->getSymbolCount();
        for (unsigned I = 0; I < NumSyms; ++I) {
            StringRef Name = LTOMod->getSymbolName(I);
            if (!DSOSymbolsSet.count(Name))
                continue;
            lto_symbol_attributes Attrs = LTOMod->getSymbolAttributes(I);
            unsigned Scope = Attrs & LTO_SYMBOL_SCOPE_MASK;
            if (Scope != LTO_SYMBOL_SCOPE_DEFAULT_CAN_BE_HIDDEN)
                KeptDSOSyms.push_back(Name);
        }
    }

    // Add all the exported symbols to the table of symbols to preserve.
    for (unsigned i = 0; i < ExportedSymbols.size(); ++i)
        CodeGen.addMustPreserveSymbol(ExportedSymbols[i].c_str());

    // Add all the dso symbols to the table of symbols to expose.
    for (unsigned i = 0; i < KeptDSOSyms.size(); ++i)
        CodeGen.addMustPreserveSymbol(KeptDSOSyms[i].c_str());

    // Set cpu and attrs strings for the default target/subtarget.
    CodeGen.setCpu(MCPU.c_str());

    CodeGen.setOptLevel(OptLevel - '0');

    std::string attrs;
    for (unsigned i = 0; i < MAttrs.size(); ++i) {
        if (i > 0)
            attrs.append(",");
        attrs.append(MAttrs[i]);
    }

    if (!attrs.empty())
        CodeGen.setAttr(attrs.c_str());

    if (!OutputFilename.empty()) {
        std::string ErrorInfo;
        std::unique_ptr<MemoryBuffer> Code = CodeGen.compile(
                DisableInline, DisableGVNLoadPRE, DisableLTOVectorization, ErrorInfo);
        if (!Code) {
            errs() << argv[0]
                   << ": error compiling the code: " << ErrorInfo << "\n";
            return 1;
        }

        std::error_code EC;
        raw_fd_ostream FileStream(OutputFilename, EC, sys::fs::F_None);
        if (EC) {
            errs() << argv[0] << ": error opening the file '" << OutputFilename
                   << "': " << EC.message() << "\n";
            return 1;
        }

        FileStream.write(Code->getBufferStart(), Code->getBufferSize());
    } else {
        std::string ErrorInfo;
        const char *OutputName = nullptr;
        if (!CodeGen.compile_to_file(&OutputName, DisableInline,
                                     DisableGVNLoadPRE, DisableLTOVectorization,
                                     ErrorInfo)) {
            errs() << argv[0]
                   << ": error compiling the code: " << ErrorInfo
                   << "\n";
            return 1;
        }

        outs() << "Wrote native object file '" << OutputName << "'\n";
    }

    return 0;
}