summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/clang-format/ClangFormat.cpp284
-rw-r--r--tools/clang-offload-wrapper/CMakeLists.txt23
-rw-r--r--tools/clang-offload-wrapper/ClangOffloadWrapper.cpp371
-rw-r--r--tools/driver/cc1_main.cpp44
-rw-r--r--tools/driver/cc1as_main.cpp38
-rw-r--r--tools/driver/driver.cpp8
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.