brintos

brintos / llvm-project-archived public Read only

0
0
Text · 5.9 KiB · a820466 Raw
156 lines · cpp
1//===-- Main entry into the loader interface ------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This utility is used to launch standard programs onto the GPU in conjunction10// with the LLVM 'libc' project. It is designed to mimic a standard emulator11// workflow, allowing for unit tests to be run on the GPU directly.12//13//===----------------------------------------------------------------------===//14 15#include "llvm-gpu-loader.h"16 17#include "llvm/BinaryFormat/Magic.h"18#include "llvm/Object/ELF.h"19#include "llvm/Object/ELFObjectFile.h"20#include "llvm/Support/CommandLine.h"21#include "llvm/Support/Error.h"22#include "llvm/Support/FileSystem.h"23#include "llvm/Support/MemoryBuffer.h"24#include "llvm/Support/Path.h"25#include "llvm/Support/Signals.h"26#include "llvm/Support/WithColor.h"27#include "llvm/TargetParser/Triple.h"28 29#include <cerrno>30#include <cstdio>31#include <cstdlib>32#include <cstring>33#include <string>34#include <sys/file.h>35 36using namespace llvm;37 38static cl::OptionCategory loader_category("loader options");39 40static cl::opt<bool> help("h", cl::desc("Alias for -help"), cl::Hidden,41                          cl::cat(loader_category));42 43static cl::opt<unsigned>44    threads_x("threads-x", cl::desc("Number of threads in the 'x' dimension"),45              cl::init(1), cl::cat(loader_category));46static cl::opt<unsigned>47    threads_y("threads-y", cl::desc("Number of threads in the 'y' dimension"),48              cl::init(1), cl::cat(loader_category));49static cl::opt<unsigned>50    threads_z("threads-z", cl::desc("Number of threads in the 'z' dimension"),51              cl::init(1), cl::cat(loader_category));52static cl::alias threads("threads", cl::aliasopt(threads_x),53                         cl::desc("Alias for --threads-x"),54                         cl::cat(loader_category));55 56static cl::opt<unsigned>57    blocks_x("blocks-x", cl::desc("Number of blocks in the 'x' dimension"),58             cl::init(1), cl::cat(loader_category));59static cl::opt<unsigned>60    blocks_y("blocks-y", cl::desc("Number of blocks in the 'y' dimension"),61             cl::init(1), cl::cat(loader_category));62static cl::opt<unsigned>63    blocks_z("blocks-z", cl::desc("Number of blocks in the 'z' dimension"),64             cl::init(1), cl::cat(loader_category));65static cl::alias blocks("blocks", cl::aliasopt(blocks_x),66                        cl::desc("Alias for --blocks-x"),67                        cl::cat(loader_category));68 69static cl::opt<bool>70    print_resource_usage("print-resource-usage",71                         cl::desc("Output resource usage of launched kernels"),72                         cl::init(false), cl::cat(loader_category));73 74static cl::opt<std::string> file(cl::Positional, cl::Required,75                                 cl::desc("<gpu executable>"),76                                 cl::cat(loader_category));77static cl::list<std::string> args(cl::ConsumeAfter,78                                  cl::desc("<program arguments>..."),79                                  cl::cat(loader_category));80 81[[noreturn]] void report_error(Error E) {82  outs().flush();83  logAllUnhandledErrors(std::move(E), WithColor::error(errs(), "loader"));84  exit(EXIT_FAILURE);85}86 87std::string get_main_executable(const char *name) {88  void *ptr = (void *)(intptr_t)&get_main_executable;89  auto cow_path = sys::fs::getMainExecutable(name, ptr);90  return sys::path::parent_path(cow_path).str();91}92 93int main(int argc, const char **argv, const char **envp) {94  sys::PrintStackTraceOnErrorSignal(argv[0]);95  cl::HideUnrelatedOptions(loader_category);96  cl::ParseCommandLineOptions(97      argc, argv,98      "A utility used to launch unit tests built for a GPU target. This is\n"99      "intended to provide an intrface simular to cross-compiling emulators\n");100 101  if (help) {102    cl::PrintHelpMessage();103    return EXIT_SUCCESS;104  }105 106  ErrorOr<std::unique_ptr<MemoryBuffer>> image_or_err =107      MemoryBuffer::getFileOrSTDIN(file);108  if (std::error_code ec = image_or_err.getError())109    report_error(errorCodeToError(ec));110  MemoryBufferRef image = **image_or_err;111 112  SmallVector<const char *> new_argv = {file.c_str()};113  llvm::transform(args, std::back_inserter(new_argv),114                  [](const std::string &arg) { return arg.c_str(); });115 116  Expected<llvm::object::ELF64LEObjectFile> elf_or_err =117      llvm::object::ELF64LEObjectFile::create(image);118  if (!elf_or_err)119    report_error(elf_or_err.takeError());120 121  int ret = 1;122  if (elf_or_err->getArch() == Triple::amdgcn) {123#ifdef AMDHSA_SUPPORT124    LaunchParameters params{threads_x, threads_y, threads_z,125                            blocks_x,  blocks_y,  blocks_z};126 127    ret = load_amdhsa(new_argv.size(), new_argv.data(), envp,128                      const_cast<char *>(image.getBufferStart()),129                      image.getBufferSize(), params, print_resource_usage);130#else131    report_error(createStringError(132        "Unsupported architecture; %s",133        Triple::getArchTypeName(elf_or_err->getArch()).bytes_begin()));134#endif135  } else if (elf_or_err->getArch() == Triple::nvptx64) {136#ifdef NVPTX_SUPPORT137    LaunchParameters params{threads_x, threads_y, threads_z,138                            blocks_x,  blocks_y,  blocks_z};139 140    ret = load_nvptx(new_argv.size(), new_argv.data(), envp,141                     const_cast<char *>(image.getBufferStart()),142                     image.getBufferSize(), params, print_resource_usage);143#else144    report_error(createStringError(145        "Unsupported architecture; %s",146        Triple::getArchTypeName(elf_or_err->getArch()).bytes_begin()));147#endif148  } else {149    report_error(createStringError(150        "Unsupported architecture; %s",151        Triple::getArchTypeName(elf_or_err->getArch()).bytes_begin()));152  }153 154  return ret;155}156