mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-03 16:41:06 +03:00
Add support for LLVM 12
This commit is contained in:
parent
8d71c8624a
commit
d8bc064cfb
21 changed files with 3493 additions and 60 deletions
|
@ -54,26 +54,24 @@ components="aarch64 aarch64asmparser aarch64codegen aarch64desc aarch64disassemb
|
|||
aggressiveinstcombine all all-targets analysis arm armasmparser armcodegen armdesc armdisassembler arminfo \
|
||||
armutils asmparser asmprinter binaryformat bitreader bitstreamreader bitwriter cfguard codegen core coroutines \
|
||||
coverage debuginfocodeview debuginfodwarf debuginfogsym debuginfomsf debuginfopdb demangle dlltooldriver \
|
||||
dwarflinker engine executionengine extensions frontendopenmp fuzzmutate globalisel instcombine instrumentation interpreter \
|
||||
dwarflinker engine executionengine extensions filecheck frontendopenacc frontendopenmp fuzzmutate globalisel \
|
||||
instcombine instrumentation interfacestub interpreter \
|
||||
ipo irreader jitlink libdriver lineeditor linker lto mc mca mcdisassembler mcjit mcparser mirparser native \
|
||||
nativecodegen objcarcopts object objectyaml option orcerror orcjit passes profiledata remarks runtimedyld \
|
||||
nativecodegen objcarcopts object objectyaml option orcjit orcshared orctargetprocess passes profiledata remarks runtimedyld \
|
||||
scalaropts selectiondag support symbolize tablegen target textapi transformutils vectorize webassembly \
|
||||
webassemblyasmparser webassemblycodegen webassemblydesc webassemblydisassembler webassemblyinfo windowsmanifest \
|
||||
x86 x86asmparser x86codegen x86desc x86disassembler x86info xray"
|
||||
static_libs="-lLLVMXRay -lLLVMWindowsManifest -lLLVMTableGen -lLLVMSymbolize -lLLVMDebugInfoPDB -lLLVMOrcJIT \
|
||||
-lLLVMOrcError -lLLVMJITLink -lLLVMObjectYAML -lLLVMMIRParser -lLLVMMCA -lLLVMLTO -lLLVMPasses -lLLVMCoroutines \
|
||||
-lLLVMObjCARCOpts -lLLVMipo -lLLVMInstrumentation -lLLVMVectorize -lLLVMLinker -lLLVMIRReader -lLLVMAsmParser \
|
||||
-lLLVMFrontendOpenMP -lLLVMExtensions -lLLVMLineEditor -lLLVMLibDriver -lLLVMInterpreter -lLLVMFuzzMutate -lLLVMMCJIT \
|
||||
-lLLVMExecutionEngine -lLLVMRuntimeDyld -lLLVMDWARFLinker -lLLVMDlltoolDriver -lLLVMOption -lLLVMDebugInfoGSYM \
|
||||
-lLLVMCoverage -lLLVMX86Disassembler -lLLVMX86AsmParser -lLLVMX86CodeGen -lLLVMX86Desc -lLLVMX86Info \
|
||||
-lLLVMWebAssemblyDisassembler -lLLVMWebAssemblyCodeGen -lLLVMWebAssemblyDesc -lLLVMWebAssemblyAsmParser \
|
||||
-lLLVMWebAssemblyInfo -lLLVMARMDisassembler -lLLVMARMCodeGen -lLLVMARMAsmParser -lLLVMARMDesc -lLLVMARMUtils \
|
||||
-lLLVMARMInfo -lLLVMAArch64Disassembler -lLLVMMCDisassembler -lLLVMAArch64CodeGen -lLLVMCFGuard -lLLVMGlobalISel \
|
||||
-lLLVMSelectionDAG -lLLVMAsmPrinter -lLLVMDebugInfoDWARF -lLLVMCodeGen -lLLVMTarget -lLLVMScalarOpts \
|
||||
-lLLVMInstCombine -lLLVMAggressiveInstCombine -lLLVMTransformUtils -lLLVMBitWriter -lLLVMAnalysis -lLLVMProfileData \
|
||||
-lLLVMObject -lLLVMTextAPI -lLLVMBitReader -lLLVMCore -lLLVMRemarks -lLLVMBitstreamReader -lLLVMAArch64AsmParser \
|
||||
-lLLVMMCParser -lLLVMAArch64Desc -lLLVMMC -lLLVMDebugInfoCodeView -lLLVMDebugInfoMSF -lLLVMBinaryFormat \
|
||||
-lLLVMAArch64Utils -lLLVMAArch64Info -lLLVMSupport -lLLVMDemangle"
|
||||
static_libs="-lLLVMWindowsManifest -lLLVMTableGen -lLLVMLTO -lLLVMPasses -lLLVMCoroutines \
|
||||
-lLLVMObjCARCOpts -lLLVMExtensions -lLLVMLibDriver -lLLVMOption -lLLVMipo -lLLVMInstrumentation -lLLVMVectorize \
|
||||
-lLLVMLinker -lLLVMIRReader -lLLVMFrontendOpenMP -lLLVMDebugInfoPDB -lLLVMAsmParser -lLLVMX86Disassembler \
|
||||
-lLLVMX86AsmParser -lLLVMX86CodeGen -lLLVMX86Desc -lLLVMX86Info -lLLVMWebAssemblyDisassembler -lLLVMWebAssemblyAsmParser \
|
||||
-lLLVMWebAssemblyCodeGen -lLLVMWebAssemblyDesc -lLLVMWebAssemblyInfo -lLLVMARMDisassembler -lLLVMARMAsmParser \
|
||||
-lLLVMARMCodeGen -lLLVMARMDesc -lLLVMARMUtils -lLLVMARMInfo -lLLVMAArch64Disassembler -lLLVMMCDisassembler \
|
||||
-lLLVMAArch64AsmParser -lLLVMAArch64CodeGen -lLLVMCFGuard -lLLVMGlobalISel -lLLVMSelectionDAG -lLLVMAsmPrinter \
|
||||
-lLLVMDebugInfoDWARF -lLLVMCodeGen -lLLVMTarget -lLLVMScalarOpts -lLLVMInstCombine -lLLVMAggressiveInstCombine \
|
||||
-lLLVMTransformUtils -lLLVMBitWriter -lLLVMAnalysis -lLLVMProfileData -lLLVMObject -lLLVMTextAPI -lLLVMMCParser \
|
||||
-lLLVMBitReader -lLLVMCore -lLLVMRemarks -lLLVMBitstreamReader -lLLVMAArch64Desc -lLLVMMC -lLLVMDebugInfoCodeView \
|
||||
-lLLVMDebugInfoMSF -lLLVMBinaryFormat -lLLVMAArch64Utils -lLLVMAArch64Info -lLLVMSupport -lLLVMDemangle"
|
||||
shared_libs="-lLLVM-$version"
|
||||
libs=$shared_libs
|
||||
handle_args () {
|
||||
|
|
|
@ -447,10 +447,15 @@ include(HandleLTOPGOBuildOptions)
|
|||
#
|
||||
# Enable Dynamic compilation if supported for this platform and LLVM version.
|
||||
#
|
||||
set(LDC_DYNAMIC_COMPILE "AUTO" CACHE STRING "Support dynamic compilation (ON|OFF). Enabled by default.")
|
||||
set(LDC_DYNAMIC_COMPILE "AUTO" CACHE STRING "Support dynamic compilation (ON|OFF). Enabled by default; not supported for LLVM >= 12.")
|
||||
option(LDC_DYNAMIC_COMPILE_USE_CUSTOM_PASSES "Use custom LDC passes in jit" ON)
|
||||
if(LDC_DYNAMIC_COMPILE STREQUAL "AUTO")
|
||||
if(LDC_LLVM_VER LESS 1200)
|
||||
set(LDC_DYNAMIC_COMPILE ON)
|
||||
else()
|
||||
# TODO: port from ORCv1 API (dropped with LLVM 12) to ORCv2 (added with LLVM 7)
|
||||
set(LDC_DYNAMIC_COMPILE OFF)
|
||||
endif()
|
||||
endif()
|
||||
message(STATUS "-- Building LDC with dynamic compilation support (LDC_DYNAMIC_COMPILE): ${LDC_DYNAMIC_COMPILE}")
|
||||
if(LDC_DYNAMIC_COMPILE)
|
||||
|
|
|
@ -30,7 +30,8 @@
|
|||
# We also want an user-specified LLVM_ROOT_DIR to take precedence over the
|
||||
# system default locations such as /usr/local/bin. Executing find_program()
|
||||
# multiples times is the approach recommended in the docs.
|
||||
set(llvm_config_names llvm-config-11.0 llvm-config110 llvm-config-11
|
||||
set(llvm_config_names llvm-config-12.0 llvm-config120 llvm-config-12
|
||||
llvm-config-11.0 llvm-config110 llvm-config-11
|
||||
llvm-config-10.0 llvm-config100 llvm-config-10
|
||||
llvm-config-9.0 llvm-config90 llvm-config-9
|
||||
llvm-config-8.0 llvm-config80 llvm-config-8
|
||||
|
|
|
@ -9,6 +9,10 @@
|
|||
|
||||
#include "driver/cl_options-llvm.h"
|
||||
|
||||
#if LDC_WITH_LLD
|
||||
#include "llvm/ADT/Triple.h"
|
||||
#endif
|
||||
|
||||
// Pull in command-line options and helper functions from special LLVM header
|
||||
// shared by multiple LLVM tools.
|
||||
#if LDC_LLVM_VER >= 1100
|
||||
|
@ -95,8 +99,10 @@ bool printTargetFeaturesHelp() {
|
|||
[](const std::string &a) { return a == "help"; });
|
||||
}
|
||||
|
||||
TargetOptions InitTargetOptionsFromCodeGenFlags() {
|
||||
#if LDC_LLVM_VER >= 1100
|
||||
TargetOptions InitTargetOptionsFromCodeGenFlags(const llvm::Triple &triple) {
|
||||
#if LDC_LLVM_VER >= 1200
|
||||
return codegen::InitTargetOptionsFromCodeGenFlags(triple);
|
||||
#elif LDC_LLVM_VER >= 1100
|
||||
return codegen::InitTargetOptionsFromCodeGenFlags();
|
||||
#else
|
||||
return ::InitTargetOptionsFromCodeGenFlags();
|
||||
|
@ -141,7 +147,7 @@ TargetOptions initTargetOptionsFromCodeGenFlags() {
|
|||
#else
|
||||
TargetOptions InitTargetOptionsFromCodeGenFlags() {
|
||||
#endif
|
||||
return ::opts::InitTargetOptionsFromCodeGenFlags();
|
||||
return ::opts::InitTargetOptionsFromCodeGenFlags(llvm::Triple());
|
||||
}
|
||||
|
||||
#if LDC_LLVM_VER >= 1000
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
namespace llvm {
|
||||
class Function;
|
||||
class Triple;
|
||||
}
|
||||
|
||||
namespace opts {
|
||||
|
@ -32,7 +33,9 @@ llvm::cl::boolOrDefault disableFPElim();
|
|||
bool disableRedZone();
|
||||
bool printTargetFeaturesHelp();
|
||||
|
||||
llvm::TargetOptions InitTargetOptionsFromCodeGenFlags();
|
||||
llvm::TargetOptions
|
||||
InitTargetOptionsFromCodeGenFlags(const llvm::Triple &triple);
|
||||
|
||||
std::string getCPUStr();
|
||||
std::string getFeaturesStr();
|
||||
#if LDC_LLVM_VER >= 1000
|
||||
|
|
|
@ -702,9 +702,18 @@ void createClashingOptions() {
|
|||
/// to be useful for end users from the -help output.
|
||||
void hideLLVMOptions() {
|
||||
static const char *const hiddenOptions[] = {
|
||||
"aarch64-neon-syntax", "addrsig", "arm-add-build-attributes",
|
||||
"aarch64-neon-syntax", "abort-on-max-devirt-iterations-reached",
|
||||
"addrsig", "amdgpu-bypass-slow-div", "amdgpu-disable-loop-alignment",
|
||||
"amdgpu-disable-power-sched", "amdgpu-dpp-combine",
|
||||
"amdgpu-dump-hsa-metadata", "amdgpu-enable-flat-scratch",
|
||||
"amdgpu-enable-global-sgpr-addr", "amdgpu-enable-merge-m0",
|
||||
"amdgpu-promote-alloca-to-vector-limit",
|
||||
"amdgpu-reserve-vgpr-for-sgpr-spill", "amdgpu-sdwa-peephole",
|
||||
"amdgpu-use-aa-in-codegen", "amdgpu-verify-hsa-metadata",
|
||||
"amdgpu-vgpr-index-mode", "arm-add-build-attributes",
|
||||
"arm-implicit-it", "asm-instrumentation", "asm-show-inst",
|
||||
"atomic-counter-update-promoted", "atomic-first-counter",
|
||||
"basic-block-sections",
|
||||
"basicblock-sections", "bounds-checking-single-trap",
|
||||
"cfg-hide-deoptimize-paths", "cfg-hide-unreachable-paths",
|
||||
"code-model", "cost-kind", "cppfname", "cppfor", "cppgen",
|
||||
|
@ -712,8 +721,10 @@ void hideLLVMOptions() {
|
|||
"cvp-dont-process-adds", "debug-counter", "debug-entry-values",
|
||||
"debugger-tune", "debugify-level", "debugify-quiet",
|
||||
"denormal-fp-math", "denormal-fp-math-f32", "disable-debug-info-verifier",
|
||||
"disable-objc-arc-checkforcfghazards", "disable-spill-fusing",
|
||||
"do-counter-promotion", "dwarf64", "emit-call-site-info",
|
||||
"disable-objc-arc-checkforcfghazards", "disable-promote-alloca-to-lds",
|
||||
"disable-promote-alloca-to-vector", "disable-slp-vectorization",
|
||||
"disable-spill-fusing",
|
||||
"do-counter-promotion", "dot-cfg-mssa", "dwarf64", "emit-call-site-info",
|
||||
"emscripten-cxx-exceptions-allowed",
|
||||
"emscripten-cxx-exceptions-whitelist",
|
||||
"emulated-tls", "enable-correct-eh-support",
|
||||
|
@ -727,17 +738,19 @@ void hideLLVMOptions() {
|
|||
"enable-no-nans-fp-math", "enable-no-signed-zeros-fp-math",
|
||||
"enable-no-trapping-fp-math", "enable-objc-arc-annotations",
|
||||
"enable-objc-arc-opts", "enable-pie", "enable-scoped-noalias",
|
||||
"enable-split-backedge-in-load-pre",
|
||||
"enable-tbaa", "enable-unsafe-fp-math", "exception-model",
|
||||
"exhaustive-register-search", "expensive-combines",
|
||||
"experimental-debug-variable-locations",
|
||||
"fatal-assembler-warnings", "filter-print-funcs",
|
||||
"force-dwarf-frame-section", "gpsize", "hash-based-counter-split",
|
||||
"hot-cold-split",
|
||||
"hot-cold-split", "ignore-xcoff-visibility",
|
||||
"imp-null-check-page-size", "imp-null-max-insts-to-consider",
|
||||
"import-all-index", "incremental-linker-compatible",
|
||||
"instcombine-code-sinking", "instcombine-guard-widening-window",
|
||||
"instcombine-max-iterations", "instcombine-max-num-phis",
|
||||
"instcombine-maxarray-size", "instcombine-negator-enabled",
|
||||
"instcombine-negator-max-depth",
|
||||
"instcombine-negator-max-depth", "instcombine-unsafe-select-transform",
|
||||
"instrprof-atomic-counter-update-all", "internalize-public-api-file",
|
||||
"internalize-public-api-list", "iterative-counter-promotion",
|
||||
"join-liveintervals", "jump-table-type", "limit-float-precision",
|
||||
|
@ -745,9 +758,9 @@ void hideLLVMOptions() {
|
|||
"max-counter-promotions", "max-counter-promotions-per-loop",
|
||||
"mc-relax-all", "mc-x86-disable-arith-relaxation", "meabi",
|
||||
"memop-size-large", "memop-size-range", "merror-missing-parenthesis",
|
||||
"merror-noncontigious-register", "mfuture-regs", "mips-compact-branches",
|
||||
"mips16-constant-islands", "mips16-hard-float", "mir-strip-debugify-only",
|
||||
"mlsm", "mno-compound",
|
||||
"merror-noncontigious-register", "mfuture-regs", "mhvx",
|
||||
"mips-compact-branches", "mips16-constant-islands", "mips16-hard-float",
|
||||
"mir-strip-debugify-only", "mlsm", "mno-compound",
|
||||
"mno-fixup", "mno-ldc1-sdc1", "mno-pairing", "mwarn-missing-parenthesis",
|
||||
"mwarn-noncontigious-register", "mwarn-sign-mismatch",
|
||||
"no-discriminators", "no-xray-index",
|
||||
|
@ -759,6 +772,7 @@ void hideLLVMOptions() {
|
|||
"print-before-all", "print-machineinstrs", "print-module-scope",
|
||||
"profile-estimator-loop-weight", "profile-estimator-loop-weight",
|
||||
"profile-file", "profile-info-file", "profile-verifier-noassert",
|
||||
"pseudo-probe-for-profiling",
|
||||
"r600-ir-structurize", "rdf-dump", "rdf-limit", "recip", "regalloc",
|
||||
"relax-elf-relocations", "remarks-section", "rewrite-map-file", "rng-seed",
|
||||
"runtime-counter-relocation", "safepoint-ir-verifier-print-only",
|
||||
|
@ -766,20 +780,26 @@ void hideLLVMOptions() {
|
|||
"sample-profile-check-sample-coverage",
|
||||
"sample-profile-inline-hot-threshold",
|
||||
"sample-profile-max-propagate-iterations", "shrink-wrap", "simplify-mir",
|
||||
"skip-ret-exit-block",
|
||||
"speculative-counter-promotion-max-exiting",
|
||||
"speculative-counter-promotion-to-loop", "spiller", "spirv-debug",
|
||||
"spirv-erase-cl-md", "spirv-lower-const-expr", "spirv-mem2reg",
|
||||
"spirv-no-deref-attr", "spirv-text",
|
||||
"spv-lower-saddwithoverflow-validate", "spvbool-validate",
|
||||
"spvmemmove-validate",
|
||||
"stack-alignment", "stack-size-section", "stack-symbol-ordering",
|
||||
"spirv-no-deref-attr", "spirv-text", "spirv-verify-regularize-passes",
|
||||
"split-machine-functions", "spv-lower-saddwithoverflow-validate",
|
||||
"spvbool-validate", "spvmemmove-validate",
|
||||
"stack-alignment", "stack-protector-guard",
|
||||
"stack-protector-guard-offset", "stack-protector-guard-reg",
|
||||
"stack-size-section", "stack-symbol-ordering",
|
||||
"stackmap-version", "static-func-full-module-prefix",
|
||||
"static-func-strip-dirname-prefix", "stats", "stats-json", "strip-debug",
|
||||
"struct-path-tbaa", "summary-file", "tail-predication", "tailcallopt",
|
||||
"thinlto-assume-merged",
|
||||
"thread-model", "time-passes", "time-trace-granularity", "tls-size",
|
||||
"unfold-element-atomic-memcpy-max-elements", "unique-bb-section-names",
|
||||
"unfold-element-atomic-memcpy-max-elements",
|
||||
"unique-basic-block-section-names", "unique-bb-section-names",
|
||||
"unique-section-names", "unit-at-a-time", "use-ctors",
|
||||
"verify-debug-info", "verify-dom-info", "verify-loop-info",
|
||||
"vec-extabi", "verify-debug-info", "verify-dom-info",
|
||||
"verify-legalizer-debug-locs", "verify-loop-info",
|
||||
"verify-loop-lcssa", "verify-machine-dom-info", "verify-regalloc",
|
||||
"verify-region-info", "verify-scev", "verify-scev-maps",
|
||||
"vp-counters-per-site", "vp-static-alloc",
|
||||
|
@ -787,6 +807,7 @@ void hideLLVMOptions() {
|
|||
"x86-branches-within-32B-boundaries", "x86-early-ifcvt",
|
||||
"x86-pad-max-prefix-size",
|
||||
"x86-recip-refinement-steps", "x86-use-vzeroupper",
|
||||
"xcoff-traceback-table",
|
||||
|
||||
// We enable -fdata-sections/-ffunction-sections by default where it makes
|
||||
// sense for reducing code size, so hide them to avoid confusion.
|
||||
|
|
|
@ -32,6 +32,14 @@
|
|||
#include "llvm/Support/Path.h"
|
||||
#include "llvm/Support/ToolOutputFile.h"
|
||||
#include "llvm/Support/YAMLTraits.h"
|
||||
#if LDC_MLIR_ENABLED
|
||||
#if LDC_LLVM_VER >= 1200
|
||||
#include "mlir/IR/BuiltinOps.h"
|
||||
#else
|
||||
#include "mlir/IR/Module.h"
|
||||
#endif
|
||||
#include "mlir/IR/MLIRContext.h"
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
|
||||
|
|
|
@ -20,9 +20,12 @@
|
|||
#pragma once
|
||||
|
||||
#include "gen/irstate.h"
|
||||
|
||||
#if LDC_MLIR_ENABLED
|
||||
#include "mlir/IR/MLIRContext.h"
|
||||
#include "mlir/IR/Module.h"
|
||||
namespace mlir {
|
||||
class MLIRContext;
|
||||
class OwningModuleRef;
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace ldc {
|
||||
|
|
|
@ -64,6 +64,9 @@
|
|||
#include "llvm/Support/TargetRegistry.h"
|
||||
#include "llvm/Support/TargetSelect.h"
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
#if LDC_MLIR_ENABLED
|
||||
#include "mlir/IR/MLIRContext.h"
|
||||
#endif
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
|
|
|
@ -447,7 +447,9 @@ createTargetMachine(const std::string targetTriple, const std::string arch,
|
|||
}
|
||||
}
|
||||
|
||||
llvm::TargetOptions targetOptions = opts::InitTargetOptionsFromCodeGenFlags();
|
||||
llvm::TargetOptions targetOptions =
|
||||
opts::InitTargetOptionsFromCodeGenFlags(triple);
|
||||
|
||||
if (targetOptions.MCOptions.ABIName.empty())
|
||||
targetOptions.MCOptions.ABIName = getABI(triple);
|
||||
|
||||
|
|
|
@ -107,8 +107,6 @@ DIBuilder::DIBuilder(IRState *const IR)
|
|||
// (https://reviews.llvm.org/D23720)
|
||||
emitColumnInfo(opts::getFlagOrDefault(::emitColumnInfo, !emitCodeView)) {}
|
||||
|
||||
llvm::LLVMContext &DIBuilder::getContext() { return IR->context(); }
|
||||
|
||||
unsigned DIBuilder::getColumn(const Loc &loc) const {
|
||||
return (loc.linnum && emitColumnInfo) ? loc.charnum : 0;
|
||||
}
|
||||
|
@ -193,16 +191,16 @@ llvm::StringRef DIBuilder::GetNameAndScope(Dsymbol *sym, DIScope &scope) {
|
|||
// Sets the memory address for a debuginfo variable.
|
||||
void DIBuilder::Declare(const Loc &loc, llvm::Value *storage,
|
||||
DILocalVariable divar, DIExpression diexpr) {
|
||||
auto debugLoc =
|
||||
llvm::DebugLoc::get(loc.linnum, getColumn(loc), GetCurrentScope());
|
||||
auto debugLoc = llvm::DILocation::get(IR->context(), loc.linnum,
|
||||
getColumn(loc), GetCurrentScope());
|
||||
DBuilder.insertDeclare(storage, divar, diexpr, debugLoc, IR->scopebb());
|
||||
}
|
||||
|
||||
// Sets the (current) value for a debuginfo variable.
|
||||
void DIBuilder::SetValue(const Loc &loc, llvm::Value *value,
|
||||
DILocalVariable divar, DIExpression diexpr) {
|
||||
auto debugLoc =
|
||||
llvm::DebugLoc::get(loc.linnum, getColumn(loc), GetCurrentScope());
|
||||
auto debugLoc = llvm::DILocation::get(IR->context(), loc.linnum,
|
||||
getColumn(loc), GetCurrentScope());
|
||||
DBuilder.insertDbgValueIntrinsic(value, divar, diexpr, debugLoc,
|
||||
IR->scopebb());
|
||||
}
|
||||
|
@ -1202,8 +1200,9 @@ void DIBuilder::EmitStopPoint(const Loc &loc) {
|
|||
unsigned col = getColumn(loc);
|
||||
Logger::println("D to dwarf stoppoint at line %u, column %u", linnum, col);
|
||||
LOG_SCOPE;
|
||||
|
||||
IR->ir->SetCurrentDebugLocation(
|
||||
llvm::DebugLoc::get(linnum, col, GetCurrentScope()));
|
||||
llvm::DILocation::get(IR->context(), linnum, col, GetCurrentScope()));
|
||||
}
|
||||
|
||||
void DIBuilder::EmitValue(llvm::Value *val, VarDeclaration *vd) {
|
||||
|
|
|
@ -152,7 +152,6 @@ public:
|
|||
void Finalize();
|
||||
|
||||
private:
|
||||
llvm::LLVMContext &getContext();
|
||||
DIScope GetSymbolScope(Dsymbol *s);
|
||||
DIScope GetCurrentScope();
|
||||
llvm::StringRef GetNameAndScope(Dsymbol *sym, DIScope &scope);
|
||||
|
|
|
@ -1163,7 +1163,9 @@ LLConstant *DtoConstExpInit(const Loc &loc, Type *targetType, Expression *exp) {
|
|||
assert(tv->basetype->ty == Tsarray);
|
||||
dinteger_t elemCount =
|
||||
static_cast<TypeSArray *>(tv->basetype)->dim->toInteger();
|
||||
#if LDC_LLVM_VER >= 1100
|
||||
#if LDC_LLVM_VER >= 1200
|
||||
const auto elementCount = llvm::ElementCount::getFixed(elemCount);
|
||||
#elif LDC_LLVM_VER >= 1100
|
||||
const auto elementCount = llvm::ElementCount(elemCount, false);
|
||||
#else
|
||||
const auto elementCount = elemCount;
|
||||
|
|
|
@ -72,7 +72,8 @@ llvm::Function *buildForwarderFunction(
|
|||
ldc::DISubprogram dis = gIR->DBuilder.EmitModuleCTor(fn, name.c_str());
|
||||
if (global.params.symdebug) {
|
||||
// Need _some_ debug info to avoid inliner bug, see GitHub issue #998.
|
||||
builder.SetCurrentDebugLocation(llvm::DebugLoc::get(0, 0, dis));
|
||||
builder.SetCurrentDebugLocation(
|
||||
llvm::DILocation::get(gIR->context(), 0, 0, dis));
|
||||
}
|
||||
|
||||
// ... calling the given functions, and...
|
||||
|
|
|
@ -663,7 +663,9 @@ public:
|
|||
// cast.
|
||||
// FIXME: Check DMD source to understand why two different ASTs are
|
||||
// constructed.
|
||||
#if LDC_LLVM_VER >= 1100
|
||||
#if LDC_LLVM_VER >= 1200
|
||||
const auto elementCount = llvm::ElementCount::getFixed(elemCount);
|
||||
#elif LDC_LLVM_VER >= 1100
|
||||
const auto elementCount = llvm::ElementCount(elemCount, false);
|
||||
#else
|
||||
const auto elementCount = elemCount;
|
||||
|
|
|
@ -2594,6 +2594,7 @@ public:
|
|||
// and store element-wise.
|
||||
if (auto ts = tsrc->isTypeSArray()) {
|
||||
Logger::println("static array expression");
|
||||
(void)ts;
|
||||
assert(ts->dim->toInteger() == N &&
|
||||
"Static array vector initializer length mismatch, should have "
|
||||
"been handled in frontend.");
|
||||
|
@ -2620,7 +2621,9 @@ public:
|
|||
DValue *val = toElem(e->e1);
|
||||
LLValue *llElement = getCastElement(val);
|
||||
if (auto llConstant = isaConstant(llElement)) {
|
||||
#if LDC_LLVM_VER >= 1100
|
||||
#if LDC_LLVM_VER >= 1200
|
||||
const auto elementCount = llvm::ElementCount::getFixed(N);
|
||||
#elif LDC_LLVM_VER >= 1100
|
||||
const auto elementCount = llvm::ElementCount(N, false);
|
||||
#else
|
||||
const auto elementCount = N;
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit deb412be02ab3c6b0c370c0b5cb6d7de1d40573e
|
||||
Subproject commit fb6a14bf006b6899d5ebeee1741e3a8e4be2323a
|
|
@ -85,7 +85,7 @@ config.available_features.add("llvm%d" % config.llvm_version)
|
|||
plusoneable_llvmversion = config.llvm_version // 10 + config.llvm_version%10
|
||||
for version in range(60, plusoneable_llvmversion+1):
|
||||
config.available_features.add("atleast_llvm%d0%d" % (version//10, version%10))
|
||||
for version in range(plusoneable_llvmversion, 111):
|
||||
for version in range(plusoneable_llvmversion, 121):
|
||||
config.available_features.add("atmost_llvm%d0%d" % (version//10, version%10))
|
||||
|
||||
# Define OS as available feature (Windows, Darwin, Linux)
|
||||
|
|
2498
tools/ldc-profdata/llvm-profdata-12.0.cpp
Normal file
2498
tools/ldc-profdata/llvm-profdata-12.0.cpp
Normal file
File diff suppressed because it is too large
Load diff
|
@ -43,6 +43,9 @@ if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${FILECHECK_SRC})
|
|||
COMPILE_FLAGS "${LLVM_CXXFLAGS} ${LDC_CXXFLAGS}"
|
||||
LINK_FLAGS "${SANITIZE_LDFLAGS}"
|
||||
)
|
||||
if(NOT (LDC_LLVM_VER LESS 1200))
|
||||
target_link_libraries(FileCheck LLVMFileCheck)
|
||||
endif()
|
||||
target_link_libraries(FileCheck ${LLVM_LIBRARIES} ${CMAKE_DL_LIBS} ${LLVM_LDFLAGS})
|
||||
else()
|
||||
message(STATUS "Skip building FileCheck (source not found), assuming it can be found in LLVM bin directory")
|
||||
|
|
876
utils/FileCheck-12.0.cpp
Normal file
876
utils/FileCheck-12.0.cpp
Normal file
|
@ -0,0 +1,876 @@
|
|||
//===- FileCheck.cpp - Check that File's Contents match what is expected --===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// FileCheck does a line-by line check of a file that validates whether it
|
||||
// contains the expected content. This is useful for regression tests etc.
|
||||
//
|
||||
// This program exits with an exit status of 2 on error, exit status of 0 if
|
||||
// the file matched the expected contents, and exit status of 1 if it did not
|
||||
// contain the expected contents.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/FileCheck/FileCheck.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/InitLLVM.h"
|
||||
#include "llvm/Support/Process.h"
|
||||
#include "llvm/Support/WithColor.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <cmath>
|
||||
using namespace llvm;
|
||||
|
||||
static cl::extrahelp FileCheckOptsEnv(
|
||||
"\nOptions are parsed from the environment variable FILECHECK_OPTS and\n"
|
||||
"from the command line.\n");
|
||||
|
||||
static cl::opt<std::string>
|
||||
CheckFilename(cl::Positional, cl::desc("<check-file>"), cl::Optional);
|
||||
|
||||
static cl::opt<std::string>
|
||||
InputFilename("input-file", cl::desc("File to check (defaults to stdin)"),
|
||||
cl::init("-"), cl::value_desc("filename"));
|
||||
|
||||
static cl::list<std::string> CheckPrefixes(
|
||||
"check-prefix",
|
||||
cl::desc("Prefix to use from check file (defaults to 'CHECK')"));
|
||||
static cl::alias CheckPrefixesAlias(
|
||||
"check-prefixes", cl::aliasopt(CheckPrefixes), cl::CommaSeparated,
|
||||
cl::NotHidden,
|
||||
cl::desc(
|
||||
"Alias for -check-prefix permitting multiple comma separated values"));
|
||||
|
||||
static cl::list<std::string> CommentPrefixes(
|
||||
"comment-prefixes", cl::CommaSeparated, cl::Hidden,
|
||||
cl::desc("Comma-separated list of comment prefixes to use from check file\n"
|
||||
"(defaults to 'COM,RUN'). Please avoid using this feature in\n"
|
||||
"LLVM's LIT-based test suites, which should be easier to\n"
|
||||
"maintain if they all follow a consistent comment style. This\n"
|
||||
"feature is meant for non-LIT test suites using FileCheck."));
|
||||
|
||||
static cl::opt<bool> NoCanonicalizeWhiteSpace(
|
||||
"strict-whitespace",
|
||||
cl::desc("Do not treat all horizontal whitespace as equivalent"));
|
||||
|
||||
static cl::opt<bool> IgnoreCase(
|
||||
"ignore-case",
|
||||
cl::desc("Use case-insensitive matching"));
|
||||
|
||||
static cl::list<std::string> ImplicitCheckNot(
|
||||
"implicit-check-not",
|
||||
cl::desc("Add an implicit negative check with this pattern to every\n"
|
||||
"positive check. This can be used to ensure that no instances of\n"
|
||||
"this pattern occur which are not matched by a positive pattern"),
|
||||
cl::value_desc("pattern"));
|
||||
|
||||
static cl::list<std::string>
|
||||
GlobalDefines("D", cl::AlwaysPrefix,
|
||||
cl::desc("Define a variable to be used in capture patterns."),
|
||||
cl::value_desc("VAR=VALUE"));
|
||||
|
||||
static cl::opt<bool> AllowEmptyInput(
|
||||
"allow-empty", cl::init(false),
|
||||
cl::desc("Allow the input file to be empty. This is useful when making\n"
|
||||
"checks that some error message does not occur, for example."));
|
||||
|
||||
static cl::opt<bool> AllowUnusedPrefixes(
|
||||
"allow-unused-prefixes", cl::init(true),
|
||||
cl::desc("Allow prefixes to be specified but not appear in the test."));
|
||||
|
||||
static cl::opt<bool> MatchFullLines(
|
||||
"match-full-lines", cl::init(false),
|
||||
cl::desc("Require all positive matches to cover an entire input line.\n"
|
||||
"Allows leading and trailing whitespace if --strict-whitespace\n"
|
||||
"is not also passed."));
|
||||
|
||||
static cl::opt<bool> EnableVarScope(
|
||||
"enable-var-scope", cl::init(false),
|
||||
cl::desc("Enables scope for regex variables. Variables with names that\n"
|
||||
"do not start with '$' will be reset at the beginning of\n"
|
||||
"each CHECK-LABEL block."));
|
||||
|
||||
static cl::opt<bool> AllowDeprecatedDagOverlap(
|
||||
"allow-deprecated-dag-overlap", cl::init(false),
|
||||
cl::desc("Enable overlapping among matches in a group of consecutive\n"
|
||||
"CHECK-DAG directives. This option is deprecated and is only\n"
|
||||
"provided for convenience as old tests are migrated to the new\n"
|
||||
"non-overlapping CHECK-DAG implementation.\n"));
|
||||
|
||||
static cl::opt<bool> Verbose(
|
||||
"v", cl::init(false), cl::ZeroOrMore,
|
||||
cl::desc("Print directive pattern matches, or add them to the input dump\n"
|
||||
"if enabled.\n"));
|
||||
|
||||
static cl::opt<bool> VerboseVerbose(
|
||||
"vv", cl::init(false), cl::ZeroOrMore,
|
||||
cl::desc("Print information helpful in diagnosing internal FileCheck\n"
|
||||
"issues, or add it to the input dump if enabled. Implies\n"
|
||||
"-v.\n"));
|
||||
|
||||
// The order of DumpInputValue members affects their precedence, as documented
|
||||
// for -dump-input below.
|
||||
enum DumpInputValue {
|
||||
DumpInputNever,
|
||||
DumpInputFail,
|
||||
DumpInputAlways,
|
||||
DumpInputHelp
|
||||
};
|
||||
|
||||
static cl::list<DumpInputValue> DumpInputs(
|
||||
"dump-input",
|
||||
cl::desc("Dump input to stderr, adding annotations representing\n"
|
||||
"currently enabled diagnostics. When there are multiple\n"
|
||||
"occurrences of this option, the <value> that appears earliest\n"
|
||||
"in the list below has precedence. The default is 'fail'.\n"),
|
||||
cl::value_desc("mode"),
|
||||
cl::values(clEnumValN(DumpInputHelp, "help", "Explain input dump and quit"),
|
||||
clEnumValN(DumpInputAlways, "always", "Always dump input"),
|
||||
clEnumValN(DumpInputFail, "fail", "Dump input on failure"),
|
||||
clEnumValN(DumpInputNever, "never", "Never dump input")));
|
||||
|
||||
// The order of DumpInputFilterValue members affects their precedence, as
|
||||
// documented for -dump-input-filter below.
|
||||
enum DumpInputFilterValue {
|
||||
DumpInputFilterError,
|
||||
DumpInputFilterAnnotation,
|
||||
DumpInputFilterAnnotationFull,
|
||||
DumpInputFilterAll
|
||||
};
|
||||
|
||||
static cl::list<DumpInputFilterValue> DumpInputFilters(
|
||||
"dump-input-filter",
|
||||
cl::desc("In the dump requested by -dump-input, print only input lines of\n"
|
||||
"kind <value> plus any context specified by -dump-input-context.\n"
|
||||
"When there are multiple occurrences of this option, the <value>\n"
|
||||
"that appears earliest in the list below has precedence. The\n"
|
||||
"default is 'error' when -dump-input=fail, and it's 'all' when\n"
|
||||
"-dump-input=always.\n"),
|
||||
cl::values(clEnumValN(DumpInputFilterAll, "all", "All input lines"),
|
||||
clEnumValN(DumpInputFilterAnnotationFull, "annotation-full",
|
||||
"Input lines with annotations"),
|
||||
clEnumValN(DumpInputFilterAnnotation, "annotation",
|
||||
"Input lines with starting points of annotations"),
|
||||
clEnumValN(DumpInputFilterError, "error",
|
||||
"Input lines with starting points of error "
|
||||
"annotations")));
|
||||
|
||||
static cl::list<unsigned> DumpInputContexts(
|
||||
"dump-input-context", cl::value_desc("N"),
|
||||
cl::desc("In the dump requested by -dump-input, print <N> input lines\n"
|
||||
"before and <N> input lines after any lines specified by\n"
|
||||
"-dump-input-filter. When there are multiple occurrences of\n"
|
||||
"this option, the largest specified <N> has precedence. The\n"
|
||||
"default is 5.\n"));
|
||||
|
||||
typedef cl::list<std::string>::const_iterator prefix_iterator;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static void DumpCommandLine(int argc, char **argv) {
|
||||
errs() << "FileCheck command line: ";
|
||||
for (int I = 0; I < argc; I++)
|
||||
errs() << " " << argv[I];
|
||||
errs() << "\n";
|
||||
}
|
||||
|
||||
struct MarkerStyle {
|
||||
/// The starting char (before tildes) for marking the line.
|
||||
char Lead;
|
||||
/// What color to use for this annotation.
|
||||
raw_ostream::Colors Color;
|
||||
/// A note to follow the marker, or empty string if none.
|
||||
std::string Note;
|
||||
/// Does this marker indicate inclusion by -dump-input-filter=error?
|
||||
bool FiltersAsError;
|
||||
MarkerStyle() {}
|
||||
MarkerStyle(char Lead, raw_ostream::Colors Color,
|
||||
const std::string &Note = "", bool FiltersAsError = false)
|
||||
: Lead(Lead), Color(Color), Note(Note), FiltersAsError(FiltersAsError) {
|
||||
assert((!FiltersAsError || !Note.empty()) &&
|
||||
"expected error diagnostic to have note");
|
||||
}
|
||||
};
|
||||
|
||||
static MarkerStyle GetMarker(FileCheckDiag::MatchType MatchTy) {
|
||||
switch (MatchTy) {
|
||||
case FileCheckDiag::MatchFoundAndExpected:
|
||||
return MarkerStyle('^', raw_ostream::GREEN);
|
||||
case FileCheckDiag::MatchFoundButExcluded:
|
||||
return MarkerStyle('!', raw_ostream::RED, "error: no match expected",
|
||||
/*FiltersAsError=*/true);
|
||||
case FileCheckDiag::MatchFoundButWrongLine:
|
||||
return MarkerStyle('!', raw_ostream::RED, "error: match on wrong line",
|
||||
/*FiltersAsError=*/true);
|
||||
case FileCheckDiag::MatchFoundButDiscarded:
|
||||
return MarkerStyle('!', raw_ostream::CYAN,
|
||||
"discard: overlaps earlier match");
|
||||
case FileCheckDiag::MatchNoneAndExcluded:
|
||||
return MarkerStyle('X', raw_ostream::GREEN);
|
||||
case FileCheckDiag::MatchNoneButExpected:
|
||||
return MarkerStyle('X', raw_ostream::RED, "error: no match found",
|
||||
/*FiltersAsError=*/true);
|
||||
case FileCheckDiag::MatchFuzzy:
|
||||
return MarkerStyle('?', raw_ostream::MAGENTA, "possible intended match",
|
||||
/*FiltersAsError=*/true);
|
||||
}
|
||||
llvm_unreachable_internal("unexpected match type");
|
||||
}
|
||||
|
||||
static void DumpInputAnnotationHelp(raw_ostream &OS) {
|
||||
OS << "The following description was requested by -dump-input=help to\n"
|
||||
<< "explain the input dump printed by FileCheck.\n"
|
||||
<< "\n"
|
||||
<< "Related command-line options:\n"
|
||||
<< "\n"
|
||||
<< " - -dump-input=<value> enables or disables the input dump\n"
|
||||
<< " - -dump-input-filter=<value> filters the input lines\n"
|
||||
<< " - -dump-input-context=<N> adjusts the context of filtered lines\n"
|
||||
<< " - -v and -vv add more annotations\n"
|
||||
<< " - -color forces colors to be enabled both in the dump and below\n"
|
||||
<< " - -help documents the above options in more detail\n"
|
||||
<< "\n"
|
||||
<< "These options can also be set via FILECHECK_OPTS. For example, for\n"
|
||||
<< "maximum debugging output on failures:\n"
|
||||
<< "\n"
|
||||
<< " $ FILECHECK_OPTS='-dump-input-filter=all -vv -color' ninja check\n"
|
||||
<< "\n"
|
||||
<< "Input dump annotation format:\n"
|
||||
<< "\n";
|
||||
|
||||
// Labels for input lines.
|
||||
OS << " - ";
|
||||
WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "L:";
|
||||
OS << " labels line number L of the input file\n";
|
||||
|
||||
// Labels for annotation lines.
|
||||
OS << " - ";
|
||||
WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "T:L";
|
||||
OS << " labels the only match result for either (1) a pattern of type T"
|
||||
<< " from\n"
|
||||
<< " line L of the check file if L is an integer or (2) the"
|
||||
<< " I-th implicit\n"
|
||||
<< " pattern if L is \"imp\" followed by an integer "
|
||||
<< "I (index origin one)\n";
|
||||
OS << " - ";
|
||||
WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "T:L'N";
|
||||
OS << " labels the Nth match result for such a pattern\n";
|
||||
|
||||
// Markers on annotation lines.
|
||||
OS << " - ";
|
||||
WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "^~~";
|
||||
OS << " marks good match (reported if -v)\n"
|
||||
<< " - ";
|
||||
WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "!~~";
|
||||
OS << " marks bad match, such as:\n"
|
||||
<< " - CHECK-NEXT on same line as previous match (error)\n"
|
||||
<< " - CHECK-NOT found (error)\n"
|
||||
<< " - CHECK-DAG overlapping match (discarded, reported if "
|
||||
<< "-vv)\n"
|
||||
<< " - ";
|
||||
WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "X~~";
|
||||
OS << " marks search range when no match is found, such as:\n"
|
||||
<< " - CHECK-NEXT not found (error)\n"
|
||||
<< " - CHECK-NOT not found (success, reported if -vv)\n"
|
||||
<< " - CHECK-DAG not found after discarded matches (error)\n"
|
||||
<< " - ";
|
||||
WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "?";
|
||||
OS << " marks fuzzy match when no match is found\n";
|
||||
|
||||
// Elided lines.
|
||||
OS << " - ";
|
||||
WithColor(OS, raw_ostream::SAVEDCOLOR, true) << "...";
|
||||
OS << " indicates elided input lines and annotations, as specified by\n"
|
||||
<< " -dump-input-filter and -dump-input-context\n";
|
||||
|
||||
// Colors.
|
||||
OS << " - colors ";
|
||||
WithColor(OS, raw_ostream::GREEN, true) << "success";
|
||||
OS << ", ";
|
||||
WithColor(OS, raw_ostream::RED, true) << "error";
|
||||
OS << ", ";
|
||||
WithColor(OS, raw_ostream::MAGENTA, true) << "fuzzy match";
|
||||
OS << ", ";
|
||||
WithColor(OS, raw_ostream::CYAN, true, false) << "discarded match";
|
||||
OS << ", ";
|
||||
WithColor(OS, raw_ostream::CYAN, true, true) << "unmatched input";
|
||||
OS << "\n";
|
||||
}
|
||||
|
||||
/// An annotation for a single input line.
|
||||
struct InputAnnotation {
|
||||
/// The index of the match result across all checks
|
||||
unsigned DiagIndex;
|
||||
/// The label for this annotation.
|
||||
std::string Label;
|
||||
/// Is this the initial fragment of a diagnostic that has been broken across
|
||||
/// multiple lines?
|
||||
bool IsFirstLine;
|
||||
/// What input line (one-origin indexing) this annotation marks. This might
|
||||
/// be different from the starting line of the original diagnostic if
|
||||
/// !IsFirstLine.
|
||||
unsigned InputLine;
|
||||
/// The column range (one-origin indexing, open end) in which to mark the
|
||||
/// input line. If InputEndCol is UINT_MAX, treat it as the last column
|
||||
/// before the newline.
|
||||
unsigned InputStartCol, InputEndCol;
|
||||
/// The marker to use.
|
||||
MarkerStyle Marker;
|
||||
/// Whether this annotation represents a good match for an expected pattern.
|
||||
bool FoundAndExpectedMatch;
|
||||
};
|
||||
|
||||
/// Get an abbreviation for the check type.
|
||||
static std::string GetCheckTypeAbbreviation(Check::FileCheckType Ty) {
|
||||
switch (Ty) {
|
||||
case Check::CheckPlain:
|
||||
if (Ty.getCount() > 1)
|
||||
return "count";
|
||||
return "check";
|
||||
case Check::CheckNext:
|
||||
return "next";
|
||||
case Check::CheckSame:
|
||||
return "same";
|
||||
case Check::CheckNot:
|
||||
return "not";
|
||||
case Check::CheckDAG:
|
||||
return "dag";
|
||||
case Check::CheckLabel:
|
||||
return "label";
|
||||
case Check::CheckEmpty:
|
||||
return "empty";
|
||||
case Check::CheckComment:
|
||||
return "com";
|
||||
case Check::CheckEOF:
|
||||
return "eof";
|
||||
case Check::CheckBadNot:
|
||||
return "bad-not";
|
||||
case Check::CheckBadCount:
|
||||
return "bad-count";
|
||||
case Check::CheckNone:
|
||||
llvm_unreachable("invalid FileCheckType");
|
||||
}
|
||||
llvm_unreachable("unknown FileCheckType");
|
||||
}
|
||||
|
||||
static void
|
||||
BuildInputAnnotations(const SourceMgr &SM, unsigned CheckFileBufferID,
|
||||
const std::pair<unsigned, unsigned> &ImpPatBufferIDRange,
|
||||
const std::vector<FileCheckDiag> &Diags,
|
||||
std::vector<InputAnnotation> &Annotations,
|
||||
unsigned &LabelWidth) {
|
||||
// How many diagnostics have we seen so far?
|
||||
unsigned DiagCount = 0;
|
||||
// How many diagnostics has the current check seen so far?
|
||||
unsigned CheckDiagCount = 0;
|
||||
// What's the widest label?
|
||||
LabelWidth = 0;
|
||||
for (auto DiagItr = Diags.begin(), DiagEnd = Diags.end(); DiagItr != DiagEnd;
|
||||
++DiagItr) {
|
||||
InputAnnotation A;
|
||||
A.DiagIndex = DiagCount++;
|
||||
|
||||
// Build label, which uniquely identifies this check result.
|
||||
unsigned CheckBufferID = SM.FindBufferContainingLoc(DiagItr->CheckLoc);
|
||||
auto CheckLineAndCol =
|
||||
SM.getLineAndColumn(DiagItr->CheckLoc, CheckBufferID);
|
||||
llvm::raw_string_ostream Label(A.Label);
|
||||
Label << GetCheckTypeAbbreviation(DiagItr->CheckTy) << ":";
|
||||
if (CheckBufferID == CheckFileBufferID)
|
||||
Label << CheckLineAndCol.first;
|
||||
else if (ImpPatBufferIDRange.first <= CheckBufferID &&
|
||||
CheckBufferID < ImpPatBufferIDRange.second)
|
||||
Label << "imp" << (CheckBufferID - ImpPatBufferIDRange.first + 1);
|
||||
else
|
||||
llvm_unreachable("expected diagnostic's check location to be either in "
|
||||
"the check file or for an implicit pattern");
|
||||
unsigned CheckDiagIndex = UINT_MAX;
|
||||
auto DiagNext = std::next(DiagItr);
|
||||
if (DiagNext != DiagEnd && DiagItr->CheckTy == DiagNext->CheckTy &&
|
||||
DiagItr->CheckLoc == DiagNext->CheckLoc)
|
||||
CheckDiagIndex = CheckDiagCount++;
|
||||
else if (CheckDiagCount) {
|
||||
CheckDiagIndex = CheckDiagCount;
|
||||
CheckDiagCount = 0;
|
||||
}
|
||||
if (CheckDiagIndex != UINT_MAX)
|
||||
Label << "'" << CheckDiagIndex;
|
||||
Label.flush();
|
||||
LabelWidth = std::max((std::string::size_type)LabelWidth, A.Label.size());
|
||||
|
||||
A.Marker = GetMarker(DiagItr->MatchTy);
|
||||
if (!DiagItr->Note.empty()) {
|
||||
A.Marker.Note = DiagItr->Note;
|
||||
// It's less confusing if notes that don't actually have ranges don't have
|
||||
// markers. For example, a marker for 'with "VAR" equal to "5"' would
|
||||
// seem to indicate where "VAR" matches, but the location we actually have
|
||||
// for the marker simply points to the start of the match/search range for
|
||||
// the full pattern of which the substitution is potentially just one
|
||||
// component.
|
||||
if (DiagItr->InputStartLine == DiagItr->InputEndLine &&
|
||||
DiagItr->InputStartCol == DiagItr->InputEndCol)
|
||||
A.Marker.Lead = ' ';
|
||||
}
|
||||
A.FoundAndExpectedMatch =
|
||||
DiagItr->MatchTy == FileCheckDiag::MatchFoundAndExpected;
|
||||
|
||||
// Compute the mark location, and break annotation into multiple
|
||||
// annotations if it spans multiple lines.
|
||||
A.IsFirstLine = true;
|
||||
A.InputLine = DiagItr->InputStartLine;
|
||||
A.InputStartCol = DiagItr->InputStartCol;
|
||||
if (DiagItr->InputStartLine == DiagItr->InputEndLine) {
|
||||
// Sometimes ranges are empty in order to indicate a specific point, but
|
||||
// that would mean nothing would be marked, so adjust the range to
|
||||
// include the following character.
|
||||
A.InputEndCol =
|
||||
std::max(DiagItr->InputStartCol + 1, DiagItr->InputEndCol);
|
||||
Annotations.push_back(A);
|
||||
} else {
|
||||
assert(DiagItr->InputStartLine < DiagItr->InputEndLine &&
|
||||
"expected input range not to be inverted");
|
||||
A.InputEndCol = UINT_MAX;
|
||||
Annotations.push_back(A);
|
||||
for (unsigned L = DiagItr->InputStartLine + 1, E = DiagItr->InputEndLine;
|
||||
L <= E; ++L) {
|
||||
// If a range ends before the first column on a line, then it has no
|
||||
// characters on that line, so there's nothing to render.
|
||||
if (DiagItr->InputEndCol == 1 && L == E)
|
||||
break;
|
||||
InputAnnotation B;
|
||||
B.DiagIndex = A.DiagIndex;
|
||||
B.Label = A.Label;
|
||||
B.IsFirstLine = false;
|
||||
B.InputLine = L;
|
||||
B.Marker = A.Marker;
|
||||
B.Marker.Lead = '~';
|
||||
B.Marker.Note = "";
|
||||
B.InputStartCol = 1;
|
||||
if (L != E)
|
||||
B.InputEndCol = UINT_MAX;
|
||||
else
|
||||
B.InputEndCol = DiagItr->InputEndCol;
|
||||
B.FoundAndExpectedMatch = A.FoundAndExpectedMatch;
|
||||
Annotations.push_back(B);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned FindInputLineInFilter(
|
||||
DumpInputFilterValue DumpInputFilter, unsigned CurInputLine,
|
||||
const std::vector<InputAnnotation>::iterator &AnnotationBeg,
|
||||
const std::vector<InputAnnotation>::iterator &AnnotationEnd) {
|
||||
if (DumpInputFilter == DumpInputFilterAll)
|
||||
return CurInputLine;
|
||||
for (auto AnnotationItr = AnnotationBeg; AnnotationItr != AnnotationEnd;
|
||||
++AnnotationItr) {
|
||||
switch (DumpInputFilter) {
|
||||
case DumpInputFilterAll:
|
||||
llvm_unreachable("unexpected DumpInputFilterAll");
|
||||
break;
|
||||
case DumpInputFilterAnnotationFull:
|
||||
return AnnotationItr->InputLine;
|
||||
case DumpInputFilterAnnotation:
|
||||
if (AnnotationItr->IsFirstLine)
|
||||
return AnnotationItr->InputLine;
|
||||
break;
|
||||
case DumpInputFilterError:
|
||||
if (AnnotationItr->IsFirstLine && AnnotationItr->Marker.FiltersAsError)
|
||||
return AnnotationItr->InputLine;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return UINT_MAX;
|
||||
}
|
||||
|
||||
/// To OS, print a vertical ellipsis (right-justified at LabelWidth) if it would
|
||||
/// occupy less lines than ElidedLines, but print ElidedLines otherwise. Either
|
||||
/// way, clear ElidedLines. Thus, if ElidedLines is empty, do nothing.
|
||||
static void DumpEllipsisOrElidedLines(raw_ostream &OS, std::string &ElidedLines,
|
||||
unsigned LabelWidth) {
|
||||
if (ElidedLines.empty())
|
||||
return;
|
||||
unsigned EllipsisLines = 3;
|
||||
if (EllipsisLines < StringRef(ElidedLines).count('\n')) {
|
||||
for (unsigned i = 0; i < EllipsisLines; ++i) {
|
||||
WithColor(OS, raw_ostream::BLACK, /*Bold=*/true)
|
||||
<< right_justify(".", LabelWidth);
|
||||
OS << '\n';
|
||||
}
|
||||
} else
|
||||
OS << ElidedLines;
|
||||
ElidedLines.clear();
|
||||
}
|
||||
|
||||
static void DumpAnnotatedInput(raw_ostream &OS, const FileCheckRequest &Req,
|
||||
DumpInputFilterValue DumpInputFilter,
|
||||
unsigned DumpInputContext,
|
||||
StringRef InputFileText,
|
||||
std::vector<InputAnnotation> &Annotations,
|
||||
unsigned LabelWidth) {
|
||||
OS << "Input was:\n<<<<<<\n";
|
||||
|
||||
// Sort annotations.
|
||||
llvm::sort(Annotations,
|
||||
[](const InputAnnotation &A, const InputAnnotation &B) {
|
||||
// 1. Sort annotations in the order of the input lines.
|
||||
//
|
||||
// This makes it easier to find relevant annotations while
|
||||
// iterating input lines in the implementation below. FileCheck
|
||||
// does not always produce diagnostics in the order of input
|
||||
// lines due to, for example, CHECK-DAG and CHECK-NOT.
|
||||
if (A.InputLine != B.InputLine)
|
||||
return A.InputLine < B.InputLine;
|
||||
// 2. Sort annotations in the temporal order FileCheck produced
|
||||
// their associated diagnostics.
|
||||
//
|
||||
// This sort offers several benefits:
|
||||
//
|
||||
// A. On a single input line, the order of annotations reflects
|
||||
// the FileCheck logic for processing directives/patterns.
|
||||
// This can be helpful in understanding cases in which the
|
||||
// order of the associated directives/patterns in the check
|
||||
// file or on the command line either (i) does not match the
|
||||
// temporal order in which FileCheck looks for matches for the
|
||||
// directives/patterns (due to, for example, CHECK-LABEL,
|
||||
// CHECK-NOT, or `--implicit-check-not`) or (ii) does match
|
||||
// that order but does not match the order of those
|
||||
// diagnostics along an input line (due to, for example,
|
||||
// CHECK-DAG).
|
||||
//
|
||||
// On the other hand, because our presentation format presents
|
||||
// input lines in order, there's no clear way to offer the
|
||||
// same benefit across input lines. For consistency, it might
|
||||
// then seem worthwhile to have annotations on a single line
|
||||
// also sorted in input order (that is, by input column).
|
||||
// However, in practice, this appears to be more confusing
|
||||
// than helpful. Perhaps it's intuitive to expect annotations
|
||||
// to be listed in the temporal order in which they were
|
||||
// produced except in cases the presentation format obviously
|
||||
// and inherently cannot support it (that is, across input
|
||||
// lines).
|
||||
//
|
||||
// B. When diagnostics' annotations are split among multiple
|
||||
// input lines, the user must track them from one input line
|
||||
// to the next. One property of the sort chosen here is that
|
||||
// it facilitates the user in this regard by ensuring the
|
||||
// following: when comparing any two input lines, a
|
||||
// diagnostic's annotations are sorted in the same position
|
||||
// relative to all other diagnostics' annotations.
|
||||
return A.DiagIndex < B.DiagIndex;
|
||||
});
|
||||
|
||||
// Compute the width of the label column.
|
||||
const unsigned char *InputFilePtr = InputFileText.bytes_begin(),
|
||||
*InputFileEnd = InputFileText.bytes_end();
|
||||
unsigned LineCount = InputFileText.count('\n');
|
||||
if (InputFileEnd[-1] != '\n')
|
||||
++LineCount;
|
||||
unsigned LineNoWidth = std::log10(LineCount) + 1;
|
||||
// +3 below adds spaces (1) to the left of the (right-aligned) line numbers
|
||||
// on input lines and (2) to the right of the (left-aligned) labels on
|
||||
// annotation lines so that input lines and annotation lines are more
|
||||
// visually distinct. For example, the spaces on the annotation lines ensure
|
||||
// that input line numbers and check directive line numbers never align
|
||||
// horizontally. Those line numbers might not even be for the same file.
|
||||
// One space would be enough to achieve that, but more makes it even easier
|
||||
// to see.
|
||||
LabelWidth = std::max(LabelWidth, LineNoWidth) + 3;
|
||||
|
||||
// Print annotated input lines.
|
||||
unsigned PrevLineInFilter = 0; // 0 means none so far
|
||||
unsigned NextLineInFilter = 0; // 0 means uncomputed, UINT_MAX means none
|
||||
std::string ElidedLines;
|
||||
raw_string_ostream ElidedLinesOS(ElidedLines);
|
||||
ColorMode TheColorMode =
|
||||
WithColor(OS).colorsEnabled() ? ColorMode::Enable : ColorMode::Disable;
|
||||
if (TheColorMode == ColorMode::Enable)
|
||||
ElidedLinesOS.enable_colors(true);
|
||||
auto AnnotationItr = Annotations.begin(), AnnotationEnd = Annotations.end();
|
||||
for (unsigned Line = 1;
|
||||
InputFilePtr != InputFileEnd || AnnotationItr != AnnotationEnd;
|
||||
++Line) {
|
||||
const unsigned char *InputFileLine = InputFilePtr;
|
||||
|
||||
// Compute the previous and next line included by the filter.
|
||||
if (NextLineInFilter < Line)
|
||||
NextLineInFilter = FindInputLineInFilter(DumpInputFilter, Line,
|
||||
AnnotationItr, AnnotationEnd);
|
||||
assert(NextLineInFilter && "expected NextLineInFilter to be computed");
|
||||
if (NextLineInFilter == Line)
|
||||
PrevLineInFilter = Line;
|
||||
|
||||
// Elide this input line and its annotations if it's not within the
|
||||
// context specified by -dump-input-context of an input line included by
|
||||
// -dump-input-filter. However, in case the resulting ellipsis would occupy
|
||||
// more lines than the input lines and annotations it elides, buffer the
|
||||
// elided lines and annotations so we can print them instead.
|
||||
raw_ostream *LineOS = &OS;
|
||||
if ((!PrevLineInFilter || PrevLineInFilter + DumpInputContext < Line) &&
|
||||
(NextLineInFilter == UINT_MAX ||
|
||||
Line + DumpInputContext < NextLineInFilter))
|
||||
LineOS = &ElidedLinesOS;
|
||||
else {
|
||||
LineOS = &OS;
|
||||
DumpEllipsisOrElidedLines(OS, ElidedLinesOS.str(), LabelWidth);
|
||||
}
|
||||
|
||||
// Print right-aligned line number.
|
||||
WithColor(*LineOS, raw_ostream::BLACK, /*Bold=*/true, /*BF=*/false,
|
||||
TheColorMode)
|
||||
<< format_decimal(Line, LabelWidth) << ": ";
|
||||
|
||||
// For the case where -v and colors are enabled, find the annotations for
|
||||
// good matches for expected patterns in order to highlight everything
|
||||
// else in the line. There are no such annotations if -v is disabled.
|
||||
std::vector<InputAnnotation> FoundAndExpectedMatches;
|
||||
if (Req.Verbose && TheColorMode == ColorMode::Enable) {
|
||||
for (auto I = AnnotationItr; I != AnnotationEnd && I->InputLine == Line;
|
||||
++I) {
|
||||
if (I->FoundAndExpectedMatch)
|
||||
FoundAndExpectedMatches.push_back(*I);
|
||||
}
|
||||
}
|
||||
|
||||
// Print numbered line with highlighting where there are no matches for
|
||||
// expected patterns.
|
||||
bool Newline = false;
|
||||
{
|
||||
WithColor COS(*LineOS, raw_ostream::SAVEDCOLOR, /*Bold=*/false,
|
||||
/*BG=*/false, TheColorMode);
|
||||
bool InMatch = false;
|
||||
if (Req.Verbose)
|
||||
COS.changeColor(raw_ostream::CYAN, true, true);
|
||||
for (unsigned Col = 1; InputFilePtr != InputFileEnd && !Newline; ++Col) {
|
||||
bool WasInMatch = InMatch;
|
||||
InMatch = false;
|
||||
for (auto M : FoundAndExpectedMatches) {
|
||||
if (M.InputStartCol <= Col && Col < M.InputEndCol) {
|
||||
InMatch = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!WasInMatch && InMatch)
|
||||
COS.resetColor();
|
||||
else if (WasInMatch && !InMatch)
|
||||
COS.changeColor(raw_ostream::CYAN, true, true);
|
||||
if (*InputFilePtr == '\n')
|
||||
Newline = true;
|
||||
else
|
||||
COS << *InputFilePtr;
|
||||
++InputFilePtr;
|
||||
}
|
||||
}
|
||||
*LineOS << '\n';
|
||||
unsigned InputLineWidth = InputFilePtr - InputFileLine - Newline;
|
||||
|
||||
// Print any annotations.
|
||||
while (AnnotationItr != AnnotationEnd &&
|
||||
AnnotationItr->InputLine == Line) {
|
||||
WithColor COS(*LineOS, AnnotationItr->Marker.Color, /*Bold=*/true,
|
||||
/*BG=*/false, TheColorMode);
|
||||
// The two spaces below are where the ": " appears on input lines.
|
||||
COS << left_justify(AnnotationItr->Label, LabelWidth) << " ";
|
||||
unsigned Col;
|
||||
for (Col = 1; Col < AnnotationItr->InputStartCol; ++Col)
|
||||
COS << ' ';
|
||||
COS << AnnotationItr->Marker.Lead;
|
||||
// If InputEndCol=UINT_MAX, stop at InputLineWidth.
|
||||
for (++Col; Col < AnnotationItr->InputEndCol && Col <= InputLineWidth;
|
||||
++Col)
|
||||
COS << '~';
|
||||
const std::string &Note = AnnotationItr->Marker.Note;
|
||||
if (!Note.empty()) {
|
||||
// Put the note at the end of the input line. If we were to instead
|
||||
// put the note right after the marker, subsequent annotations for the
|
||||
// same input line might appear to mark this note instead of the input
|
||||
// line.
|
||||
for (; Col <= InputLineWidth; ++Col)
|
||||
COS << ' ';
|
||||
COS << ' ' << Note;
|
||||
}
|
||||
COS << '\n';
|
||||
++AnnotationItr;
|
||||
}
|
||||
}
|
||||
DumpEllipsisOrElidedLines(OS, ElidedLinesOS.str(), LabelWidth);
|
||||
|
||||
OS << ">>>>>>\n";
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
// Enable use of ANSI color codes because FileCheck is using them to
|
||||
// highlight text.
|
||||
llvm::sys::Process::UseANSIEscapeCodes(true);
|
||||
|
||||
InitLLVM X(argc, argv);
|
||||
cl::ParseCommandLineOptions(argc, argv, /*Overview*/ "", /*Errs*/ nullptr,
|
||||
"FILECHECK_OPTS");
|
||||
|
||||
// Select -dump-input* values. The -help documentation specifies the default
|
||||
// value and which value to choose if an option is specified multiple times.
|
||||
// In the latter case, the general rule of thumb is to choose the value that
|
||||
// provides the most information.
|
||||
DumpInputValue DumpInput =
|
||||
DumpInputs.empty()
|
||||
? DumpInputFail
|
||||
: *std::max_element(DumpInputs.begin(), DumpInputs.end());
|
||||
DumpInputFilterValue DumpInputFilter;
|
||||
if (DumpInputFilters.empty())
|
||||
DumpInputFilter = DumpInput == DumpInputAlways ? DumpInputFilterAll
|
||||
: DumpInputFilterError;
|
||||
else
|
||||
DumpInputFilter =
|
||||
*std::max_element(DumpInputFilters.begin(), DumpInputFilters.end());
|
||||
unsigned DumpInputContext = DumpInputContexts.empty()
|
||||
? 5
|
||||
: *std::max_element(DumpInputContexts.begin(),
|
||||
DumpInputContexts.end());
|
||||
|
||||
if (DumpInput == DumpInputHelp) {
|
||||
DumpInputAnnotationHelp(outs());
|
||||
return 0;
|
||||
}
|
||||
if (CheckFilename.empty()) {
|
||||
errs() << "<check-file> not specified\n";
|
||||
return 2;
|
||||
}
|
||||
|
||||
FileCheckRequest Req;
|
||||
for (StringRef Prefix : CheckPrefixes)
|
||||
Req.CheckPrefixes.push_back(Prefix);
|
||||
|
||||
for (StringRef Prefix : CommentPrefixes)
|
||||
Req.CommentPrefixes.push_back(Prefix);
|
||||
|
||||
for (StringRef CheckNot : ImplicitCheckNot)
|
||||
Req.ImplicitCheckNot.push_back(CheckNot);
|
||||
|
||||
bool GlobalDefineError = false;
|
||||
for (StringRef G : GlobalDefines) {
|
||||
size_t EqIdx = G.find('=');
|
||||
if (EqIdx == std::string::npos) {
|
||||
errs() << "Missing equal sign in command-line definition '-D" << G
|
||||
<< "'\n";
|
||||
GlobalDefineError = true;
|
||||
continue;
|
||||
}
|
||||
if (EqIdx == 0) {
|
||||
errs() << "Missing variable name in command-line definition '-D" << G
|
||||
<< "'\n";
|
||||
GlobalDefineError = true;
|
||||
continue;
|
||||
}
|
||||
Req.GlobalDefines.push_back(G);
|
||||
}
|
||||
if (GlobalDefineError)
|
||||
return 2;
|
||||
|
||||
Req.AllowEmptyInput = AllowEmptyInput;
|
||||
Req.AllowUnusedPrefixes = AllowUnusedPrefixes;
|
||||
Req.EnableVarScope = EnableVarScope;
|
||||
Req.AllowDeprecatedDagOverlap = AllowDeprecatedDagOverlap;
|
||||
Req.Verbose = Verbose;
|
||||
Req.VerboseVerbose = VerboseVerbose;
|
||||
Req.NoCanonicalizeWhiteSpace = NoCanonicalizeWhiteSpace;
|
||||
Req.MatchFullLines = MatchFullLines;
|
||||
Req.IgnoreCase = IgnoreCase;
|
||||
|
||||
if (VerboseVerbose)
|
||||
Req.Verbose = true;
|
||||
|
||||
FileCheck FC(Req);
|
||||
if (!FC.ValidateCheckPrefixes())
|
||||
return 2;
|
||||
|
||||
Regex PrefixRE = FC.buildCheckPrefixRegex();
|
||||
std::string REError;
|
||||
if (!PrefixRE.isValid(REError)) {
|
||||
errs() << "Unable to combine check-prefix strings into a prefix regular "
|
||||
"expression! This is likely a bug in FileCheck's verification of "
|
||||
"the check-prefix strings. Regular expression parsing failed "
|
||||
"with the following error: "
|
||||
<< REError << "\n";
|
||||
return 2;
|
||||
}
|
||||
|
||||
SourceMgr SM;
|
||||
|
||||
// Read the expected strings from the check file.
|
||||
ErrorOr<std::unique_ptr<MemoryBuffer>> CheckFileOrErr =
|
||||
MemoryBuffer::getFileOrSTDIN(CheckFilename);
|
||||
if (std::error_code EC = CheckFileOrErr.getError()) {
|
||||
errs() << "Could not open check file '" << CheckFilename
|
||||
<< "': " << EC.message() << '\n';
|
||||
return 2;
|
||||
}
|
||||
MemoryBuffer &CheckFile = *CheckFileOrErr.get();
|
||||
|
||||
SmallString<4096> CheckFileBuffer;
|
||||
StringRef CheckFileText = FC.CanonicalizeFile(CheckFile, CheckFileBuffer);
|
||||
|
||||
unsigned CheckFileBufferID =
|
||||
SM.AddNewSourceBuffer(MemoryBuffer::getMemBuffer(
|
||||
CheckFileText, CheckFile.getBufferIdentifier()),
|
||||
SMLoc());
|
||||
|
||||
std::pair<unsigned, unsigned> ImpPatBufferIDRange;
|
||||
if (FC.readCheckFile(SM, CheckFileText, PrefixRE, &ImpPatBufferIDRange))
|
||||
return 2;
|
||||
|
||||
// Open the file to check and add it to SourceMgr.
|
||||
ErrorOr<std::unique_ptr<MemoryBuffer>> InputFileOrErr =
|
||||
MemoryBuffer::getFileOrSTDIN(InputFilename);
|
||||
if (InputFilename == "-")
|
||||
InputFilename = "<stdin>"; // Overwrite for improved diagnostic messages
|
||||
if (std::error_code EC = InputFileOrErr.getError()) {
|
||||
errs() << "Could not open input file '" << InputFilename
|
||||
<< "': " << EC.message() << '\n';
|
||||
return 2;
|
||||
}
|
||||
MemoryBuffer &InputFile = *InputFileOrErr.get();
|
||||
|
||||
if (InputFile.getBufferSize() == 0 && !AllowEmptyInput) {
|
||||
errs() << "FileCheck error: '" << InputFilename << "' is empty.\n";
|
||||
DumpCommandLine(argc, argv);
|
||||
return 2;
|
||||
}
|
||||
|
||||
SmallString<4096> InputFileBuffer;
|
||||
StringRef InputFileText = FC.CanonicalizeFile(InputFile, InputFileBuffer);
|
||||
|
||||
SM.AddNewSourceBuffer(MemoryBuffer::getMemBuffer(
|
||||
InputFileText, InputFile.getBufferIdentifier()),
|
||||
SMLoc());
|
||||
|
||||
std::vector<FileCheckDiag> Diags;
|
||||
int ExitCode = FC.checkInput(SM, InputFileText,
|
||||
DumpInput == DumpInputNever ? nullptr : &Diags)
|
||||
? EXIT_SUCCESS
|
||||
: 1;
|
||||
if (DumpInput == DumpInputAlways ||
|
||||
(ExitCode == 1 && DumpInput == DumpInputFail)) {
|
||||
errs() << "\n"
|
||||
<< "Input file: " << InputFilename << "\n"
|
||||
<< "Check file: " << CheckFilename << "\n"
|
||||
<< "\n"
|
||||
<< "-dump-input=help explains the following input dump.\n"
|
||||
<< "\n";
|
||||
std::vector<InputAnnotation> Annotations;
|
||||
unsigned LabelWidth;
|
||||
BuildInputAnnotations(SM, CheckFileBufferID, ImpPatBufferIDRange, Diags,
|
||||
Annotations, LabelWidth);
|
||||
DumpAnnotatedInput(errs(), Req, DumpInputFilter, DumpInputContext,
|
||||
InputFileText, Annotations, LabelWidth);
|
||||
}
|
||||
|
||||
return ExitCode;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue