diff options
Diffstat (limited to 'tools')
-rw-r--r-- | tools/clang-format/ClangFormat.cpp | 284 | ||||
-rw-r--r-- | tools/clang-offload-wrapper/CMakeLists.txt | 23 | ||||
-rw-r--r-- | tools/clang-offload-wrapper/ClangOffloadWrapper.cpp | 371 | ||||
-rw-r--r-- | tools/driver/cc1_main.cpp | 44 | ||||
-rw-r--r-- | tools/driver/cc1as_main.cpp | 38 | ||||
-rw-r--r-- | tools/driver/driver.cpp | 8 |
6 files changed, 645 insertions, 123 deletions
diff --git a/tools/clang-format/ClangFormat.cpp b/tools/clang-format/ClangFormat.cpp index 60a7feb7119b4..f39c18bae3ff4 100644 --- a/tools/clang-format/ClangFormat.cpp +++ b/tools/clang-format/ClangFormat.cpp @@ -18,6 +18,7 @@ #include "clang/Basic/SourceManager.h" #include "clang/Basic/Version.h" #include "clang/Format/Format.h" +#include "clang/Frontend/TextDiagnosticPrinter.h" #include "clang/Rewrite/Core/Rewriter.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileSystem.h" @@ -51,13 +52,14 @@ static cl::list<unsigned> "Can only be used with one input file."), cl::cat(ClangFormatCategory)); static cl::list<std::string> -LineRanges("lines", cl::desc("<start line>:<end line> - format a range of\n" - "lines (both 1-based).\n" - "Multiple ranges can be formatted by specifying\n" - "several -lines arguments.\n" - "Can't be used with -offset and -length.\n" - "Can only be used with one input file."), - cl::cat(ClangFormatCategory)); + LineRanges("lines", + cl::desc("<start line>:<end line> - format a range of\n" + "lines (both 1-based).\n" + "Multiple ranges can be formatted by specifying\n" + "several -lines arguments.\n" + "Can't be used with -offset and -length.\n" + "Can only be used with one input file."), + cl::cat(ClangFormatCategory)); static cl::opt<std::string> Style("style", cl::desc(clang::format::StyleOptionHelpDescription), cl::init(clang::format::DefaultFormatStyle), @@ -72,12 +74,12 @@ static cl::opt<std::string> cl::init(clang::format::DefaultFallbackStyle), cl::cat(ClangFormatCategory)); -static cl::opt<std::string> -AssumeFileName("assume-filename", - cl::desc("When reading from stdin, clang-format assumes this\n" - "filename to look for a style config file (with\n" - "-style=file) and to determine the language."), - cl::init("<stdin>"), cl::cat(ClangFormatCategory)); +static cl::opt<std::string> AssumeFileName( + "assume-filename", + cl::desc("When reading from stdin, clang-format assumes this\n" + "filename to look for a style config file (with\n" + "-style=file) and to determine the language."), + cl::init("<stdin>"), cl::cat(ClangFormatCategory)); static cl::opt<bool> Inplace("i", cl::desc("Inplace edit <file>s, if specified."), @@ -107,6 +109,54 @@ static cl::opt<bool> Verbose("verbose", cl::desc("If set, shows the list of processed files"), cl::cat(ClangFormatCategory)); +// Use --dry-run to match other LLVM tools when you mean do it but don't +// actually do it +static cl::opt<bool> + DryRun("dry-run", + cl::desc("If set, do not actually make the formatting changes"), + cl::cat(ClangFormatCategory)); + +// Use -n as a common command as an alias for --dry-run. (git and make use -n) +static cl::alias DryRunShort("n", cl::desc("Alias for --dry-run"), + cl::cat(ClangFormatCategory), cl::aliasopt(DryRun), + cl::NotHidden); + +// Emulate being able to turn on/off the warning. +static cl::opt<bool> + WarnFormat("Wclang-format-violations", + cl::desc("Warnings about individual formatting changes needed. " + "Used only with --dry-run or -n"), + cl::init(true), cl::cat(ClangFormatCategory), cl::Hidden); + +static cl::opt<bool> + NoWarnFormat("Wno-clang-format-violations", + cl::desc("Do not warn about individual formatting changes " + "needed. Used only with --dry-run or -n"), + cl::init(false), cl::cat(ClangFormatCategory), cl::Hidden); + +static cl::opt<unsigned> ErrorLimit( + "ferror-limit", + cl::desc("Set the maximum number of clang-format errors to emit before " + "stopping (0 = no limit). Used only with --dry-run or -n"), + cl::init(0), cl::cat(ClangFormatCategory)); + +static cl::opt<bool> + WarningsAsErrors("Werror", + cl::desc("If set, changes formatting warnings to errors"), + cl::cat(ClangFormatCategory)); + +static cl::opt<bool> + ShowColors("fcolor-diagnostics", + cl::desc("If set, and on a color-capable terminal controls " + "whether or not to print diagnostics in color"), + cl::init(true), cl::cat(ClangFormatCategory), cl::Hidden); + +static cl::opt<bool> + NoShowColors("fno-color-diagnostics", + cl::desc("If set, and on a color-capable terminal controls " + "whether or not to print diagnostics in color"), + cl::init(false), cl::cat(ClangFormatCategory), cl::Hidden); + static cl::list<std::string> FileNames(cl::Positional, cl::desc("[<file> ...]"), cl::cat(ClangFormatCategory)); @@ -117,7 +167,8 @@ static FileID createInMemoryFile(StringRef FileName, MemoryBuffer *Source, SourceManager &Sources, FileManager &Files, llvm::vfs::InMemoryFileSystem *MemFS) { MemFS->addFileNoOwn(FileName, 0, Source); - return Sources.createFileID(Files.getFile(FileName), SourceLocation(), + auto File = Files.getFile(FileName); + return Sources.createFileID(File ? *File : nullptr, SourceLocation(), SrcMgr::C_User); } @@ -239,6 +290,95 @@ static void outputReplacementsXML(const Replacements &Replaces) { } } +// If BufStr has an invalid BOM, returns the BOM name; otherwise, returns +// nullptr. +static const char *getInValidBOM(StringRef BufStr) { + // Check to see if the buffer has a UTF Byte Order Mark (BOM). + // We only support UTF-8 with and without a BOM right now. See + // https://en.wikipedia.org/wiki/Byte_order_mark#Byte_order_marks_by_encoding + // for more information. + const char *InvalidBOM = + llvm::StringSwitch<const char *>(BufStr) + .StartsWith(llvm::StringLiteral::withInnerNUL("\x00\x00\xFE\xFF"), + "UTF-32 (BE)") + .StartsWith(llvm::StringLiteral::withInnerNUL("\xFF\xFE\x00\x00"), + "UTF-32 (LE)") + .StartsWith("\xFE\xFF", "UTF-16 (BE)") + .StartsWith("\xFF\xFE", "UTF-16 (LE)") + .StartsWith("\x2B\x2F\x76", "UTF-7") + .StartsWith("\xF7\x64\x4C", "UTF-1") + .StartsWith("\xDD\x73\x66\x73", "UTF-EBCDIC") + .StartsWith("\x0E\xFE\xFF", "SCSU") + .StartsWith("\xFB\xEE\x28", "BOCU-1") + .StartsWith("\x84\x31\x95\x33", "GB-18030") + .Default(nullptr); + return InvalidBOM; +} + +static bool +emitReplacementWarnings(const Replacements &Replaces, StringRef AssumedFileName, + const std::unique_ptr<llvm::MemoryBuffer> &Code) { + if (Replaces.empty()) { + return false; + } + + IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions(); + DiagOpts->ShowColors = (ShowColors && !NoShowColors); + + TextDiagnosticPrinter *DiagsBuffer = + new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts, false); + + IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); + IntrusiveRefCntPtr<DiagnosticsEngine> Diags( + new DiagnosticsEngine(DiagID, &*DiagOpts, DiagsBuffer)); + + IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem( + new llvm::vfs::InMemoryFileSystem); + FileManager Files(FileSystemOptions(), InMemoryFileSystem); + SourceManager Sources(*Diags, Files); + FileID FileID = createInMemoryFile(AssumedFileName, Code.get(), Sources, + Files, InMemoryFileSystem.get()); + + const unsigned ID = Diags->getCustomDiagID( + WarningsAsErrors ? clang::DiagnosticsEngine::Error + : clang::DiagnosticsEngine::Warning, + "code should be clang-formatted [-Wclang-format-violations]"); + + unsigned Errors = 0; + DiagsBuffer->BeginSourceFile(LangOptions(), nullptr); + if (WarnFormat && !NoWarnFormat) { + for (const auto &R : Replaces) { + Diags->Report( + Sources.getLocForStartOfFile(FileID).getLocWithOffset(R.getOffset()), + ID); + Errors++; + if (ErrorLimit && Errors >= ErrorLimit) + break; + } + } + DiagsBuffer->EndSourceFile(); + return WarningsAsErrors; +} + +static void outputXML(const Replacements &Replaces, + const Replacements &FormatChanges, + const FormattingAttemptStatus &Status, + const cl::opt<unsigned> &Cursor, + unsigned CursorPosition) { + outs() << "<?xml version='1.0'?>\n<replacements " + "xml:space='preserve' incomplete_format='" + << (Status.FormatComplete ? "false" : "true") << "'"; + if (!Status.FormatComplete) + outs() << " line='" << Status.Line << "'"; + outs() << ">\n"; + if (Cursor.getNumOccurrences() != 0) + outs() << "<cursor>" << FormatChanges.getShiftedCodePosition(CursorPosition) + << "</cursor>\n"; + + outputReplacementsXML(Replaces); + outs() << "</replacements>\n"; +} + // Returns true on error. static bool format(StringRef FileName) { if (!OutputXML && Inplace && FileName == "-") { @@ -248,8 +388,8 @@ static bool format(StringRef FileName) { // On Windows, overwriting a file with an open file mapping doesn't work, // so read the whole file into memory when formatting in-place. ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr = - !OutputXML && Inplace ? MemoryBuffer::getFileAsStream(FileName) : - MemoryBuffer::getFileOrSTDIN(FileName); + !OutputXML && Inplace ? MemoryBuffer::getFileAsStream(FileName) + : MemoryBuffer::getFileOrSTDIN(FileName); if (std::error_code EC = CodeOrErr.getError()) { errs() << EC.message() << "\n"; return true; @@ -258,25 +398,9 @@ static bool format(StringRef FileName) { if (Code->getBufferSize() == 0) return false; // Empty files are formatted correctly. - // Check to see if the buffer has a UTF Byte Order Mark (BOM). - // We only support UTF-8 with and without a BOM right now. See - // https://en.wikipedia.org/wiki/Byte_order_mark#Byte_order_marks_by_encoding - // for more information. StringRef BufStr = Code->getBuffer(); - const char *InvalidBOM = llvm::StringSwitch<const char *>(BufStr) - .StartsWith(llvm::StringLiteral::withInnerNUL("\x00\x00\xFE\xFF"), - "UTF-32 (BE)") - .StartsWith(llvm::StringLiteral::withInnerNUL("\xFF\xFE\x00\x00"), - "UTF-32 (LE)") - .StartsWith("\xFE\xFF", "UTF-16 (BE)") - .StartsWith("\xFF\xFE", "UTF-16 (LE)") - .StartsWith("\x2B\x2F\x76", "UTF-7") - .StartsWith("\xF7\x64\x4C", "UTF-1") - .StartsWith("\xDD\x73\x66\x73", "UTF-EBCDIC") - .StartsWith("\x0E\xFE\xFF", "SCSU") - .StartsWith("\xFB\xEE\x28", "BOCU-1") - .StartsWith("\x84\x31\x95\x33", "GB-18030") - .Default(nullptr); + + const char *InvalidBOM = getInValidBOM(BufStr); if (InvalidBOM) { errs() << "error: encoding with unsupported byte order mark \"" @@ -312,23 +436,15 @@ static bool format(StringRef FileName) { // Get new affected ranges after sorting `#includes`. Ranges = tooling::calculateRangesAfterReplacements(Replaces, Ranges); FormattingAttemptStatus Status; - Replacements FormatChanges = reformat(*FormatStyle, *ChangedCode, Ranges, - AssumedFileName, &Status); + Replacements FormatChanges = + reformat(*FormatStyle, *ChangedCode, Ranges, AssumedFileName, &Status); Replaces = Replaces.merge(FormatChanges); - if (OutputXML) { - outs() << "<?xml version='1.0'?>\n<replacements " - "xml:space='preserve' incomplete_format='" - << (Status.FormatComplete ? "false" : "true") << "'"; - if (!Status.FormatComplete) - outs() << " line='" << Status.Line << "'"; - outs() << ">\n"; - if (Cursor.getNumOccurrences() != 0) - outs() << "<cursor>" - << FormatChanges.getShiftedCodePosition(CursorPosition) - << "</cursor>\n"; - - outputReplacementsXML(Replaces); - outs() << "</replacements>\n"; + if (OutputXML || DryRun) { + if (DryRun) { + return emitReplacementWarnings(Replaces, AssumedFileName, Code); + } else { + outputXML(Replaces, FormatChanges, Status, Cursor, CursorPosition); + } } else { IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFileSystem( new llvm::vfs::InMemoryFileSystem); @@ -360,13 +476,45 @@ static bool format(StringRef FileName) { return false; } -} // namespace format -} // namespace clang +} // namespace format +} // namespace clang static void PrintVersion(raw_ostream &OS) { OS << clang::getClangToolFullVersion("clang-format") << '\n'; } +// Dump the configuration. +static int dumpConfig() { + StringRef FileName; + std::unique_ptr<llvm::MemoryBuffer> Code; + if (FileNames.empty()) { + // We can't read the code to detect the language if there's no + // file name, so leave Code empty here. + FileName = AssumeFileName; + } else { + // Read in the code in case the filename alone isn't enough to + // detect the language. + ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr = + MemoryBuffer::getFileOrSTDIN(FileNames[0]); + if (std::error_code EC = CodeOrErr.getError()) { + llvm::errs() << EC.message() << "\n"; + return 1; + } + FileName = (FileNames[0] == "-") ? AssumeFileName : FileNames[0]; + Code = std::move(CodeOrErr.get()); + } + llvm::Expected<clang::format::FormatStyle> FormatStyle = + clang::format::getStyle(Style, FileName, FallbackStyle, + Code ? Code->getBuffer() : ""); + if (!FormatStyle) { + llvm::errs() << llvm::toString(FormatStyle.takeError()) << "\n"; + return 1; + } + std::string Config = clang::format::configurationAsText(*FormatStyle); + outs() << Config << "\n"; + return 0; +} + int main(int argc, const char **argv) { llvm::InitLLVM X(argc, argv); @@ -388,34 +536,7 @@ int main(int argc, const char **argv) { } if (DumpConfig) { - StringRef FileName; - std::unique_ptr<llvm::MemoryBuffer> Code; - if (FileNames.empty()) { - // We can't read the code to detect the language if there's no - // file name, so leave Code empty here. - FileName = AssumeFileName; - } else { - // Read in the code in case the filename alone isn't enough to - // detect the language. - ErrorOr<std::unique_ptr<MemoryBuffer>> CodeOrErr = - MemoryBuffer::getFileOrSTDIN(FileNames[0]); - if (std::error_code EC = CodeOrErr.getError()) { - llvm::errs() << EC.message() << "\n"; - return 1; - } - FileName = (FileNames[0] == "-") ? AssumeFileName : FileNames[0]; - Code = std::move(CodeOrErr.get()); - } - llvm::Expected<clang::format::FormatStyle> FormatStyle = - clang::format::getStyle(Style, FileName, FallbackStyle, - Code ? Code->getBuffer() : ""); - if (!FormatStyle) { - llvm::errs() << llvm::toString(FormatStyle.takeError()) << "\n"; - return 1; - } - std::string Config = clang::format::configurationAsText(*FormatStyle); - outs() << Config << "\n"; - return 0; + return dumpConfig(); } bool Error = false; @@ -423,7 +544,8 @@ int main(int argc, const char **argv) { Error = clang::format::format("-"); return Error ? 1 : 0; } - if (FileNames.size() != 1 && (!Offsets.empty() || !Lengths.empty() || !LineRanges.empty())) { + if (FileNames.size() != 1 && + (!Offsets.empty() || !Lengths.empty() || !LineRanges.empty())) { errs() << "error: -offset, -length and -lines can only be used for " "single file.\n"; return 1; diff --git a/tools/clang-offload-wrapper/CMakeLists.txt b/tools/clang-offload-wrapper/CMakeLists.txt new file mode 100644 index 0000000000000..6f8940f88eabd --- /dev/null +++ b/tools/clang-offload-wrapper/CMakeLists.txt @@ -0,0 +1,23 @@ +set(LLVM_LINK_COMPONENTS BitWriter Core Support TransformUtils) + +if(NOT CLANG_BUILT_STANDALONE) + set(tablegen_deps intrinsics_gen) +endif() + +add_clang_tool(clang-offload-wrapper + ClangOffloadWrapper.cpp + + DEPENDS + ${tablegen_deps} + ) + +set(CLANG_OFFLOAD_WRAPPER_LIB_DEPS + clangBasic + ) + +add_dependencies(clang clang-offload-wrapper) + +clang_target_link_libraries(clang-offload-wrapper + PRIVATE + ${CLANG_OFFLOAD_WRAPPER_LIB_DEPS} + ) diff --git a/tools/clang-offload-wrapper/ClangOffloadWrapper.cpp b/tools/clang-offload-wrapper/ClangOffloadWrapper.cpp new file mode 100644 index 0000000000000..c3863422adf60 --- /dev/null +++ b/tools/clang-offload-wrapper/ClangOffloadWrapper.cpp @@ -0,0 +1,371 @@ +//===-- clang-offload-wrapper/ClangOffloadWrapper.cpp -----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Implementation of the offload wrapper tool. It takes offload target binaries +/// as input and creates wrapper bitcode file containing target binaries +/// packaged as data. Wrapper bitcode also includes initialization code which +/// registers target binaries in offloading runtime at program startup. +/// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/Version.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Bitcode/BitcodeWriter.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/GlobalVariable.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Errc.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/ErrorOr.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Signals.h" +#include "llvm/Support/ToolOutputFile.h" +#include "llvm/Support/WithColor.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Transforms/Utils/ModuleUtils.h" +#include <cassert> +#include <cstdint> + +using namespace llvm; + +static cl::opt<bool> Help("h", cl::desc("Alias for -help"), cl::Hidden); + +// Mark all our options with this category, everything else (except for -version +// and -help) will be hidden. +static cl::OptionCategory + ClangOffloadWrapperCategory("clang-offload-wrapper options"); + +static cl::opt<std::string> Output("o", cl::Required, + cl::desc("Output filename"), + cl::value_desc("filename"), + cl::cat(ClangOffloadWrapperCategory)); + +static cl::list<std::string> Inputs(cl::Positional, cl::OneOrMore, + cl::desc("<input files>"), + cl::cat(ClangOffloadWrapperCategory)); + +static cl::opt<std::string> + Target("target", cl::Required, + cl::desc("Target triple for the output module"), + cl::value_desc("triple"), cl::cat(ClangOffloadWrapperCategory)); + +namespace { + +class BinaryWrapper { + LLVMContext C; + Module M; + + StructType *EntryTy = nullptr; + StructType *ImageTy = nullptr; + StructType *DescTy = nullptr; + +private: + IntegerType *getSizeTTy() { + switch (M.getDataLayout().getPointerTypeSize(Type::getInt8PtrTy(C))) { + case 4u: + return Type::getInt32Ty(C); + case 8u: + return Type::getInt64Ty(C); + } + llvm_unreachable("unsupported pointer type size"); + } + + // struct __tgt_offload_entry { + // void *addr; + // char *name; + // size_t size; + // int32_t flags; + // int32_t reserved; + // }; + StructType *getEntryTy() { + if (!EntryTy) + EntryTy = StructType::create("__tgt_offload_entry", Type::getInt8PtrTy(C), + Type::getInt8PtrTy(C), getSizeTTy(), + Type::getInt32Ty(C), Type::getInt32Ty(C)); + return EntryTy; + } + + PointerType *getEntryPtrTy() { return PointerType::getUnqual(getEntryTy()); } + + // struct __tgt_device_image { + // void *ImageStart; + // void *ImageEnd; + // __tgt_offload_entry *EntriesBegin; + // __tgt_offload_entry *EntriesEnd; + // }; + StructType *getDeviceImageTy() { + if (!ImageTy) + ImageTy = StructType::create("__tgt_device_image", Type::getInt8PtrTy(C), + Type::getInt8PtrTy(C), getEntryPtrTy(), + getEntryPtrTy()); + return ImageTy; + } + + PointerType *getDeviceImagePtrTy() { + return PointerType::getUnqual(getDeviceImageTy()); + } + + // struct __tgt_bin_desc { + // int32_t NumDeviceImages; + // __tgt_device_image *DeviceImages; + // __tgt_offload_entry *HostEntriesBegin; + // __tgt_offload_entry *HostEntriesEnd; + // }; + StructType *getBinDescTy() { + if (!DescTy) + DescTy = StructType::create("__tgt_bin_desc", Type::getInt32Ty(C), + getDeviceImagePtrTy(), getEntryPtrTy(), + getEntryPtrTy()); + return DescTy; + } + + PointerType *getBinDescPtrTy() { + return PointerType::getUnqual(getBinDescTy()); + } + + /// Creates binary descriptor for the given device images. Binary descriptor + /// is an object that is passed to the offloading runtime at program startup + /// and it describes all device images available in the executable or shared + /// library. It is defined as follows + /// + /// __attribute__((visibility("hidden"))) + /// extern __tgt_offload_entry *__start_omp_offloading_entries; + /// __attribute__((visibility("hidden"))) + /// extern __tgt_offload_entry *__stop_omp_offloading_entries; + /// + /// static const char Image0[] = { <Bufs.front() contents> }; + /// ... + /// static const char ImageN[] = { <Bufs.back() contents> }; + /// + /// static const __tgt_device_image Images[] = { + /// { + /// Image0, /*ImageStart*/ + /// Image0 + sizeof(Image0), /*ImageEnd*/ + /// __start_omp_offloading_entries, /*EntriesBegin*/ + /// __stop_omp_offloading_entries /*EntriesEnd*/ + /// }, + /// ... + /// { + /// ImageN, /*ImageStart*/ + /// ImageN + sizeof(ImageN), /*ImageEnd*/ + /// __start_omp_offloading_entries, /*EntriesBegin*/ + /// __stop_omp_offloading_entries /*EntriesEnd*/ + /// } + /// }; + /// + /// static const __tgt_bin_desc BinDesc = { + /// sizeof(Images) / sizeof(Images[0]), /*NumDeviceImages*/ + /// Images, /*DeviceImages*/ + /// __start_omp_offloading_entries, /*HostEntriesBegin*/ + /// __stop_omp_offloading_entries /*HostEntriesEnd*/ + /// }; + /// + /// Global variable that represents BinDesc is returned. + GlobalVariable *createBinDesc(ArrayRef<ArrayRef<char>> Bufs) { + // Create external begin/end symbols for the offload entries table. + auto *EntriesB = new GlobalVariable( + M, getEntryTy(), /*isConstant*/ true, GlobalValue::ExternalLinkage, + /*Initializer*/ nullptr, "__start_omp_offloading_entries"); + EntriesB->setVisibility(GlobalValue::HiddenVisibility); + auto *EntriesE = new GlobalVariable( + M, getEntryTy(), /*isConstant*/ true, GlobalValue::ExternalLinkage, + /*Initializer*/ nullptr, "__stop_omp_offloading_entries"); + EntriesE->setVisibility(GlobalValue::HiddenVisibility); + + // We assume that external begin/end symbols that we have created above will + // be defined by the linker. But linker will do that only if linker inputs + // have section with "omp_offloading_entries" name which is not guaranteed. + // So, we just create dummy zero sized object in the offload entries section + // to force linker to define those symbols. + auto *DummyInit = + ConstantAggregateZero::get(ArrayType::get(getEntryTy(), 0u)); + auto *DummyEntry = new GlobalVariable( + M, DummyInit->getType(), true, GlobalVariable::ExternalLinkage, + DummyInit, "__dummy.omp_offloading.entry"); + DummyEntry->setSection("omp_offloading_entries"); + DummyEntry->setVisibility(GlobalValue::HiddenVisibility); + + auto *Zero = ConstantInt::get(getSizeTTy(), 0u); + Constant *ZeroZero[] = {Zero, Zero}; + + // Create initializer for the images array. + SmallVector<Constant *, 4u> ImagesInits; + ImagesInits.reserve(Bufs.size()); + for (ArrayRef<char> Buf : Bufs) { + auto *Data = ConstantDataArray::get(C, Buf); + auto *Image = new GlobalVariable(M, Data->getType(), /*isConstant*/ true, + GlobalVariable::InternalLinkage, Data, + ".omp_offloading.device_image"); + Image->setUnnamedAddr(GlobalValue::UnnamedAddr::Global); + + auto *Size = ConstantInt::get(getSizeTTy(), Buf.size()); + Constant *ZeroSize[] = {Zero, Size}; + + auto *ImageB = ConstantExpr::getGetElementPtr(Image->getValueType(), + Image, ZeroZero); + auto *ImageE = ConstantExpr::getGetElementPtr(Image->getValueType(), + Image, ZeroSize); + + ImagesInits.push_back(ConstantStruct::get(getDeviceImageTy(), ImageB, + ImageE, EntriesB, EntriesE)); + } + + // Then create images array. + auto *ImagesData = ConstantArray::get( + ArrayType::get(getDeviceImageTy(), ImagesInits.size()), ImagesInits); + + auto *Images = + new GlobalVariable(M, ImagesData->getType(), /*isConstant*/ true, + GlobalValue::InternalLinkage, ImagesData, + ".omp_offloading.device_images"); + Images->setUnnamedAddr(GlobalValue::UnnamedAddr::Global); + + auto *ImagesB = ConstantExpr::getGetElementPtr(Images->getValueType(), + Images, ZeroZero); + + // And finally create the binary descriptor object. + auto *DescInit = ConstantStruct::get( + getBinDescTy(), + ConstantInt::get(Type::getInt32Ty(C), ImagesInits.size()), ImagesB, + EntriesB, EntriesE); + + return new GlobalVariable(M, DescInit->getType(), /*isConstant*/ true, + GlobalValue::InternalLinkage, DescInit, + ".omp_offloading.descriptor"); + } + + void createRegisterFunction(GlobalVariable *BinDesc) { + auto *FuncTy = FunctionType::get(Type::getVoidTy(C), /*isVarArg*/ false); + auto *Func = Function::Create(FuncTy, GlobalValue::InternalLinkage, + ".omp_offloading.descriptor_reg", &M); + Func->setSection(".text.startup"); + + // Get __tgt_register_lib function declaration. + auto *RegFuncTy = FunctionType::get(Type::getVoidTy(C), getBinDescPtrTy(), + /*isVarArg*/ false); + FunctionCallee RegFuncC = + M.getOrInsertFunction("__tgt_register_lib", RegFuncTy); + + // Construct function body + IRBuilder<> Builder(BasicBlock::Create(C, "entry", Func)); + Builder.CreateCall(RegFuncC, BinDesc); + Builder.CreateRetVoid(); + + // Add this function to constructors. + appendToGlobalCtors(M, Func, 0); + } + + void createUnregisterFunction(GlobalVariable *BinDesc) { + auto *FuncTy = FunctionType::get(Type::getVoidTy(C), /*isVarArg*/ false); + auto *Func = Function::Create(FuncTy, GlobalValue::InternalLinkage, + ".omp_offloading.descriptor_unreg", &M); + Func->setSection(".text.startup"); + + // Get __tgt_unregister_lib function declaration. + auto *UnRegFuncTy = FunctionType::get(Type::getVoidTy(C), getBinDescPtrTy(), + /*isVarArg*/ false); + FunctionCallee UnRegFuncC = + M.getOrInsertFunction("__tgt_unregister_lib", UnRegFuncTy); + + // Construct function body + IRBuilder<> Builder(BasicBlock::Create(C, "entry", Func)); + Builder.CreateCall(UnRegFuncC, BinDesc); + Builder.CreateRetVoid(); + + // Add this function to global destructors. + appendToGlobalDtors(M, Func, 0); + } + +public: + BinaryWrapper(StringRef Target) : M("offload.wrapper.object", C) { + M.setTargetTriple(Target); + } + + const Module &wrapBinaries(ArrayRef<ArrayRef<char>> Binaries) { + GlobalVariable *Desc = createBinDesc(Binaries); + assert(Desc && "no binary descriptor"); + createRegisterFunction(Desc); + createUnregisterFunction(Desc); + return M; + } +}; + +} // anonymous namespace + +int main(int argc, const char **argv) { + sys::PrintStackTraceOnErrorSignal(argv[0]); + + cl::HideUnrelatedOptions(ClangOffloadWrapperCategory); + cl::SetVersionPrinter([](raw_ostream &OS) { + OS << clang::getClangToolFullVersion("clang-offload-wrapper") << '\n'; + }); + cl::ParseCommandLineOptions( + argc, argv, + "A tool to create a wrapper bitcode for offload target binaries. Takes " + "offload\ntarget binaries as input and produces bitcode file containing " + "target binaries packaged\nas data and initialization code which " + "registers target binaries in offload runtime.\n"); + + if (Help) { + cl::PrintHelpMessage(); + return 0; + } + + auto reportError = [argv](Error E) { + logAllUnhandledErrors(std::move(E), WithColor::error(errs(), argv[0])); + }; + + if (Triple(Target).getArch() == Triple::UnknownArch) { + reportError(createStringError( + errc::invalid_argument, "'" + Target + "': unsupported target triple")); + return 1; + } + + // Read device binaries. + SmallVector<std::unique_ptr<MemoryBuffer>, 4u> Buffers; + SmallVector<ArrayRef<char>, 4u> Images; + Buffers.reserve(Inputs.size()); + Images.reserve(Inputs.size()); + for (const std::string &File : Inputs) { + ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr = + MemoryBuffer::getFileOrSTDIN(File); + if (!BufOrErr) { + reportError(createFileError(File, BufOrErr.getError())); + return 1; + } + const std::unique_ptr<MemoryBuffer> &Buf = + Buffers.emplace_back(std::move(*BufOrErr)); + Images.emplace_back(Buf->getBufferStart(), Buf->getBufferSize()); + } + + // Create the output file to write the resulting bitcode to. + std::error_code EC; + ToolOutputFile Out(Output, EC, sys::fs::OF_None); + if (EC) { + reportError(createFileError(Output, EC)); + return 1; + } + + // Create a wrapper for device binaries and write its bitcode to the file. + WriteBitcodeToFile(BinaryWrapper(Target).wrapBinaries( + makeArrayRef(Images.data(), Images.size())), + Out.os()); + if (Out.os().has_error()) { + reportError(createFileError(Output, Out.os().error())); + return 1; + } + + // Success. + Out.keep(); + return 0; +} diff --git a/tools/driver/cc1_main.cpp b/tools/driver/cc1_main.cpp index 7315a1357089c..9e4f32da884fe 100644 --- a/tools/driver/cc1_main.cpp +++ b/tools/driver/cc1_main.cpp @@ -194,8 +194,8 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) { // Register the support for object-file-wrapped Clang modules. auto PCHOps = Clang->getPCHContainerOperations(); - PCHOps->registerWriter(llvm::make_unique<ObjectFilePCHContainerWriter>()); - PCHOps->registerReader(llvm::make_unique<ObjectFilePCHContainerReader>()); + PCHOps->registerWriter(std::make_unique<ObjectFilePCHContainerWriter>()); + PCHOps->registerReader(std::make_unique<ObjectFilePCHContainerReader>()); // Initialize targets first, so that --version shows registered targets. llvm::InitializeAllTargets(); @@ -213,12 +213,13 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) { IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions(); TextDiagnosticBuffer *DiagsBuffer = new TextDiagnosticBuffer; DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagsBuffer); - bool Success = CompilerInvocation::CreateFromArgs( - Clang->getInvocation(), Argv.begin(), Argv.end(), Diags); - - if (Clang->getFrontendOpts().TimeTrace) - llvm::timeTraceProfilerInitialize(); + bool Success = + CompilerInvocation::CreateFromArgs(Clang->getInvocation(), Argv, Diags); + if (Clang->getFrontendOpts().TimeTrace) { + llvm::timeTraceProfilerInitialize( + Clang->getFrontendOpts().TimeTraceGranularity); + } // --print-supported-cpus takes priority over the actual compilation. if (Clang->getFrontendOpts().PrintSupportedCPUs) return PrintSupportedCPUs(Clang->getTargetOpts().Triple); @@ -252,26 +253,23 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) { // If any timers were active but haven't been destroyed yet, print their // results now. This happens in -disable-free mode. llvm::TimerGroup::printAll(llvm::errs()); + llvm::TimerGroup::clearAll(); if (llvm::timeTraceProfilerEnabled()) { SmallString<128> Path(Clang->getFrontendOpts().OutputFile); llvm::sys::path::replace_extension(Path, "json"); - auto profilerOutput = - Clang->createOutputFile(Path.str(), - /*Binary=*/false, - /*RemoveFileOnSignal=*/false, "", - /*Extension=*/"json", - /*useTemporary=*/false); - - llvm::timeTraceProfilerWrite(*profilerOutput); - // FIXME(ibiryukov): make profilerOutput flush in destructor instead. - profilerOutput->flush(); - llvm::timeTraceProfilerCleanup(); - - llvm::errs() << "Time trace json-file dumped to " << Path.str() << "\n"; - llvm::errs() - << "Use chrome://tracing or Speedscope App " - "(https://www.speedscope.app) for flamegraph visualization\n"; + if (auto profilerOutput = + Clang->createOutputFile(Path.str(), + /*Binary=*/false, + /*RemoveFileOnSignal=*/false, "", + /*Extension=*/"json", + /*useTemporary=*/false)) { + + llvm::timeTraceProfilerWrite(*profilerOutput); + // FIXME(ibiryukov): make profilerOutput flush in destructor instead. + profilerOutput->flush(); + llvm::timeTraceProfilerCleanup(); + } } // Our error handler depends on the Diagnostics object, which we're diff --git a/tools/driver/cc1as_main.cpp b/tools/driver/cc1as_main.cpp index a2902b6aa9263..ae58a95f36f5b 100644 --- a/tools/driver/cc1as_main.cpp +++ b/tools/driver/cc1as_main.cpp @@ -131,6 +131,7 @@ struct AssemblerInvocation { unsigned RelaxAll : 1; unsigned NoExecStack : 1; unsigned FatalWarnings : 1; + unsigned NoWarn : 1; unsigned IncrementalLinkerCompatible : 1; unsigned EmbedBitcode : 1; @@ -156,6 +157,7 @@ public: RelaxAll = 0; NoExecStack = 0; FatalWarnings = 0; + NoWarn = 0; IncrementalLinkerCompatible = 0; DwarfVersion = 0; EmbedBitcode = 0; @@ -174,12 +176,12 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts, bool Success = true; // Parse the arguments. - std::unique_ptr<OptTable> OptTbl(createDriverOptTable()); + const OptTable &OptTbl = getDriverOptTable(); const unsigned IncludedFlagsBitmask = options::CC1AsOption; unsigned MissingArgIndex, MissingArgCount; - InputArgList Args = OptTbl->ParseArgs(Argv, MissingArgIndex, MissingArgCount, - IncludedFlagsBitmask); + InputArgList Args = OptTbl.ParseArgs(Argv, MissingArgIndex, MissingArgCount, + IncludedFlagsBitmask); // Check for missing argument error. if (MissingArgCount) { @@ -192,7 +194,7 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts, for (const Arg *A : Args.filtered(OPT_UNKNOWN)) { auto ArgString = A->getAsString(Args); std::string Nearest; - if (OptTbl->findNearest(ArgString, Nearest, IncludedFlagsBitmask) > 1) + if (OptTbl.findNearest(ArgString, Nearest, IncludedFlagsBitmask) > 1) Diags.Report(diag::err_drv_unknown_argument) << ArgString; else Diags.Report(diag::err_drv_unknown_argument_with_suggestion) @@ -285,6 +287,7 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts, Opts.RelaxAll = Args.hasArg(OPT_mrelax_all); Opts.NoExecStack = Args.hasArg(OPT_mno_exec_stack); Opts.FatalWarnings = Args.hasArg(OPT_massembler_fatal_warnings); + Opts.NoWarn = Args.hasArg(OPT_massembler_no_warn); Opts.RelocationModel = Args.getLastArgValue(OPT_mrelocation_model, "pic"); Opts.TargetABI = Args.getLastArgValue(OPT_target_abi); Opts.IncrementalLinkerCompatible = @@ -312,8 +315,8 @@ getOutputStream(StringRef Path, DiagnosticsEngine &Diags, bool Binary) { sys::RemoveFileOnSignal(Path); std::error_code EC; - auto Out = llvm::make_unique<raw_fd_ostream>( - Path, EC, (Binary ? sys::fs::F_None : sys::fs::F_Text)); + auto Out = std::make_unique<raw_fd_ostream>( + Path, EC, (Binary ? sys::fs::OF_None : sys::fs::OF_Text)); if (EC) { Diags.Report(diag::err_fe_unable_to_open_output) << Path << EC.message(); return nullptr; @@ -374,7 +377,8 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts, // MCObjectFileInfo needs a MCContext reference in order to initialize itself. std::unique_ptr<MCObjectFileInfo> MOFI(new MCObjectFileInfo()); - MCContext Ctx(MAI.get(), MRI.get(), MOFI.get(), &SrcMgr); + MCTargetOptions MCOptions; + MCContext Ctx(MAI.get(), MRI.get(), MOFI.get(), &SrcMgr, &MCOptions); bool PIC = false; if (Opts.RelocationModel == "static") { @@ -431,7 +435,8 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts, raw_pwrite_stream *Out = FDOS.get(); std::unique_ptr<buffer_ostream> BOS; - MCTargetOptions MCOptions; + MCOptions.MCNoWarn = Opts.NoWarn; + MCOptions.MCFatalWarnings = Opts.FatalWarnings; MCOptions.ABIName = Opts.TargetABI; // FIXME: There is a bit of code duplication with addPassesToEmitFile. @@ -445,7 +450,7 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts, std::unique_ptr<MCAsmBackend> MAB( TheTarget->createMCAsmBackend(*STI, *MRI, MCOptions)); - auto FOut = llvm::make_unique<formatted_raw_ostream>(*Out); + auto FOut = std::make_unique<formatted_raw_ostream>(*Out); Str.reset(TheTarget->createAsmStreamer( Ctx, std::move(FOut), /*asmverbose*/ true, /*useDwarfDirectory*/ true, IP, std::move(CE), std::move(MAB), @@ -456,7 +461,7 @@ static bool ExecuteAssembler(AssemblerInvocation &Opts, assert(Opts.OutputType == AssemblerInvocation::FT_Obj && "Invalid file type!"); if (!FDOS->supportsSeeking()) { - BOS = make_unique<buffer_ostream>(*FDOS); + BOS = std::make_unique<buffer_ostream>(*FDOS); Out = BOS.get(); } @@ -569,11 +574,11 @@ int cc1as_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) { return 1; if (Asm.ShowHelp) { - std::unique_ptr<OptTable> Opts(driver::createDriverOptTable()); - Opts->PrintHelp(llvm::outs(), "clang -cc1as [options] file...", - "Clang Integrated Assembler", - /*Include=*/driver::options::CC1AsOption, /*Exclude=*/0, - /*ShowAllAliases=*/false); + getDriverOptTable().PrintHelp( + llvm::outs(), "clang -cc1as [options] file...", + "Clang Integrated Assembler", + /*Include=*/driver::options::CC1AsOption, /*Exclude=*/0, + /*ShowAllAliases=*/false); return 0; } @@ -590,7 +595,7 @@ int cc1as_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) { // FIXME: Remove this, one day. if (!Asm.LLVMArgs.empty()) { unsigned NumArgs = Asm.LLVMArgs.size(); - auto Args = llvm::make_unique<const char*[]>(NumArgs + 2); + auto Args = std::make_unique<const char*[]>(NumArgs + 2); Args[0] = "clang (LLVM option parsing)"; for (unsigned i = 0; i != NumArgs; ++i) Args[i + 1] = Asm.LLVMArgs[i].c_str(); @@ -604,6 +609,7 @@ int cc1as_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) { // If any timers were active but haven't been destroyed yet, print their // results now. TimerGroup::printAll(errs()); + TimerGroup::clearAll(); return !!Failed; } diff --git a/tools/driver/driver.cpp b/tools/driver/driver.cpp index dfc96d308ab50..f1600490017d7 100644 --- a/tools/driver/driver.cpp +++ b/tools/driver/driver.cpp @@ -13,6 +13,7 @@ #include "clang/Driver/Driver.h" #include "clang/Basic/DiagnosticOptions.h" +#include "clang/Basic/Stack.h" #include "clang/Driver/Compilation.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Options.h" @@ -270,10 +271,9 @@ static void FixupDiagPrefixExeName(TextDiagnosticPrinter *DiagClient, static DiagnosticOptions * CreateAndPopulateDiagOpts(ArrayRef<const char *> argv) { auto *DiagOpts = new DiagnosticOptions; - std::unique_ptr<OptTable> Opts(createDriverOptTable()); unsigned MissingArgIndex, MissingArgCount; - InputArgList Args = - Opts->ParseArgs(argv.slice(1), MissingArgIndex, MissingArgCount); + InputArgList Args = getDriverOptTable().ParseArgs( + argv.slice(1), MissingArgIndex, MissingArgCount); // We ignore MissingArgCount and the return value of ParseDiagnosticArgs. // Any errors that would be diagnosed here will also be diagnosed later, // when the DiagnosticsEngine actually exists. @@ -319,6 +319,7 @@ static int ExecuteCC1Tool(ArrayRef<const char *> argv, StringRef Tool) { } int main(int argc_, const char **argv_) { + noteBottomOfStack(); llvm::InitLLVM X(argc_, argv_); SmallVector<const char *, 256> argv(argv_, argv_ + argc_); @@ -498,6 +499,7 @@ int main(int argc_, const char **argv_) { // If any timers were active but haven't been destroyed yet, print their // results now. This happens in -disable-free mode. llvm::TimerGroup::printAll(llvm::errs()); + llvm::TimerGroup::clearAll(); #ifdef _WIN32 // Exit status should not be negative on Win32, unless abnormal termination. |