Ejemplo n.º 1
0
static unsigned PrintActions1(const Compilation &C,
                              Action *A, 
                              std::map<Action*, unsigned> &Ids) {
  if (Ids.count(A))
    return Ids[A];
  
  std::string str;
  llvm::raw_string_ostream os(str);
  
  os << Action::getClassName(A->getKind()) << ", ";
  if (InputAction *IA = dyn_cast<InputAction>(A)) {    
    os << "\"" << IA->getInputArg().getValue(C.getArgs()) << "\"";
  } else if (BindArchAction *BIA = dyn_cast<BindArchAction>(A)) {
    os << '"' << (BIA->getArchName() ? BIA->getArchName() : 
                  C.getDefaultToolChain().getArchName()) << '"'
       << ", {" << PrintActions1(C, *BIA->begin(), Ids) << "}";
  } else {
    os << "{";
    for (Action::iterator it = A->begin(), ie = A->end(); it != ie;) {
      os << PrintActions1(C, *it, Ids);
      ++it;
      if (it != ie)
        os << ", ";
    }
    os << "}";
  }

  unsigned Id = Ids.size();
  Ids[A] = Id;
  llvm::errs() << Id << ": " << os.str() << ", " 
               << types::getTypeName(A->getType()) << "\n";

  return Id;
}
Ejemplo n.º 2
0
int Driver::ExecuteCompilation(const Compilation &C) const {
  // Just print if -### was present.
  if (C.getArgs().hasArg(options::OPT__HASH_HASH_HASH)) {
    C.PrintJob(llvm::errs(), C.getJobs(), "\n", true);
    return 0;
  }

  // If there were errors building the compilation, quit now.
  if (getDiags().getNumErrors())
    return 1;

  const Command *FailingCommand = 0;
  int Res = C.ExecuteJob(C.getJobs(), FailingCommand);
  
  // Remove temp files.
  C.CleanupFileList(C.getTempFiles());

  // If the compilation failed, remove result files as well.
  if (Res != 0 && !C.getArgs().hasArg(options::OPT_save_temps))
    C.CleanupFileList(C.getResultFiles(), true);

  // Print extra information about abnormal failures, if possible.
  if (Res) {
    // This is ad-hoc, but we don't want to be excessively noisy. If the result
    // status was 1, assume the command failed normally. In particular, if it
    // was the compiler then assume it gave a reasonable error code. Failures in
    // other tools are less common, and they generally have worse diagnostics,
    // so always print the diagnostic there.
    const Action &Source = FailingCommand->getSource();
    bool IsFriendlyTool = (isa<PreprocessJobAction>(Source) ||
                           isa<PrecompileJobAction>(Source) ||
                           isa<AnalyzeJobAction>(Source) ||
                           isa<CompileJobAction>(Source));

    if (!IsFriendlyTool || Res != 1) {
      // FIXME: See FIXME above regarding result code interpretation.
      if (Res < 0)
        Diag(clang::diag::err_drv_command_signalled) 
          << Source.getClassName() << -Res;
      else
        Diag(clang::diag::err_drv_command_failed) 
          << Source.getClassName() << Res;
    }
  }

  return Res;
}
Ejemplo n.º 3
0
void Driver::BuildJobsForAction(Compilation &C,
                                const Action *A,
                                const ToolChain *TC,
                                bool CanAcceptPipe,
                                bool AtTopLevel,
                                const char *LinkingOutput,
                                InputInfo &Result) const {
  llvm::PrettyStackTraceString CrashInfo("Building compilation jobs for action");

  bool UsePipes = C.getArgs().hasArg(options::OPT_pipe);
  // FIXME: Pipes are forcibly disabled until we support executing
  // them.
  if (!CCCPrintBindings)
    UsePipes = false;

  if (const InputAction *IA = dyn_cast<InputAction>(A)) {
    // FIXME: It would be nice to not claim this here; maybe the old
    // scheme of just using Args was better?
    const Arg &Input = IA->getInputArg();
    Input.claim();
    if (isa<PositionalArg>(Input)) {
      const char *Name = Input.getValue(C.getArgs());
      Result = InputInfo(Name, A->getType(), Name);
    } else
      Result = InputInfo(&Input, A->getType(), "");
    return;
  }

  if (const BindArchAction *BAA = dyn_cast<BindArchAction>(A)) {
    const char *ArchName = BAA->getArchName();
    std::string Arch;
    if (!ArchName) {
      Arch = C.getDefaultToolChain().getArchName();
      ArchName = Arch.c_str();
    }
    BuildJobsForAction(C,
                       *BAA->begin(), 
                       Host->getToolChain(C.getArgs(), ArchName),
                       CanAcceptPipe,
                       AtTopLevel,
                       LinkingOutput,
                       Result);
    return;
  }

  const JobAction *JA = cast<JobAction>(A);
  const Tool &T = TC->SelectTool(C, *JA);
  
  // See if we should use an integrated preprocessor. We do so when we
  // have exactly one input, since this is the only use case we care
  // about (irrelevant since we don't support combine yet).
  bool UseIntegratedCPP = false;
  const ActionList *Inputs = &A->getInputs();
  if (Inputs->size() == 1 && isa<PreprocessJobAction>(*Inputs->begin())) {
    if (!C.getArgs().hasArg(options::OPT_no_integrated_cpp) &&
        !C.getArgs().hasArg(options::OPT_traditional_cpp) &&
        !C.getArgs().hasArg(options::OPT_save_temps) &&
        T.hasIntegratedCPP()) {
      UseIntegratedCPP = true;
      Inputs = &(*Inputs)[0]->getInputs();
    }
  }

  // Only use pipes when there is exactly one input.
  bool TryToUsePipeInput = Inputs->size() == 1 && T.acceptsPipedInput();
  InputInfoList InputInfos;
  for (ActionList::const_iterator it = Inputs->begin(), ie = Inputs->end();
       it != ie; ++it) {
    InputInfo II;
    BuildJobsForAction(C, *it, TC, TryToUsePipeInput, 
                       /*AtTopLevel*/false,
                       LinkingOutput,
                       II);
    InputInfos.push_back(II);
  }

  // Determine if we should output to a pipe.
  bool OutputToPipe = false;
  if (CanAcceptPipe && T.canPipeOutput()) {
    // Some actions default to writing to a pipe if they are the top
    // level phase and there was no user override.
    //
    // FIXME: Is there a better way to handle this?
    if (AtTopLevel) {
      if (isa<PreprocessJobAction>(A) && !C.getArgs().hasArg(options::OPT_o))
        OutputToPipe = true;
    } else if (UsePipes)
      OutputToPipe = true;
  }

  // Figure out where to put the job (pipes).
  Job *Dest = &C.getJobs();
  if (InputInfos[0].isPipe()) {
    assert(TryToUsePipeInput && "Unrequested pipe!");
    assert(InputInfos.size() == 1 && "Unexpected pipe with multiple inputs.");
    Dest = &InputInfos[0].getPipe();
  }

  // Always use the first input as the base input.
  const char *BaseInput = InputInfos[0].getBaseInput();

  // Determine the place to write output to (nothing, pipe, or
  // filename) and where to put the new job.
  if (JA->getType() == types::TY_Nothing) {
    Result = InputInfo(A->getType(), BaseInput);
  } else if (OutputToPipe) {
    // Append to current piped job or create a new one as appropriate.
    PipedJob *PJ = dyn_cast<PipedJob>(Dest);
    if (!PJ) {
      PJ = new PipedJob();
      // FIXME: Temporary hack so that -ccc-print-bindings work until
      // we have pipe support. Please remove later.
      if (!CCCPrintBindings)
        cast<JobList>(Dest)->addJob(PJ);
      Dest = PJ;
    }
    Result = InputInfo(PJ, A->getType(), BaseInput);
  } else {
    Result = InputInfo(GetNamedOutputPath(C, *JA, BaseInput, AtTopLevel),
                       A->getType(), BaseInput);
  }

  if (CCCPrintBindings) {
    llvm::errs() << "# \"" << T.getToolChain().getTripleString() << '"'
                 << " - \"" << T.getName() << "\", inputs: [";
    for (unsigned i = 0, e = InputInfos.size(); i != e; ++i) {
      llvm::errs() << InputInfos[i].getAsString();
      if (i + 1 != e)
        llvm::errs() << ", ";
    }
    llvm::errs() << "], output: " << Result.getAsString() << "\n";
  } else {
    T.ConstructJob(C, *JA, *Dest, Result, InputInfos, 
                   C.getArgsForToolChain(TC), LinkingOutput);
  }
}
Ejemplo n.º 4
0
void Driver::BuildJobs(Compilation &C) const {
  llvm::PrettyStackTraceString CrashInfo("Building compilation jobs");
  bool SaveTemps = C.getArgs().hasArg(options::OPT_save_temps);
  bool UsePipes = C.getArgs().hasArg(options::OPT_pipe);

  // FIXME: Pipes are forcibly disabled until we support executing
  // them.
  if (!CCCPrintBindings)
    UsePipes = false;
  
  // -save-temps inhibits pipes.
  if (SaveTemps && UsePipes) {
    Diag(clang::diag::warn_drv_pipe_ignored_with_save_temps);
    UsePipes = true;
  }

  Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o);

  // It is an error to provide a -o option if we are making multiple
  // output files.
  if (FinalOutput) {
    unsigned NumOutputs = 0;
    for (ActionList::const_iterator it = C.getActions().begin(), 
           ie = C.getActions().end(); it != ie; ++it)
      if ((*it)->getType() != types::TY_Nothing)
        ++NumOutputs;
    
    if (NumOutputs > 1) {
      Diag(clang::diag::err_drv_output_argument_with_multiple_files);
      FinalOutput = 0;
    }
  }

  for (ActionList::const_iterator it = C.getActions().begin(), 
         ie = C.getActions().end(); it != ie; ++it) {
    Action *A = *it;

    // If we are linking an image for multiple archs then the linker
    // wants -arch_multiple and -final_output <final image
    // name>. Unfortunately, this doesn't fit in cleanly because we
    // have to pass this information down.
    //
    // FIXME: This is a hack; find a cleaner way to integrate this
    // into the process.
    const char *LinkingOutput = 0;
    if (isa<LipoJobAction>(A)) {
      if (FinalOutput)
        LinkingOutput = FinalOutput->getValue(C.getArgs());
      else
        LinkingOutput = DefaultImageName.c_str();
    }

    InputInfo II;
    BuildJobsForAction(C, A, &C.getDefaultToolChain(), 
                       /*CanAcceptPipe*/ true,
                       /*AtTopLevel*/ true,
                       /*LinkingOutput*/ LinkingOutput,
                       II);
  }

  // If the user passed -Qunused-arguments or there were errors, don't
  // warn about any unused arguments.
  if (Diags.getNumErrors() || 
      C.getArgs().hasArg(options::OPT_Qunused_arguments))
    return;

  // Claim -### here.
  (void) C.getArgs().hasArg(options::OPT__HASH_HASH_HASH);
  
  for (ArgList::const_iterator it = C.getArgs().begin(), ie = C.getArgs().end();
       it != ie; ++it) {
    Arg *A = *it;
      
    // FIXME: It would be nice to be able to send the argument to the
    // Diagnostic, so that extra values, position, and so on could be
    // printed.
    if (!A->isClaimed()) {
      if (A->getOption().hasNoArgumentUnused())
        continue;

      // Suppress the warning automatically if this is just a flag,
      // and it is an instance of an argument we already claimed.
      const Option &Opt = A->getOption();
      if (isa<FlagOption>(Opt)) {
        bool DuplicateClaimed = false;

        // FIXME: Use iterator.
        for (ArgList::const_iterator it = C.getArgs().begin(), 
               ie = C.getArgs().end(); it != ie; ++it) {
          if ((*it)->isClaimed() && (*it)->getOption().matches(Opt.getId())) {
            DuplicateClaimed = true;
            break;
          }
        }

        if (DuplicateClaimed)
          continue;
      }

      Diag(clang::diag::warn_drv_unused_argument) 
        << A->getAsString(C.getArgs());
    }
  }
}
Ejemplo n.º 5
0
bool Driver::HandleImmediateArgs(const Compilation &C) {
  // The order these options are handled in in gcc is all over the
  // place, but we don't expect inconsistencies w.r.t. that to matter
  // in practice.

  if (C.getArgs().hasArg(options::OPT_dumpversion)) {
    llvm::outs() << CLANG_VERSION_STRING "\n";
    return false;
  }

  if (C.getArgs().hasArg(options::OPT__help) || 
      C.getArgs().hasArg(options::OPT__help_hidden)) {
    PrintHelp(C.getArgs().hasArg(options::OPT__help_hidden));
    return false;
  }

  if (C.getArgs().hasArg(options::OPT__version)) {
    // Follow gcc behavior and use stdout for --version and stderr for -v
    PrintVersion(C, llvm::outs());
    return false;
  }

  if (C.getArgs().hasArg(options::OPT_v) || 
      C.getArgs().hasArg(options::OPT__HASH_HASH_HASH)) {
    PrintVersion(C, llvm::errs());
    SuppressMissingInputWarning = true;
  }

  const ToolChain &TC = C.getDefaultToolChain();
  if (C.getArgs().hasArg(options::OPT_print_search_dirs)) {
    llvm::outs() << "programs: =";
    for (ToolChain::path_list::const_iterator it = TC.getProgramPaths().begin(),
           ie = TC.getProgramPaths().end(); it != ie; ++it) {
      if (it != TC.getProgramPaths().begin())
        llvm::outs() << ':';
      llvm::outs() << *it;
    }
    llvm::outs() << "\n";
    llvm::outs() << "libraries: =";
    for (ToolChain::path_list::const_iterator it = TC.getFilePaths().begin(), 
           ie = TC.getFilePaths().end(); it != ie; ++it) {
      if (it != TC.getFilePaths().begin())
        llvm::outs() << ':';
      llvm::outs() << *it;
    }
    llvm::outs() << "\n";
    return false;
  }

  // FIXME: The following handlers should use a callback mechanism, we
  // don't know what the client would like to do.
  if (Arg *A = C.getArgs().getLastArg(options::OPT_print_file_name_EQ)) {
    llvm::outs() << GetFilePath(A->getValue(C.getArgs()), TC).toString() 
                 << "\n";
    return false;
  }

  if (Arg *A = C.getArgs().getLastArg(options::OPT_print_prog_name_EQ)) {
    llvm::outs() << GetProgramPath(A->getValue(C.getArgs()), TC).toString() 
                 << "\n";
    return false;
  }

  if (C.getArgs().hasArg(options::OPT_print_libgcc_file_name)) {
    llvm::outs() << GetFilePath("libgcc.a", TC).toString() << "\n";
    return false;
  }

  if (C.getArgs().hasArg(options::OPT_print_multi_lib)) {
    // FIXME: We need tool chain support for this.
    llvm::outs() << ".;\n";

    switch (C.getDefaultToolChain().getTriple().getArch()) {
    default:
      break;
      
    case llvm::Triple::x86_64:
      llvm::outs() << "x86_64;@m64" << "\n";
      break;

    case llvm::Triple::ppc64:
      llvm::outs() << "ppc64;@m64" << "\n";
      break;
    }
    return false;
  }

  // FIXME: What is the difference between print-multi-directory and
  // print-multi-os-directory?
  if (C.getArgs().hasArg(options::OPT_print_multi_directory) ||
      C.getArgs().hasArg(options::OPT_print_multi_os_directory)) {
    switch (C.getDefaultToolChain().getTriple().getArch()) {
    default:
    case llvm::Triple::x86:
    case llvm::Triple::ppc:
      llvm::outs() << "." << "\n";
      break;
      
    case llvm::Triple::x86_64:
      llvm::outs() << "x86_64" << "\n";
      break;

    case llvm::Triple::ppc64:
      llvm::outs() << "ppc64" << "\n";
      break;
    }
    return false;
  }

  return true;
}
Ejemplo n.º 6
0
Compilation *Driver::BuildCompilation(int argc, const char **argv) {
  llvm::PrettyStackTraceString CrashInfo("Compilation construction");

  // FIXME: Handle environment options which effect driver behavior,
  // somewhere (client?). GCC_EXEC_PREFIX, COMPILER_PATH,
  // LIBRARY_PATH, LPATH, CC_PRINT_OPTIONS, QA_OVERRIDE_GCC3_OPTIONS.

  // FIXME: What are we going to do with -V and -b?

  // FIXME: This stuff needs to go into the Compilation, not the
  // driver.
  bool CCCPrintOptions = false, CCCPrintActions = false;

  const char **Start = argv + 1, **End = argv + argc;
  const char *HostTriple = DefaultHostTriple.c_str();

  // Read -ccc args. 
  //
  // FIXME: We need to figure out where this behavior should
  // live. Most of it should be outside in the client; the parts that
  // aren't should have proper options, either by introducing new ones
  // or by overloading gcc ones like -V or -b.
  for (; Start != End && memcmp(*Start, "-ccc-", 5) == 0; ++Start) {
    const char *Opt = *Start + 5;
    
    if (!strcmp(Opt, "print-options")) {
      CCCPrintOptions = true;
    } else if (!strcmp(Opt, "print-phases")) {
      CCCPrintActions = true;
    } else if (!strcmp(Opt, "print-bindings")) {
      CCCPrintBindings = true;
    } else if (!strcmp(Opt, "cxx")) {
      CCCIsCXX = true;
    } else if (!strcmp(Opt, "echo")) {
      CCCEcho = true;
      
    } else if (!strcmp(Opt, "gcc-name")) {
      assert(Start+1 < End && "FIXME: -ccc- argument handling.");
      CCCGenericGCCName = *++Start;

    } else if (!strcmp(Opt, "clang-cxx")) {
      CCCUseClangCXX = true;
    } else if (!strcmp(Opt, "no-clang-cxx")) {
      CCCUseClangCXX = false;
    } else if (!strcmp(Opt, "pch-is-pch")) {
      CCCUsePCH = true;
    } else if (!strcmp(Opt, "pch-is-pth")) {
      CCCUsePCH = false;
    } else if (!strcmp(Opt, "no-clang")) {
      CCCUseClang = false;
    } else if (!strcmp(Opt, "no-clang-cpp")) {
      CCCUseClangCPP = false;
    } else if (!strcmp(Opt, "clang-archs")) {
      assert(Start+1 < End && "FIXME: -ccc- argument handling.");
      const char *Cur = *++Start;
    
      CCCClangArchs.clear();
      for (;;) {
        const char *Next = strchr(Cur, ',');

        if (Next) {
          if (Cur != Next)
            CCCClangArchs.insert(std::string(Cur, Next));
          Cur = Next + 1;
        } else {
          if (*Cur != '\0')
            CCCClangArchs.insert(std::string(Cur));
          break;
        }
      }

    } else if (!strcmp(Opt, "host-triple")) {
      assert(Start+1 < End && "FIXME: -ccc- argument handling.");
      HostTriple = *++Start;

    } else {
      // FIXME: Error handling.
      llvm::errs() << "invalid option: " << *Start << "\n";
      exit(1);
    }
  }

  InputArgList *Args = ParseArgStrings(Start, End);

  Host = GetHostInfo(HostTriple);

  // The compilation takes ownership of Args.
  Compilation *C = new Compilation(*this, *Host->getToolChain(*Args), Args);

  // FIXME: This behavior shouldn't be here.
  if (CCCPrintOptions) {
    PrintOptions(C->getArgs());
    return C;
  }

  if (!HandleImmediateArgs(*C))
    return C;

  // Construct the list of abstract actions to perform for this
  // compilation. We avoid passing a Compilation here simply to
  // enforce the abstraction that pipelining is not host or toolchain
  // dependent (other than the driver driver test).
  if (Host->useDriverDriver())
    BuildUniversalActions(C->getArgs(), C->getActions());
  else
    BuildActions(C->getArgs(), C->getActions());

  if (CCCPrintActions) {
    PrintActions(*C);
    return C;
  }

  BuildJobs(*C);

  return C;
}
Ejemplo n.º 7
0
void NVPTX::OpenMPLinker::ConstructJob(Compilation &C, const JobAction &JA,
                                       const InputInfo &Output,
                                       const InputInfoList &Inputs,
                                       const ArgList &Args,
                                       const char *LinkingOutput) const {
  const auto &TC =
      static_cast<const toolchains::CudaToolChain &>(getToolChain());
  assert(TC.getTriple().isNVPTX() && "Wrong platform");

  ArgStringList CmdArgs;

  // OpenMP uses nvlink to link cubin files. The result will be embedded in the
  // host binary by the host linker.
  assert(!JA.isHostOffloading(Action::OFK_OpenMP) &&
         "CUDA toolchain not expected for an OpenMP host device.");

  if (Output.isFilename()) {
    CmdArgs.push_back("-o");
    CmdArgs.push_back(Output.getFilename());
  } else
    assert(Output.isNothing() && "Invalid output.");
  if (Args.hasArg(options::OPT_g_Flag))
    CmdArgs.push_back("-g");

  if (Args.hasArg(options::OPT_v))
    CmdArgs.push_back("-v");

  StringRef GPUArch =
      Args.getLastArgValue(options::OPT_march_EQ);
  assert(!GPUArch.empty() && "At least one GPU Arch required for ptxas.");

  CmdArgs.push_back("-arch");
  CmdArgs.push_back(Args.MakeArgString(GPUArch));

  // Add paths specified in LIBRARY_PATH environment variable as -L options.
  addDirectoryList(Args, CmdArgs, "-L", "LIBRARY_PATH");

  // Add paths for the default clang library path.
  SmallString<256> DefaultLibPath =
      llvm::sys::path::parent_path(TC.getDriver().Dir);
  llvm::sys::path::append(DefaultLibPath, "lib" CLANG_LIBDIR_SUFFIX);
  CmdArgs.push_back(Args.MakeArgString(Twine("-L") + DefaultLibPath));

  // Add linking against library implementing OpenMP calls on NVPTX target.
  CmdArgs.push_back("-lomptarget-nvptx");

  for (const auto &II : Inputs) {
    if (II.getType() == types::TY_LLVM_IR ||
        II.getType() == types::TY_LTO_IR ||
        II.getType() == types::TY_LTO_BC ||
        II.getType() == types::TY_LLVM_BC) {
      C.getDriver().Diag(diag::err_drv_no_linker_llvm_support)
          << getToolChain().getTripleString();
      continue;
    }

    // Currently, we only pass the input files to the linker, we do not pass
    // any libraries that may be valid only for the host.
    if (!II.isFilename())
      continue;

    const char *CubinF = C.addTempFile(
        C.getArgs().MakeArgString(getToolChain().getInputFilename(II)));

    CmdArgs.push_back(CubinF);
  }

  AddOpenMPLinkerScript(getToolChain(), C, Output, Inputs, Args, CmdArgs, JA);

  const char *Exec =
      Args.MakeArgString(getToolChain().GetProgramPath("nvlink"));
  C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
}
Ejemplo n.º 8
0
/// Add OpenMP linker script arguments at the end of the argument list so that
/// the fat binary is built by embedding each of the device images into the
/// host. The linker script also defines a few symbols required by the code
/// generation so that the images can be easily retrieved at runtime by the
/// offloading library. This should be used only in tool chains that support
/// linker scripts.
void tools::AddOpenMPLinkerScript(const ToolChain &TC, Compilation &C,
                                  const InputInfo &Output,
                                  const InputInfoList &Inputs,
                                  const ArgList &Args, ArgStringList &CmdArgs,
                                  const JobAction &JA) {

  // If this is not an OpenMP host toolchain, we don't need to do anything.
  if (!JA.isHostOffloading(Action::OFK_OpenMP))
    return;

  // Create temporary linker script. Keep it if save-temps is enabled.
  const char *LKS;
  SmallString<256> Name = llvm::sys::path::filename(Output.getFilename());
  if (C.getDriver().isSaveTempsEnabled()) {
    llvm::sys::path::replace_extension(Name, "lk");
    LKS = C.getArgs().MakeArgString(Name.c_str());
  } else {
    llvm::sys::path::replace_extension(Name, "");
    Name = C.getDriver().GetTemporaryPath(Name, "lk");
    LKS = C.addTempFile(C.getArgs().MakeArgString(Name.c_str()));
  }

  // Add linker script option to the command.
  CmdArgs.push_back("-T");
  CmdArgs.push_back(LKS);

  // Create a buffer to write the contents of the linker script.
  std::string LksBuffer;
  llvm::raw_string_ostream LksStream(LksBuffer);

  // Get the OpenMP offload tool chains so that we can extract the triple
  // associated with each device input.
  auto OpenMPToolChains = C.getOffloadToolChains<Action::OFK_OpenMP>();
  assert(OpenMPToolChains.first != OpenMPToolChains.second &&
         "No OpenMP toolchains??");

  // Track the input file name and device triple in order to build the script,
  // inserting binaries in the designated sections.
  SmallVector<std::pair<std::string, const char *>, 8> InputBinaryInfo;

  // Add commands to embed target binaries. We ensure that each section and
  // image is 16-byte aligned. This is not mandatory, but increases the
  // likelihood of data to be aligned with a cache block in several main host
  // machines.
  LksStream << "/*\n";
  LksStream << "       OpenMP Offload Linker Script\n";
  LksStream << " *** Automatically generated by Clang ***\n";
  LksStream << "*/\n";
  LksStream << "TARGET(binary)\n";
  auto DTC = OpenMPToolChains.first;
  for (auto &II : Inputs) {
    const Action *A = II.getAction();
    // Is this a device linking action?
    if (A && isa<LinkJobAction>(A) &&
        A->isDeviceOffloading(Action::OFK_OpenMP)) {
      assert(DTC != OpenMPToolChains.second &&
             "More device inputs than device toolchains??");
      InputBinaryInfo.push_back(std::make_pair(
          DTC->second->getTriple().normalize(), II.getFilename()));
      ++DTC;
      LksStream << "INPUT(" << II.getFilename() << ")\n";
    }
  }

  assert(DTC == OpenMPToolChains.second &&
         "Less device inputs than device toolchains??");

  LksStream << "SECTIONS\n";
  LksStream << "{\n";

  // Put each target binary into a separate section.
  for (const auto &BI : InputBinaryInfo) {
    LksStream << "  .omp_offloading." << BI.first << " :\n";
    LksStream << "  ALIGN(0x10)\n";
    LksStream << "  {\n";
    LksStream << "    PROVIDE_HIDDEN(.omp_offloading.img_start." << BI.first
              << " = .);\n";
    LksStream << "    " << BI.second << "\n";
    LksStream << "    PROVIDE_HIDDEN(.omp_offloading.img_end." << BI.first
              << " = .);\n";
    LksStream << "  }\n";
  }

  // Add commands to define host entries begin and end. We use 1-byte subalign
  // so that the linker does not add any padding and the elements in this
  // section form an array.
  LksStream << "  .omp_offloading.entries :\n";
  LksStream << "  ALIGN(0x10)\n";
  LksStream << "  SUBALIGN(0x01)\n";
  LksStream << "  {\n";
  LksStream << "    PROVIDE_HIDDEN(.omp_offloading.entries_begin = .);\n";
  LksStream << "    *(.omp_offloading.entries)\n";
  LksStream << "    PROVIDE_HIDDEN(.omp_offloading.entries_end = .);\n";
  LksStream << "  }\n";
  LksStream << "}\n";
  LksStream << "INSERT BEFORE .data\n";
  LksStream.flush();

  // Dump the contents of the linker script if the user requested that. We
  // support this option to enable testing of behavior with -###.
  if (C.getArgs().hasArg(options::OPT_fopenmp_dump_offload_linker_script))
    llvm::errs() << LksBuffer;

  // If this is a dry run, do not create the linker script file.
  if (C.getArgs().hasArg(options::OPT__HASH_HASH_HASH))
    return;

  // Open script file and write the contents.
  std::error_code EC;
  llvm::raw_fd_ostream Lksf(LKS, EC, llvm::sys::fs::F_None);

  if (EC) {
    C.getDriver().Diag(clang::diag::err_unable_to_make_temp) << EC.message();
    return;
  }

  Lksf << LksBuffer;
}
Ejemplo n.º 9
0
static 
void ExecuteTemplightJobs(Driver &TheDriver, DiagnosticsEngine &Diags, 
    Compilation &C, Job &J, const char* Argv0,
    SmallVector<std::pair<int, const Command *>, 4>& FailingCommands) {
  if (JobList *jobs = dyn_cast<JobList>(&J)) {
    for (JobList::iterator it = jobs->begin(), it_end = jobs->end(); it != it_end; ++it)
      ExecuteTemplightJobs(TheDriver, Diags, C, *it, Argv0, FailingCommands);
    return;
  }
  
  Command *command = dyn_cast<Command>(&J);
  
  // Since argumentsFitWithinSystemLimits() may underestimate system's capacity
  // if the tool does not support response files, there is a chance/ that things
  // will just work without a response file, so we silently just skip it.
  if ( command && 
       command->getCreator().getResponseFilesSupport() != Tool::RF_None &&
       llvm::sys::argumentsFitWithinSystemLimits(command->getArguments()) ) {
    std::string TmpName = TheDriver.GetTemporaryPath("response", "txt");
    command->setResponseFile(C.addTempFile(C.getArgs().MakeArgString(
        TmpName.c_str())));
  }
  
  if ( command && (StringRef(command->getCreator().getName()) == "clang") ) {
    // Initialize a compiler invocation object from the clang (-cc1) arguments.
    const ArgStringList &cc_arguments = command->getArguments();
    const char** args_start = const_cast<const char**>(cc_arguments.data());
    const char** args_end = args_start + cc_arguments.size();
    
    std::unique_ptr<CompilerInstance> Clang(new CompilerInstance());
    
    int Res = !CompilerInvocation::CreateFromArgs(
        Clang->getInvocation(), args_start, args_end, Diags);
    if(Res)
      FailingCommands.push_back(std::make_pair(Res, command));
    
    Clang->getFrontendOpts().DisableFree = false;
    
    // Infer the builtin include path if unspecified.
    void *GetExecutablePathVP = (void *)(intptr_t) GetExecutablePath;
    if (Clang->getHeaderSearchOpts().UseBuiltinIncludes &&
        Clang->getHeaderSearchOpts().ResourceDir.empty())
      Clang->getHeaderSearchOpts().ResourceDir =
        CompilerInvocation::GetResourcesPath(Argv0, GetExecutablePathVP);
    
    // Create the compilers actual diagnostics engine.
    Clang->createDiagnostics();
    if (!Clang->hasDiagnostics()) {
      FailingCommands.push_back(std::make_pair(1, command));
      return;
    }
    
    LocalOutputFilename = ""; // Let the filename be created from options or output file name.
    std::string TemplightOutFile = TemplightAction::CreateOutputFilename(
      Clang.get(), "", InstProfiler, OutputToStdOut, MemoryProfile);
    // Check if templight filename is in a temporary path:
    llvm::SmallString<128> TDir;
    llvm::sys::path::system_temp_directory(true, TDir);
    if ( TDir.equals(llvm::sys::path::parent_path(llvm::StringRef(TemplightOutFile))) ) {
      C.addTempFile(TemplightOutFile.c_str());
      TempOutputFiles.push_back(TemplightOutFile);
    }
    
    // Execute the frontend actions.
    Res = ExecuteTemplightInvocation(Clang.get());
    if(Res)
      FailingCommands.push_back(std::make_pair(Res, command));
    
  } else {
    
    C.ExecuteJob(J, FailingCommands);
    
  }
  
}
Ejemplo n.º 10
0
Compilation *Driver::BuildCompilation(int argc, const char **argv) {
    llvm::PrettyStackTraceString CrashInfo("Compilation construction");

    // FIXME: Handle environment options which effect driver behavior, somewhere
    // (client?). GCC_EXEC_PREFIX, COMPILER_PATH, LIBRARY_PATH, LPATH,
    // CC_PRINT_OPTIONS.

    // FIXME: What are we going to do with -V and -b?

    // FIXME: This stuff needs to go into the Compilation, not the driver.
    bool CCCPrintOptions = false, CCCPrintActions = false;

    const char **Start = argv + 1, **End = argv + argc;
    const char *HostTriple = DefaultHostTriple.c_str();

    InputArgList *Args = ParseArgStrings(Start, End);

    // -no-canonical-prefixes is used very early in main.
    Args->ClaimAllArgs(options::OPT_no_canonical_prefixes);

    // Extract -ccc args.
    //
    // FIXME: We need to figure out where this behavior should live. Most of it
    // should be outside in the client; the parts that aren't should have proper
    // options, either by introducing new ones or by overloading gcc ones like -V
    // or -b.
    CCCPrintOptions = Args->hasArg(options::OPT_ccc_print_options);
    CCCPrintActions = Args->hasArg(options::OPT_ccc_print_phases);
    CCCPrintBindings = Args->hasArg(options::OPT_ccc_print_bindings);
    CCCIsCXX = Args->hasArg(options::OPT_ccc_cxx) || CCCIsCXX;
    CCCEcho = Args->hasArg(options::OPT_ccc_echo);
    if (const Arg *A = Args->getLastArg(options::OPT_ccc_gcc_name))
        CCCGenericGCCName = A->getValue(*Args);
    CCCUseClangCXX = Args->hasFlag(options::OPT_ccc_clang_cxx,
                                   options::OPT_ccc_no_clang_cxx,
                                   CCCUseClangCXX);
    CCCUsePCH = Args->hasFlag(options::OPT_ccc_pch_is_pch,
                              options::OPT_ccc_pch_is_pth);
    CCCUseClang = !Args->hasArg(options::OPT_ccc_no_clang);
    CCCUseClangCPP = !Args->hasArg(options::OPT_ccc_no_clang_cpp);
    if (const Arg *A = Args->getLastArg(options::OPT_ccc_clang_archs)) {
        llvm::StringRef Cur = A->getValue(*Args);

        CCCClangArchs.clear();
        while (!Cur.empty()) {
            std::pair<llvm::StringRef, llvm::StringRef> Split = Cur.split(',');

            if (!Split.first.empty()) {
                llvm::Triple::ArchType Arch =
                    llvm::Triple(Split.first, "", "").getArch();

                if (Arch == llvm::Triple::UnknownArch)
                    Diag(clang::diag::err_drv_invalid_arch_name) << Split.first;

                CCCClangArchs.insert(Arch);
            }

            Cur = Split.second;
        }
    }
    if (const Arg *A = Args->getLastArg(options::OPT_ccc_host_triple))
        HostTriple = A->getValue(*Args);
    if (const Arg *A = Args->getLastArg(options::OPT_ccc_install_dir))
        Dir = A->getValue(*Args);

    Host = GetHostInfo(HostTriple);

    // The compilation takes ownership of Args.
    Compilation *C = new Compilation(*this, *Host->CreateToolChain(*Args), Args);

    // FIXME: This behavior shouldn't be here.
    if (CCCPrintOptions) {
        PrintOptions(C->getArgs());
        return C;
    }

    if (!HandleImmediateArgs(*C))
        return C;

    // Construct the list of abstract actions to perform for this compilation. We
    // avoid passing a Compilation here simply to enforce the abstraction that
    // pipelining is not host or toolchain dependent (other than the driver driver
    // test).
    if (Host->useDriverDriver())
        BuildUniversalActions(C->getArgs(), C->getActions());
    else
        BuildActions(C->getArgs(), C->getActions());

    if (CCCPrintActions) {
        PrintActions(*C);
        return C;
    }

    BuildJobs(*C);

    return C;
}