mirror of
https://git.FreeBSD.org/src.git
synced 2024-11-28 08:02:54 +00:00
Merge llvm-project release/13.x llvmorg-13.0.0-rc1-97-g23ba3732246a
This updates llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and openmp to llvmorg-13.0.0-rc1-97-g23ba3732246a. PR: 258209 MFC after: 2 weeks
This commit is contained in:
commit
6e75b2fbf9
@ -331,6 +331,152 @@ OLD_DIRS+=usr/lib/clang/12.0.1/lib/freebsd
|
||||
OLD_DIRS+=usr/lib/clang/12.0.1/lib
|
||||
OLD_DIRS+=usr/lib/clang/12.0.1
|
||||
|
||||
# 20211113: new libc++ import which bumps version from 12.0.1 to 13.0.0.
|
||||
OLD_FILES+=usr/include/c++/v1/__functional_03
|
||||
OLD_FILES+=usr/include/c++/v1/__functional_base_03
|
||||
OLD_FILES+=usr/include/c++/v1/__memory/base.h
|
||||
OLD_FILES+=usr/include/c++/v1/__memory/utilities.h
|
||||
OLD_FILES+=usr/include/c++/v1/__sso_allocator
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/__availability
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/__bit_reference
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/__bits
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/__bsd_locale_defaults.h
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/__bsd_locale_fallbacks.h
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/__config
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/__debug
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/__errc
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/__functional_03
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/__functional_base
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/__functional_base_03
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/__hash_table
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/__libcpp_version
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/__locale
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/__mutex_base
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/__node_handle
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/__nullptr
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/__split_buffer
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/__sso_allocator
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/__std_stream
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/__string
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/__threading_support
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/__tree
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/__tuple
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/__undef_macros
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/algorithm
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/any
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/array
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/atomic
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/barrier
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/bit
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/bitset
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/cassert
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/ccomplex
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/cctype
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/cerrno
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/cfenv
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/cfloat
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/charconv
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/chrono
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/cinttypes
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/ciso646
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/climits
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/clocale
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/cmath
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/codecvt
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/compare
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/complex
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/complex.h
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/concepts
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/condition_variable
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/csetjmp
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/csignal
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/cstdarg
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/cstdbool
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/cstddef
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/cstdint
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/cstdio
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/cstdlib
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/cstring
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/ctgmath
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/ctime
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/ctype.h
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/cwchar
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/cwctype
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/deque
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/errno.h
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/exception
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/execution
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/fenv.h
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/filesystem
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/float.h
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/forward_list
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/fstream
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/functional
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/future
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/initializer_list
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/inttypes.h
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/iomanip
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/ios
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/iosfwd
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/iostream
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/istream
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/iterator
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/latch
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/limits
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/limits.h
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/list
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/locale
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/locale.h
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/map
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/math.h
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/memory
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/mutex
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/new
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/numbers
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/numeric
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/optional
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/ostream
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/queue
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/random
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/ratio
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/regex
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/scoped_allocator
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/semaphore
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/set
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/setjmp.h
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/shared_mutex
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/span
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/sstream
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/stack
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/stdbool.h
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/stddef.h
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/stdexcept
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/stdint.h
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/stdio.h
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/stdlib.h
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/streambuf
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/string
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/string.h
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/string_view
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/strstream
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/system_error
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/tgmath.h
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/thread
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/tuple
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/type_traits
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/typeindex
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/typeinfo
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/unordered_map
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/unordered_set
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/utility
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/valarray
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/variant
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/vector
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/version
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/wchar.h
|
||||
OLD_FILES+=usr/include/c++/v1/tr1/wctype.h
|
||||
OLD_DIRS+=usr/include/c++/v1/tr1
|
||||
|
||||
# 20211027: libdialog shlib bumped to version 10 for dialog 1.3
|
||||
OLD_LIBS+=usr/lib/libdialog.so.9
|
||||
OLD_LIBS+=usr/lib/libdpv.so.2
|
||||
|
@ -243,6 +243,9 @@ TARGET_HEADER_BUILTIN(_ReadStatusReg, "LLii", "nh", "intrin.h", ALL_MS_LANGUAG
|
||||
TARGET_HEADER_BUILTIN(_WriteStatusReg, "viLLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
|
||||
TARGET_HEADER_BUILTIN(_AddressOfReturnAddress, "v*", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
|
||||
|
||||
TARGET_HEADER_BUILTIN(__mulh, "SLLiSLLiSLLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
|
||||
TARGET_HEADER_BUILTIN(__umulh, "ULLiULLiULLi", "nh", "intrin.h", ALL_MS_LANGUAGES, "")
|
||||
|
||||
#undef BUILTIN
|
||||
#undef LANGBUILTIN
|
||||
#undef TARGET_HEADER_BUILTIN
|
||||
|
@ -129,8 +129,6 @@ def err_drv_invalid_Xopenmp_target_with_args : Error<
|
||||
"invalid -Xopenmp-target argument: '%0', options requiring arguments are unsupported">;
|
||||
def err_drv_argument_only_allowed_with : Error<
|
||||
"invalid argument '%0' only allowed with '%1'">;
|
||||
def err_drv_minws_unsupported_input_type : Error<
|
||||
"'-fminimize-whitespace' invalid for input of type %0">;
|
||||
def err_drv_amdgpu_ieee_without_no_honor_nans : Error<
|
||||
"invalid argument '-mno-amdgpu-ieee' only allowed with relaxed NaN handling">;
|
||||
def err_drv_argument_not_allowed_with : Error<
|
||||
|
@ -300,6 +300,13 @@ def pp_pragma_once_in_main_file : Warning<"#pragma once in main file">,
|
||||
def pp_pragma_sysheader_in_main_file : Warning<
|
||||
"#pragma system_header ignored in main file">,
|
||||
InGroup<DiagGroup<"pragma-system-header-outside-header">>;
|
||||
|
||||
def err_pragma_include_instead_not_sysheader : Error<
|
||||
"'#pragma clang include_instead' cannot be used outside of system headers">;
|
||||
def err_pragma_include_instead_system_reserved : Error<
|
||||
"header '%0' is an implementation detail; #include %select{'%2'|either '%2' "
|
||||
"or '%3'|one of %2}1 instead">;
|
||||
|
||||
def pp_poisoning_existing_macro : Warning<"poisoning existing macro">;
|
||||
def pp_out_of_date_dependency : Warning<
|
||||
"current file is older than dependency %0">;
|
||||
|
@ -10100,8 +10100,6 @@ def err_opencl_requires_extension : Error<
|
||||
def ext_opencl_double_without_pragma : Extension<
|
||||
"Clang permits use of type 'double' regardless pragma if 'cl_khr_fp64' is"
|
||||
" supported">;
|
||||
def err_opencl_double_requires_extension : Error<
|
||||
"use of type 'double' requires %select{cl_khr_fp64|cl_khr_fp64 and __opencl_c_fp64}0 support">;
|
||||
def warn_opencl_generic_address_space_arg : Warning<
|
||||
"passing non-generic address space pointer to %0"
|
||||
" may cause dynamic conversion affecting performance">,
|
||||
|
@ -224,7 +224,7 @@ LANGOPT(OpenCLVersion , 32, 0, "OpenCL C version")
|
||||
LANGOPT(OpenCLCPlusPlus , 1, 0, "C++ for OpenCL")
|
||||
LANGOPT(OpenCLCPlusPlusVersion , 32, 0, "C++ for OpenCL version")
|
||||
LANGOPT(OpenCLGenericAddressSpace, 1, 0, "OpenCL generic keyword")
|
||||
LANGOPT(OpenCLPipe , 1, 0, "OpenCL pipe keyword")
|
||||
LANGOPT(OpenCLPipes , 1, 0, "OpenCL pipes language constructs and built-ins")
|
||||
LANGOPT(NativeHalfType , 1, 0, "Native half type support")
|
||||
LANGOPT(NativeHalfArgsAndReturns, 1, 0, "Native half args and returns")
|
||||
LANGOPT(HalfArgsAndReturns, 1, 0, "half args and returns")
|
||||
|
@ -354,6 +354,9 @@ class LangOptions : public LangOptionsBase {
|
||||
/// A list of all -fno-builtin-* function names (e.g., memset).
|
||||
std::vector<std::string> NoBuiltinFuncs;
|
||||
|
||||
/// A prefix map for __FILE__, __BASE_FILE__ and __builtin_FILE().
|
||||
std::map<std::string, std::string, std::greater<std::string>> MacroPrefixMap;
|
||||
|
||||
/// Triples of the OpenMP targets that the host code codegen should
|
||||
/// take into account in order to generate accurate offloading descriptors.
|
||||
std::vector<llvm::Triple> OMPTargetTriples;
|
||||
@ -460,6 +463,9 @@ class LangOptions : public LangOptionsBase {
|
||||
}
|
||||
|
||||
bool isSYCL() const { return SYCLIsDevice || SYCLIsHost; }
|
||||
|
||||
/// Remap path prefix according to -fmacro-prefix-path option.
|
||||
void remapPathPrefix(SmallString<256> &Path) const;
|
||||
};
|
||||
|
||||
/// Floating point control options
|
||||
|
@ -1799,9 +1799,6 @@ def frewrite_map_file_EQ : Joined<["-"], "frewrite-map-file=">,
|
||||
defm use_line_directives : BoolFOption<"use-line-directives",
|
||||
PreprocessorOutputOpts<"UseLineDirectives">, DefaultFalse,
|
||||
PosFlag<SetTrue, [CC1Option], "Use #line in preprocessed output">, NegFlag<SetFalse>>;
|
||||
defm minimize_whitespace : BoolFOption<"minimize-whitespace",
|
||||
PreprocessorOutputOpts<"MinimizeWhitespace">, DefaultFalse,
|
||||
PosFlag<SetTrue, [CC1Option], "Minimize whitespace when emitting preprocessor output">, NegFlag<SetFalse>>;
|
||||
|
||||
def ffreestanding : Flag<["-"], "ffreestanding">, Group<f_Group>, Flags<[CC1Option]>,
|
||||
HelpText<"Assert that the compilation takes place in a freestanding environment">,
|
||||
@ -2828,10 +2825,10 @@ def fcoverage_prefix_map_EQ
|
||||
HelpText<"remap file source paths in coverage mapping">;
|
||||
def ffile_prefix_map_EQ
|
||||
: Joined<["-"], "ffile-prefix-map=">, Group<f_Group>,
|
||||
HelpText<"remap file source paths in debug info and predefined preprocessor macros">;
|
||||
HelpText<"remap file source paths in debug info, predefined preprocessor macros and __builtin_FILE()">;
|
||||
def fmacro_prefix_map_EQ
|
||||
: Joined<["-"], "fmacro-prefix-map=">, Group<Preprocessor_Group>, Flags<[CC1Option]>,
|
||||
HelpText<"remap file source paths in predefined preprocessor macros">;
|
||||
: Joined<["-"], "fmacro-prefix-map=">, Group<f_Group>, Flags<[CC1Option]>,
|
||||
HelpText<"remap file source paths in predefined preprocessor macros and __builtin_FILE()">;
|
||||
defm force_dwarf_frame : BoolFOption<"force-dwarf-frame",
|
||||
CodeGenOpts<"ForceDwarfFrameSection">, DefaultFalse,
|
||||
PosFlag<SetTrue, [CC1Option], "Always emit a debug frame section">, NegFlag<SetFalse>>;
|
||||
|
@ -66,14 +66,6 @@ namespace types {
|
||||
/// isAcceptedByClang - Can clang handle this input type.
|
||||
bool isAcceptedByClang(ID Id);
|
||||
|
||||
/// isDerivedFromC - Is the input derived from C.
|
||||
///
|
||||
/// That is, does the lexer follow the rules of
|
||||
/// TokenConcatenation::AvoidConcat. If this is the case, the preprocessor may
|
||||
/// add and remove whitespace between tokens. Used to determine whether the
|
||||
/// input can be processed by -fminimize-whitespace.
|
||||
bool isDerivedFromC(ID Id);
|
||||
|
||||
/// isCXX - Is this a "C++" input (C++ and Obj-C++ sources and headers).
|
||||
bool isCXX(ID Id);
|
||||
|
||||
|
@ -24,7 +24,6 @@ class PreprocessorOutputOptions {
|
||||
unsigned ShowIncludeDirectives : 1; ///< Print includes, imports etc. within preprocessed output.
|
||||
unsigned RewriteIncludes : 1; ///< Preprocess include directives only.
|
||||
unsigned RewriteImports : 1; ///< Include contents of transitively-imported modules.
|
||||
unsigned MinimizeWhitespace : 1; ///< Ignore whitespace from input.
|
||||
|
||||
public:
|
||||
PreprocessorOutputOptions() {
|
||||
@ -37,7 +36,6 @@ class PreprocessorOutputOptions {
|
||||
ShowIncludeDirectives = 0;
|
||||
RewriteIncludes = 0;
|
||||
RewriteImports = 0;
|
||||
MinimizeWhitespace = 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -20,9 +20,12 @@
|
||||
#include "clang/Lex/ModuleMap.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/SetVector.h"
|
||||
#include "llvm/ADT/SmallSet.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include "llvm/ADT/StringSet.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ADT/StringSet.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
@ -110,6 +113,14 @@ struct HeaderFileInfo {
|
||||
/// of the framework.
|
||||
StringRef Framework;
|
||||
|
||||
/// List of aliases that this header is known as.
|
||||
/// Most headers should only have at most one alias, but a handful
|
||||
/// have two.
|
||||
llvm::SetVector<llvm::SmallString<32>,
|
||||
llvm::SmallVector<llvm::SmallString<32>, 2>,
|
||||
llvm::SmallSet<llvm::SmallString<32>, 2>>
|
||||
Aliases;
|
||||
|
||||
HeaderFileInfo()
|
||||
: isImport(false), isPragmaOnce(false), DirInfo(SrcMgr::C_User),
|
||||
External(false), isModuleHeader(false), isCompilingModuleHeader(false),
|
||||
@ -453,6 +464,10 @@ class HeaderSearch {
|
||||
getFileInfo(File).DirInfo = SrcMgr::C_System;
|
||||
}
|
||||
|
||||
void AddFileAlias(const FileEntry *File, StringRef Alias) {
|
||||
getFileInfo(File).Aliases.insert(Alias);
|
||||
}
|
||||
|
||||
/// Mark the specified file as part of a module.
|
||||
void MarkFileModuleHeader(const FileEntry *FE,
|
||||
ModuleMap::ModuleHeaderRole Role,
|
||||
|
@ -1953,7 +1953,8 @@ class Preprocessor {
|
||||
/// This either returns the EOF token and returns true, or
|
||||
/// pops a level off the include stack and returns false, at which point the
|
||||
/// client should call lex again.
|
||||
bool HandleEndOfFile(Token &Result, bool isEndOfMacro = false);
|
||||
bool HandleEndOfFile(Token &Result, SourceLocation Loc,
|
||||
bool isEndOfMacro = false);
|
||||
|
||||
/// Callback invoked when the current TokenLexer hits the end of its
|
||||
/// token stream.
|
||||
@ -2363,12 +2364,14 @@ class Preprocessor {
|
||||
|
||||
// Pragmas.
|
||||
void HandlePragmaDirective(PragmaIntroducer Introducer);
|
||||
void ResolvePragmaIncludeInstead(SourceLocation Location) const;
|
||||
|
||||
public:
|
||||
void HandlePragmaOnce(Token &OnceTok);
|
||||
void HandlePragmaMark(Token &MarkTok);
|
||||
void HandlePragmaPoison();
|
||||
void HandlePragmaSystemHeader(Token &SysHeaderTok);
|
||||
void HandlePragmaIncludeInstead(Token &Tok);
|
||||
void HandlePragmaDependency(Token &DependencyTok);
|
||||
void HandlePragmaPushMacro(Token &Tok);
|
||||
void HandlePragmaPopMacro(Token &Tok);
|
||||
|
@ -14,11 +14,13 @@
|
||||
#ifndef LLVM_CLANG_LEX_PREPROCESSORLEXER_H
|
||||
#define LLVM_CLANG_LEX_PREPROCESSORLEXER_H
|
||||
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "clang/Lex/HeaderSearch.h"
|
||||
#include "clang/Lex/MultipleIncludeOpt.h"
|
||||
#include "clang/Lex/Token.h"
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include <cassert>
|
||||
|
||||
namespace clang {
|
||||
@ -74,6 +76,13 @@ class PreprocessorLexer {
|
||||
/// we are currently in.
|
||||
SmallVector<PPConditionalInfo, 4> ConditionalStack;
|
||||
|
||||
struct IncludeInfo {
|
||||
const FileEntry *File;
|
||||
SourceLocation Location;
|
||||
};
|
||||
// A complete history of all the files included by the current file.
|
||||
llvm::StringMap<IncludeInfo> IncludeHistory;
|
||||
|
||||
PreprocessorLexer() : FID() {}
|
||||
PreprocessorLexer(Preprocessor *pp, FileID fid);
|
||||
virtual ~PreprocessorLexer() = default;
|
||||
@ -175,6 +184,15 @@ class PreprocessorLexer {
|
||||
ConditionalStack.clear();
|
||||
ConditionalStack.append(CL.begin(), CL.end());
|
||||
}
|
||||
|
||||
void addInclude(StringRef Filename, const FileEntry &File,
|
||||
SourceLocation Location) {
|
||||
IncludeHistory.insert({Filename, {&File, Location}});
|
||||
}
|
||||
|
||||
const llvm::StringMap<IncludeInfo> &getIncludeHistory() const {
|
||||
return IncludeHistory;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace clang
|
||||
|
@ -199,9 +199,6 @@ class PreprocessorOptions {
|
||||
/// build it again.
|
||||
std::shared_ptr<FailedModulesSet> FailedModules;
|
||||
|
||||
/// A prefix map for __FILE__ and __BASE_FILE__.
|
||||
std::map<std::string, std::string, std::greater<std::string>> MacroPrefixMap;
|
||||
|
||||
/// Contains the currently active skipped range mappings for skipping excluded
|
||||
/// conditional directives.
|
||||
///
|
||||
|
@ -7828,8 +7828,7 @@ class Sema final {
|
||||
TemplateArgumentLoc &Arg,
|
||||
SmallVectorImpl<TemplateArgument> &Converted);
|
||||
|
||||
bool CheckTemplateArgument(TemplateTypeParmDecl *Param,
|
||||
TypeSourceInfo *Arg);
|
||||
bool CheckTemplateArgument(TypeSourceInfo *Arg);
|
||||
ExprResult CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
|
||||
QualType InstantiatedParamType, Expr *Arg,
|
||||
TemplateArgument &Converted,
|
||||
|
@ -6066,9 +6066,11 @@ ASTContext::getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) const {
|
||||
NNS->getAsNamespaceAlias()->getNamespace()
|
||||
->getOriginalNamespace());
|
||||
|
||||
// The difference between TypeSpec and TypeSpecWithTemplate is that the
|
||||
// latter will have the 'template' keyword when printed.
|
||||
case NestedNameSpecifier::TypeSpec:
|
||||
case NestedNameSpecifier::TypeSpecWithTemplate: {
|
||||
QualType T = getCanonicalType(QualType(NNS->getAsType(), 0));
|
||||
const Type *T = getCanonicalType(NNS->getAsType());
|
||||
|
||||
// If we have some kind of dependent-named type (e.g., "typename T::type"),
|
||||
// break it apart into its prefix and identifier, then reconsititute those
|
||||
@ -6078,14 +6080,16 @@ ASTContext::getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) const {
|
||||
// typedef typename T::type T1;
|
||||
// typedef typename T1::type T2;
|
||||
if (const auto *DNT = T->getAs<DependentNameType>())
|
||||
return NestedNameSpecifier::Create(*this, DNT->getQualifier(),
|
||||
const_cast<IdentifierInfo *>(DNT->getIdentifier()));
|
||||
return NestedNameSpecifier::Create(
|
||||
*this, DNT->getQualifier(),
|
||||
const_cast<IdentifierInfo *>(DNT->getIdentifier()));
|
||||
if (const auto *DTST = T->getAs<DependentTemplateSpecializationType>())
|
||||
return NestedNameSpecifier::Create(*this, DTST->getQualifier(), true,
|
||||
const_cast<Type *>(T));
|
||||
|
||||
// Otherwise, just canonicalize the type, and force it to be a TypeSpec.
|
||||
// FIXME: Why are TypeSpec and TypeSpecWithTemplate distinct in the
|
||||
// first place?
|
||||
// TODO: Set 'Template' parameter to true for other template types.
|
||||
return NestedNameSpecifier::Create(*this, nullptr, false,
|
||||
const_cast<Type *>(T.getTypePtr()));
|
||||
const_cast<Type *>(T));
|
||||
}
|
||||
|
||||
case NestedNameSpecifier::Global:
|
||||
|
@ -2233,8 +2233,11 @@ APValue SourceLocExpr::EvaluateInContext(const ASTContext &Ctx,
|
||||
};
|
||||
|
||||
switch (getIdentKind()) {
|
||||
case SourceLocExpr::File:
|
||||
return MakeStringLiteral(PLoc.getFilename());
|
||||
case SourceLocExpr::File: {
|
||||
SmallString<256> Path(PLoc.getFilename());
|
||||
Ctx.getLangOpts().remapPathPrefix(Path);
|
||||
return MakeStringLiteral(Path);
|
||||
}
|
||||
case SourceLocExpr::Function: {
|
||||
const Decl *CurDecl = dyn_cast_or_null<Decl>(Context);
|
||||
return MakeStringLiteral(
|
||||
|
@ -11,6 +11,8 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Basic/LangOptions.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
|
||||
using namespace clang;
|
||||
|
||||
@ -48,6 +50,12 @@ VersionTuple LangOptions::getOpenCLVersionTuple() const {
|
||||
return VersionTuple(Ver / 100, (Ver % 100) / 10);
|
||||
}
|
||||
|
||||
void LangOptions::remapPathPrefix(SmallString<256> &Path) const {
|
||||
for (const auto &Entry : MacroPrefixMap)
|
||||
if (llvm::sys::path::replace_path_prefix(Path, Entry.first, Entry.second))
|
||||
break;
|
||||
}
|
||||
|
||||
FPOptions FPOptions::defaultWithoutTrailingStorage(const LangOptions &LO) {
|
||||
FPOptions result(LO);
|
||||
return result;
|
||||
|
@ -111,7 +111,9 @@ bool OpenCLOptions::diagnoseUnsupportedFeatureDependencies(
|
||||
// Feature pairs. First feature in a pair requires the second one to be
|
||||
// supported.
|
||||
static const llvm::StringMap<llvm::StringRef> DependentFeaturesMap = {
|
||||
{"__opencl_c_read_write_images", "__opencl_c_images"}};
|
||||
{"__opencl_c_read_write_images", "__opencl_c_images"},
|
||||
{"__opencl_c_3d_image_writes", "__opencl_c_images"},
|
||||
{"__opencl_c_pipes", "__opencl_c_generic_address_space"}};
|
||||
|
||||
auto OpenCLFeaturesMap = TI.getSupportedOpenCLOpts();
|
||||
|
||||
@ -130,7 +132,8 @@ bool OpenCLOptions::diagnoseFeatureExtensionDifferences(
|
||||
const TargetInfo &TI, DiagnosticsEngine &Diags) {
|
||||
// Extensions and equivalent feature pairs.
|
||||
static const llvm::StringMap<llvm::StringRef> FeatureExtensionMap = {
|
||||
{"cl_khr_fp64", "__opencl_c_fp64"}};
|
||||
{"cl_khr_fp64", "__opencl_c_fp64"},
|
||||
{"cl_khr_3d_image_writes", "__opencl_c_3d_image_writes"}};
|
||||
|
||||
auto OpenCLFeaturesMap = TI.getSupportedOpenCLOpts();
|
||||
|
||||
|
@ -400,14 +400,18 @@ void TargetInfo::adjust(DiagnosticsEngine &Diags, LangOptions &Opts) {
|
||||
// OpenCL C v3.0 s6.7.5 - The generic address space requires support for
|
||||
// OpenCL C 2.0 or OpenCL C 3.0 with the __opencl_c_generic_address_space
|
||||
// feature
|
||||
// FIXME: OpenCLGenericAddressSpace is also defined in setLangDefaults()
|
||||
// OpenCL C v3.0 s6.2.1 - OpenCL pipes require support of OpenCL C 2.0
|
||||
// or later and __opencl_c_pipes feature
|
||||
// FIXME: These language options are also defined in setLangDefaults()
|
||||
// for OpenCL C 2.0 but with no access to target capabilities. Target
|
||||
// should be immutable once created and thus this language option needs
|
||||
// should be immutable once created and thus these language options need
|
||||
// to be defined only once.
|
||||
if (Opts.OpenCLVersion >= 300) {
|
||||
if (Opts.OpenCLVersion == 300) {
|
||||
const auto &OpenCLFeaturesMap = getSupportedOpenCLOpts();
|
||||
Opts.OpenCLGenericAddressSpace = hasFeatureEnabled(
|
||||
OpenCLFeaturesMap, "__opencl_c_generic_address_space");
|
||||
Opts.OpenCLPipes =
|
||||
hasFeatureEnabled(OpenCLFeaturesMap, "__opencl_c_pipes");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -431,7 +431,8 @@ bool AArch64TargetInfo::hasFeature(StringRef Feature) const {
|
||||
Feature == "sve2-aes" || Feature == "sve2-sha3" ||
|
||||
Feature == "sve2-sm4" || Feature == "f64mm" || Feature == "f32mm" ||
|
||||
Feature == "i8mm" || Feature == "bf16") &&
|
||||
(FPU & SveMode));
|
||||
(FPU & SveMode)) ||
|
||||
(Feature == "ls64" && HasLS64);
|
||||
}
|
||||
|
||||
bool AArch64TargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
|
||||
@ -752,6 +753,9 @@ bool AArch64TargetInfo::validateConstraintModifier(
|
||||
if (Size == 64)
|
||||
return true;
|
||||
|
||||
if (Size == 512)
|
||||
return HasLS64;
|
||||
|
||||
SuggestedModifier = "w";
|
||||
return false;
|
||||
}
|
||||
|
@ -310,9 +310,12 @@ class LLVM_LIBRARY_VISIBILITY AMDGPUTargetInfo final : public TargetInfo {
|
||||
Opts["cl_khr_mipmap_image"] = true;
|
||||
Opts["cl_khr_mipmap_image_writes"] = true;
|
||||
Opts["cl_khr_subgroups"] = true;
|
||||
Opts["cl_khr_3d_image_writes"] = true;
|
||||
Opts["cl_amd_media_ops"] = true;
|
||||
Opts["cl_amd_media_ops2"] = true;
|
||||
|
||||
Opts["__opencl_c_images"] = true;
|
||||
Opts["__opencl_c_3d_image_writes"] = true;
|
||||
Opts["cl_khr_3d_image_writes"] = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9732,6 +9732,29 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
|
||||
return Builder.CreateCall(F);
|
||||
}
|
||||
|
||||
if (BuiltinID == AArch64::BI__mulh || BuiltinID == AArch64::BI__umulh) {
|
||||
llvm::Type *ResType = ConvertType(E->getType());
|
||||
llvm::Type *Int128Ty = llvm::IntegerType::get(getLLVMContext(), 128);
|
||||
|
||||
bool IsSigned = BuiltinID == AArch64::BI__mulh;
|
||||
Value *LHS =
|
||||
Builder.CreateIntCast(EmitScalarExpr(E->getArg(0)), Int128Ty, IsSigned);
|
||||
Value *RHS =
|
||||
Builder.CreateIntCast(EmitScalarExpr(E->getArg(1)), Int128Ty, IsSigned);
|
||||
|
||||
Value *MulResult, *HigherBits;
|
||||
if (IsSigned) {
|
||||
MulResult = Builder.CreateNSWMul(LHS, RHS);
|
||||
HigherBits = Builder.CreateAShr(MulResult, 64);
|
||||
} else {
|
||||
MulResult = Builder.CreateNUWMul(LHS, RHS);
|
||||
HigherBits = Builder.CreateLShr(MulResult, 64);
|
||||
}
|
||||
HigherBits = Builder.CreateIntCast(HigherBits, ResType, IsSigned);
|
||||
|
||||
return HigherBits;
|
||||
}
|
||||
|
||||
// Handle MSVC intrinsics before argument evaluation to prevent double
|
||||
// evaluation.
|
||||
if (Optional<MSVCIntrin> MsvcIntId = translateAarch64ToMsvcIntrin(BuiltinID))
|
||||
|
@ -555,7 +555,8 @@ CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D,
|
||||
PrioritizedCXXGlobalInits.size());
|
||||
PrioritizedCXXGlobalInits.push_back(std::make_pair(Key, Fn));
|
||||
} else if (isTemplateInstantiation(D->getTemplateSpecializationKind()) ||
|
||||
getContext().GetGVALinkageForVariable(D) == GVA_DiscardableODR) {
|
||||
getContext().GetGVALinkageForVariable(D) == GVA_DiscardableODR ||
|
||||
D->hasAttr<SelectAnyAttr>()) {
|
||||
// C++ [basic.start.init]p2:
|
||||
// Definitions of explicitly specialized class template static data
|
||||
// members have ordered initialization. Other class template static data
|
||||
@ -568,17 +569,18 @@ CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D,
|
||||
// group with the global being initialized. On most platforms, this is a
|
||||
// minor startup time optimization. In the MS C++ ABI, there are no guard
|
||||
// variables, so this COMDAT key is required for correctness.
|
||||
AddGlobalCtor(Fn, 65535, COMDATKey);
|
||||
if (getTarget().getCXXABI().isMicrosoft() && COMDATKey) {
|
||||
// In The MS C++, MS add template static data member in the linker
|
||||
// drective.
|
||||
addUsedGlobal(COMDATKey);
|
||||
}
|
||||
} else if (D->hasAttr<SelectAnyAttr>()) {
|
||||
//
|
||||
// SelectAny globals will be comdat-folded. Put the initializer into a
|
||||
// COMDAT group associated with the global, so the initializers get folded
|
||||
// too.
|
||||
|
||||
AddGlobalCtor(Fn, 65535, COMDATKey);
|
||||
if (COMDATKey && (getTriple().isOSBinFormatELF() ||
|
||||
getTarget().getCXXABI().isMicrosoft())) {
|
||||
// When COMDAT is used on ELF or in the MS C++ ABI, the key must be in
|
||||
// llvm.used to prevent linker GC.
|
||||
addUsedGlobal(COMDATKey);
|
||||
}
|
||||
} else {
|
||||
I = DelayedCXXInitPosition.find(D); // Re-do lookup in case of re-hash.
|
||||
if (I == DelayedCXXInitPosition.end()) {
|
||||
|
@ -2097,7 +2097,8 @@ CodeGenFunction::EmitAsmInputLValue(const TargetInfo::ConstraintInfo &Info,
|
||||
} else {
|
||||
llvm::Type *Ty = ConvertType(InputType);
|
||||
uint64_t Size = CGM.getDataLayout().getTypeSizeInBits(Ty);
|
||||
if (Size <= 64 && llvm::isPowerOf2_64(Size)) {
|
||||
if ((Size <= 64 && llvm::isPowerOf2_64(Size)) ||
|
||||
getTargetHooks().isScalarizableAsmOperand(*this, Ty)) {
|
||||
Ty = llvm::IntegerType::get(getLLVMContext(), Size);
|
||||
Ty = llvm::PointerType::getUnqual(Ty);
|
||||
|
||||
@ -2320,23 +2321,28 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
|
||||
|
||||
// If this is a register output, then make the inline asm return it
|
||||
// by-value. If this is a memory result, return the value by-reference.
|
||||
bool isScalarizableAggregate =
|
||||
hasAggregateEvaluationKind(OutExpr->getType());
|
||||
if (!Info.allowsMemory() && (hasScalarEvaluationKind(OutExpr->getType()) ||
|
||||
isScalarizableAggregate)) {
|
||||
QualType QTy = OutExpr->getType();
|
||||
const bool IsScalarOrAggregate = hasScalarEvaluationKind(QTy) ||
|
||||
hasAggregateEvaluationKind(QTy);
|
||||
if (!Info.allowsMemory() && IsScalarOrAggregate) {
|
||||
|
||||
Constraints += "=" + OutputConstraint;
|
||||
ResultRegQualTys.push_back(OutExpr->getType());
|
||||
ResultRegQualTys.push_back(QTy);
|
||||
ResultRegDests.push_back(Dest);
|
||||
ResultTruncRegTypes.push_back(ConvertTypeForMem(OutExpr->getType()));
|
||||
if (Info.allowsRegister() && isScalarizableAggregate) {
|
||||
ResultTypeRequiresCast.push_back(true);
|
||||
unsigned Size = getContext().getTypeSize(OutExpr->getType());
|
||||
llvm::Type *ConvTy = llvm::IntegerType::get(getLLVMContext(), Size);
|
||||
ResultRegTypes.push_back(ConvTy);
|
||||
} else {
|
||||
ResultTypeRequiresCast.push_back(false);
|
||||
ResultRegTypes.push_back(ResultTruncRegTypes.back());
|
||||
|
||||
llvm::Type *Ty = ConvertTypeForMem(QTy);
|
||||
const bool RequiresCast = Info.allowsRegister() &&
|
||||
(getTargetHooks().isScalarizableAsmOperand(*this, Ty) ||
|
||||
Ty->isAggregateType());
|
||||
|
||||
ResultTruncRegTypes.push_back(Ty);
|
||||
ResultTypeRequiresCast.push_back(RequiresCast);
|
||||
|
||||
if (RequiresCast) {
|
||||
unsigned Size = getContext().getTypeSize(QTy);
|
||||
Ty = llvm::IntegerType::get(getLLVMContext(), Size);
|
||||
}
|
||||
ResultRegTypes.push_back(Ty);
|
||||
// If this output is tied to an input, and if the input is larger, then
|
||||
// we need to set the actual result type of the inline asm node to be the
|
||||
// same as the input type.
|
||||
@ -2638,11 +2644,11 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
|
||||
assert(ResultTypeRequiresCast.size() <= ResultRegDests.size());
|
||||
for (unsigned i = 0, e = RegResults.size(); i != e; ++i) {
|
||||
llvm::Value *Tmp = RegResults[i];
|
||||
llvm::Type *TruncTy = ResultTruncRegTypes[i];
|
||||
|
||||
// If the result type of the LLVM IR asm doesn't match the result type of
|
||||
// the expression, do the conversion.
|
||||
if (ResultRegTypes[i] != ResultTruncRegTypes[i]) {
|
||||
llvm::Type *TruncTy = ResultTruncRegTypes[i];
|
||||
|
||||
// Truncate the integer result to the right size, note that TruncTy can be
|
||||
// a pointer.
|
||||
@ -2672,6 +2678,11 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
|
||||
unsigned Size = getContext().getTypeSize(ResultRegQualTys[i]);
|
||||
Address A = Builder.CreateBitCast(Dest.getAddress(*this),
|
||||
ResultRegTypes[i]->getPointerTo());
|
||||
if (getTargetHooks().isScalarizableAsmOperand(*this, TruncTy)) {
|
||||
Builder.CreateStore(Tmp, A);
|
||||
continue;
|
||||
}
|
||||
|
||||
QualType Ty = getContext().getIntTypeForBitwidth(Size, /*Signed*/ false);
|
||||
if (Ty.isNull()) {
|
||||
const Expr *OutExpr = S.getOutputExpr(i);
|
||||
|
@ -186,7 +186,7 @@ CodeGenModule::CodeGenModule(ASTContext &C, const HeaderSearchOptions &HSO,
|
||||
!getModule().getSourceFileName().empty()) {
|
||||
std::string Path = getModule().getSourceFileName();
|
||||
// Check if a path substitution is needed from the MacroPrefixMap.
|
||||
for (const auto &Entry : PPO.MacroPrefixMap)
|
||||
for (const auto &Entry : LangOpts.MacroPrefixMap)
|
||||
if (Path.rfind(Entry.first, 0) != std::string::npos) {
|
||||
Path = Entry.second + Path.substr(Entry.first.size());
|
||||
break;
|
||||
|
@ -5526,6 +5526,20 @@ class AArch64TargetCodeGenInfo : public TargetCodeGenInfo {
|
||||
Fn->addFnAttr("branch-target-enforcement",
|
||||
BPI.BranchTargetEnforcement ? "true" : "false");
|
||||
}
|
||||
|
||||
bool isScalarizableAsmOperand(CodeGen::CodeGenFunction &CGF,
|
||||
llvm::Type *Ty) const override {
|
||||
if (CGF.getTarget().hasFeature("ls64")) {
|
||||
auto *ST = dyn_cast<llvm::StructType>(Ty);
|
||||
if (ST && ST->getNumElements() == 1) {
|
||||
auto *AT = dyn_cast<llvm::ArrayType>(ST->getElementType(0));
|
||||
if (AT && AT->getNumElements() == 8 &&
|
||||
AT->getElementType()->isIntegerTy(64))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return TargetCodeGenInfo::isScalarizableAsmOperand(CGF, Ty);
|
||||
}
|
||||
};
|
||||
|
||||
class WindowsAArch64TargetCodeGenInfo : public AArch64TargetCodeGenInfo {
|
||||
|
@ -148,6 +148,13 @@ class TargetCodeGenInfo {
|
||||
return Ty;
|
||||
}
|
||||
|
||||
/// Target hook to decide whether an inline asm operand can be passed
|
||||
/// by value.
|
||||
virtual bool isScalarizableAsmOperand(CodeGen::CodeGenFunction &CGF,
|
||||
llvm::Type *Ty) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Adds constraints and types for result registers.
|
||||
virtual void addReturnRegisterOutputs(
|
||||
CodeGen::CodeGenFunction &CGF, CodeGen::LValue ReturnValue,
|
||||
|
@ -52,9 +52,8 @@ using namespace clang;
|
||||
using namespace llvm::opt;
|
||||
|
||||
static void CheckPreprocessingOptions(const Driver &D, const ArgList &Args) {
|
||||
if (Arg *A = Args.getLastArg(clang::driver::options::OPT_C, options::OPT_CC,
|
||||
options::OPT_fminimize_whitespace,
|
||||
options::OPT_fno_minimize_whitespace)) {
|
||||
if (Arg *A =
|
||||
Args.getLastArg(clang::driver::options::OPT_C, options::OPT_CC)) {
|
||||
if (!Args.hasArg(options::OPT_E) && !Args.hasArg(options::OPT__SLASH_P) &&
|
||||
!Args.hasArg(options::OPT__SLASH_EP) && !D.CCCIsCPP()) {
|
||||
D.Diag(clang::diag::err_drv_argument_only_allowed_with)
|
||||
@ -2638,7 +2637,7 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
|
||||
|
||||
llvm::DenormalMode DenormalFPMath = DefaultDenormalFPMath;
|
||||
llvm::DenormalMode DenormalFP32Math = DefaultDenormalFP32Math;
|
||||
StringRef FPContract = "on";
|
||||
StringRef FPContract = "";
|
||||
bool StrictFPModel = false;
|
||||
|
||||
|
||||
@ -2663,7 +2662,7 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
|
||||
ReciprocalMath = false;
|
||||
SignedZeros = true;
|
||||
// -fno_fast_math restores default denormal and fpcontract handling
|
||||
FPContract = "on";
|
||||
FPContract = "";
|
||||
DenormalFPMath = llvm::DenormalMode::getIEEE();
|
||||
|
||||
// FIXME: The target may have picked a non-IEEE default mode here based on
|
||||
@ -2683,18 +2682,20 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
|
||||
// ffp-model= is a Driver option, it is entirely rewritten into more
|
||||
// granular options before being passed into cc1.
|
||||
// Use the gcc option in the switch below.
|
||||
if (!FPModel.empty() && !FPModel.equals(Val))
|
||||
if (!FPModel.empty() && !FPModel.equals(Val)) {
|
||||
D.Diag(clang::diag::warn_drv_overriding_flag_option)
|
||||
<< Args.MakeArgString("-ffp-model=" + FPModel)
|
||||
<< Args.MakeArgString("-ffp-model=" + Val);
|
||||
FPContract = "";
|
||||
}
|
||||
if (Val.equals("fast")) {
|
||||
optID = options::OPT_ffast_math;
|
||||
FPModel = Val;
|
||||
FPContract = Val;
|
||||
FPContract = "fast";
|
||||
} else if (Val.equals("precise")) {
|
||||
optID = options::OPT_ffp_contract;
|
||||
FPModel = Val;
|
||||
FPContract = "on";
|
||||
FPContract = "fast";
|
||||
PreciseFPModel = true;
|
||||
} else if (Val.equals("strict")) {
|
||||
StrictFPModel = true;
|
||||
@ -2780,11 +2781,9 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
|
||||
case options::OPT_ffp_contract: {
|
||||
StringRef Val = A->getValue();
|
||||
if (PreciseFPModel) {
|
||||
// When -ffp-model=precise is seen on the command line,
|
||||
// the boolean PreciseFPModel is set to true which indicates
|
||||
// "the current option is actually PreciseFPModel". The optID
|
||||
// is changed to OPT_ffp_contract and FPContract is set to "on".
|
||||
// the argument Val string is "precise": it shouldn't be checked.
|
||||
// -ffp-model=precise enables ffp-contract=fast as a side effect
|
||||
// the FPContract value has already been set to a string literal
|
||||
// and the Val string isn't a pertinent value.
|
||||
;
|
||||
} else if (Val.equals("fast") || Val.equals("on") || Val.equals("off"))
|
||||
FPContract = Val;
|
||||
@ -2882,17 +2881,18 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D,
|
||||
// -fno_fast_math restores default denormal and fpcontract handling
|
||||
DenormalFPMath = DefaultDenormalFPMath;
|
||||
DenormalFP32Math = llvm::DenormalMode::getIEEE();
|
||||
FPContract = "on";
|
||||
FPContract = "";
|
||||
break;
|
||||
}
|
||||
if (StrictFPModel) {
|
||||
// If -ffp-model=strict has been specified on command line but
|
||||
// subsequent options conflict then emit warning diagnostic.
|
||||
if (HonorINFs && HonorNaNs && !AssociativeMath && !ReciprocalMath &&
|
||||
SignedZeros && TrappingMath && RoundingFPMath &&
|
||||
DenormalFPMath == llvm::DenormalMode::getIEEE() &&
|
||||
DenormalFP32Math == llvm::DenormalMode::getIEEE() &&
|
||||
FPContract.equals("off"))
|
||||
if (HonorINFs && HonorNaNs &&
|
||||
!AssociativeMath && !ReciprocalMath &&
|
||||
SignedZeros && TrappingMath && RoundingFPMath &&
|
||||
(FPContract.equals("off") || FPContract.empty()) &&
|
||||
DenormalFPMath == llvm::DenormalMode::getIEEE() &&
|
||||
DenormalFP32Math == llvm::DenormalMode::getIEEE())
|
||||
// OK: Current Arg doesn't conflict with -ffp-model=strict
|
||||
;
|
||||
else {
|
||||
@ -6068,16 +6068,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
|
||||
options::OPT_fno_use_line_directives, false))
|
||||
CmdArgs.push_back("-fuse-line-directives");
|
||||
|
||||
// -fno-minimize-whitespace is default.
|
||||
if (Args.hasFlag(options::OPT_fminimize_whitespace,
|
||||
options::OPT_fno_minimize_whitespace, false)) {
|
||||
types::ID InputType = Inputs[0].getType();
|
||||
if (!isDerivedFromC(InputType))
|
||||
D.Diag(diag::err_drv_minws_unsupported_input_type)
|
||||
<< types::getTypeName(InputType);
|
||||
CmdArgs.push_back("-fminimize-whitespace");
|
||||
}
|
||||
|
||||
// -fms-extensions=0 is default.
|
||||
if (Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions,
|
||||
IsWindowsMSVC))
|
||||
@ -7701,8 +7691,11 @@ void OffloadBundler::ConstructJob(Compilation &C, const JobAction &JA,
|
||||
assert(CurTC == nullptr && "Expected one dependence!");
|
||||
CurTC = TC;
|
||||
});
|
||||
UB += C.addTempFile(
|
||||
C.getArgs().MakeArgString(CurTC->getInputFilename(Inputs[I])));
|
||||
} else {
|
||||
UB += CurTC->getInputFilename(Inputs[I]);
|
||||
}
|
||||
UB += CurTC->getInputFilename(Inputs[I]);
|
||||
}
|
||||
CmdArgs.push_back(TCArgs.MakeArgString(UB));
|
||||
|
||||
|
@ -588,21 +588,43 @@ void HexagonToolChain::addClangTargetOptions(const ArgList &DriverArgs,
|
||||
|
||||
void HexagonToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
|
||||
ArgStringList &CC1Args) const {
|
||||
if (DriverArgs.hasArg(options::OPT_nostdinc) ||
|
||||
DriverArgs.hasArg(options::OPT_nostdlibinc))
|
||||
if (DriverArgs.hasArg(options::OPT_nostdinc))
|
||||
return;
|
||||
|
||||
const bool IsELF = !getTriple().isMusl() && !getTriple().isOSLinux();
|
||||
const bool IsLinuxMusl = getTriple().isMusl() && getTriple().isOSLinux();
|
||||
|
||||
const Driver &D = getDriver();
|
||||
if (!D.SysRoot.empty()) {
|
||||
SmallString<128> ResourceDirInclude(D.ResourceDir);
|
||||
if (!IsELF) {
|
||||
llvm::sys::path::append(ResourceDirInclude, "include");
|
||||
if (!DriverArgs.hasArg(options::OPT_nobuiltininc) &&
|
||||
(!IsLinuxMusl || DriverArgs.hasArg(options::OPT_nostdlibinc)))
|
||||
addSystemInclude(DriverArgs, CC1Args, ResourceDirInclude);
|
||||
}
|
||||
if (DriverArgs.hasArg(options::OPT_nostdlibinc))
|
||||
return;
|
||||
|
||||
const bool HasSysRoot = !D.SysRoot.empty();
|
||||
if (HasSysRoot) {
|
||||
SmallString<128> P(D.SysRoot);
|
||||
if (getTriple().isMusl())
|
||||
if (IsLinuxMusl)
|
||||
llvm::sys::path::append(P, "usr/include");
|
||||
else
|
||||
llvm::sys::path::append(P, "include");
|
||||
|
||||
addExternCSystemInclude(DriverArgs, CC1Args, P.str());
|
||||
return;
|
||||
// LOCAL_INCLUDE_DIR
|
||||
addSystemInclude(DriverArgs, CC1Args, P + "/usr/local/include");
|
||||
// TOOL_INCLUDE_DIR
|
||||
AddMultilibIncludeArgs(DriverArgs, CC1Args);
|
||||
}
|
||||
|
||||
if (!DriverArgs.hasArg(options::OPT_nobuiltininc) && IsLinuxMusl)
|
||||
addSystemInclude(DriverArgs, CC1Args, ResourceDirInclude);
|
||||
|
||||
if (HasSysRoot)
|
||||
return;
|
||||
std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(),
|
||||
D.PrefixDirs);
|
||||
addExternCSystemInclude(DriverArgs, CC1Args, TargetDir + "/hexagon/include");
|
||||
|
@ -136,10 +136,13 @@ void tools::MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA,
|
||||
llvm_unreachable("Unsupported target architecture.");
|
||||
}
|
||||
|
||||
if (Args.hasArg(options::OPT_mwindows)) {
|
||||
Arg *SubsysArg =
|
||||
Args.getLastArg(options::OPT_mwindows, options::OPT_mconsole);
|
||||
if (SubsysArg && SubsysArg->getOption().matches(options::OPT_mwindows)) {
|
||||
CmdArgs.push_back("--subsystem");
|
||||
CmdArgs.push_back("windows");
|
||||
} else if (Args.hasArg(options::OPT_mconsole)) {
|
||||
} else if (SubsysArg &&
|
||||
SubsysArg->getOption().matches(options::OPT_mconsole)) {
|
||||
CmdArgs.push_back("--subsystem");
|
||||
CmdArgs.push_back("console");
|
||||
}
|
||||
|
@ -147,45 +147,6 @@ bool types::isAcceptedByClang(ID Id) {
|
||||
}
|
||||
}
|
||||
|
||||
bool types::isDerivedFromC(ID Id) {
|
||||
switch (Id) {
|
||||
default:
|
||||
return false;
|
||||
|
||||
case TY_PP_C:
|
||||
case TY_C:
|
||||
case TY_CL:
|
||||
case TY_CLCXX:
|
||||
case TY_PP_CUDA:
|
||||
case TY_CUDA:
|
||||
case TY_CUDA_DEVICE:
|
||||
case TY_PP_HIP:
|
||||
case TY_HIP:
|
||||
case TY_HIP_DEVICE:
|
||||
case TY_PP_ObjC:
|
||||
case TY_PP_ObjC_Alias:
|
||||
case TY_ObjC:
|
||||
case TY_PP_CXX:
|
||||
case TY_CXX:
|
||||
case TY_PP_ObjCXX:
|
||||
case TY_PP_ObjCXX_Alias:
|
||||
case TY_ObjCXX:
|
||||
case TY_RenderScript:
|
||||
case TY_PP_CHeader:
|
||||
case TY_CHeader:
|
||||
case TY_CLHeader:
|
||||
case TY_PP_ObjCHeader:
|
||||
case TY_ObjCHeader:
|
||||
case TY_PP_CXXHeader:
|
||||
case TY_CXXHeader:
|
||||
case TY_PP_ObjCXXHeader:
|
||||
case TY_ObjCXXHeader:
|
||||
case TY_CXXModule:
|
||||
case TY_PP_CXXModule:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool types::isObjC(ID Id) {
|
||||
switch (Id) {
|
||||
default:
|
||||
|
@ -347,7 +347,7 @@ AlignTokenSequence(const FormatStyle &Style, unsigned Start, unsigned End,
|
||||
if (ScopeStart > Start + 1 &&
|
||||
Changes[ScopeStart - 2].Tok->is(tok::identifier) &&
|
||||
Changes[ScopeStart - 1].Tok->is(tok::l_paren))
|
||||
return true;
|
||||
return Style.BinPackArguments;
|
||||
|
||||
// Ternary operator
|
||||
if (Changes[i].Tok->is(TT_ConditionalExpr))
|
||||
|
@ -3173,7 +3173,7 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK,
|
||||
Opts.ZVector = 0;
|
||||
Opts.setDefaultFPContractMode(LangOptions::FPM_On);
|
||||
Opts.OpenCLCPlusPlus = Opts.CPlusPlus;
|
||||
Opts.OpenCLPipe = Opts.OpenCLCPlusPlus || Opts.OpenCLVersion == 200;
|
||||
Opts.OpenCLPipes = Opts.OpenCLCPlusPlus || Opts.OpenCLVersion == 200;
|
||||
Opts.OpenCLGenericAddressSpace =
|
||||
Opts.OpenCLCPlusPlus || Opts.OpenCLVersion == 200;
|
||||
|
||||
@ -3528,6 +3528,9 @@ void CompilerInvocation::GenerateLangArgs(const LangOptions &Opts,
|
||||
GenerateArg(Args, OPT_fexperimental_relative_cxx_abi_vtables, SA);
|
||||
else
|
||||
GenerateArg(Args, OPT_fno_experimental_relative_cxx_abi_vtables, SA);
|
||||
|
||||
for (const auto &MP : Opts.MacroPrefixMap)
|
||||
GenerateArg(Args, OPT_fmacro_prefix_map_EQ, MP.first + "=" + MP.second, SA);
|
||||
}
|
||||
|
||||
bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args,
|
||||
@ -4037,6 +4040,12 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args,
|
||||
options::OPT_fno_experimental_relative_cxx_abi_vtables,
|
||||
TargetCXXABI::usesRelativeVTables(T));
|
||||
|
||||
for (const auto &A : Args.getAllArgValues(OPT_fmacro_prefix_map_EQ)) {
|
||||
auto Split = StringRef(A).split('=');
|
||||
Opts.MacroPrefixMap.insert(
|
||||
{std::string(Split.first), std::string(Split.second)});
|
||||
}
|
||||
|
||||
return Diags.getNumErrors() == NumErrorsBefore;
|
||||
}
|
||||
|
||||
@ -4109,9 +4118,6 @@ static void GeneratePreprocessorArgs(PreprocessorOptions &Opts,
|
||||
for (const auto &D : Opts.DeserializedPCHDeclsToErrorOn)
|
||||
GenerateArg(Args, OPT_error_on_deserialized_pch_decl, D, SA);
|
||||
|
||||
for (const auto &MP : Opts.MacroPrefixMap)
|
||||
GenerateArg(Args, OPT_fmacro_prefix_map_EQ, MP.first + "=" + MP.second, SA);
|
||||
|
||||
if (Opts.PrecompiledPreambleBytes != std::make_pair(0u, false))
|
||||
GenerateArg(Args, OPT_preamble_bytes_EQ,
|
||||
Twine(Opts.PrecompiledPreambleBytes.first) + "," +
|
||||
@ -4180,12 +4186,6 @@ static bool ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args,
|
||||
for (const auto *A : Args.filtered(OPT_error_on_deserialized_pch_decl))
|
||||
Opts.DeserializedPCHDeclsToErrorOn.insert(A->getValue());
|
||||
|
||||
for (const auto &A : Args.getAllArgValues(OPT_fmacro_prefix_map_EQ)) {
|
||||
auto Split = StringRef(A).split('=');
|
||||
Opts.MacroPrefixMap.insert(
|
||||
{std::string(Split.first), std::string(Split.second)});
|
||||
}
|
||||
|
||||
if (const Arg *A = Args.getLastArg(OPT_preamble_bytes_EQ)) {
|
||||
StringRef Value(A->getValue());
|
||||
size_t Comma = Value.find(',');
|
||||
|
@ -95,20 +95,14 @@ class PrintPPOutputPPCallbacks : public PPCallbacks {
|
||||
bool DumpIncludeDirectives;
|
||||
bool UseLineDirectives;
|
||||
bool IsFirstFileEntered;
|
||||
bool MinimizeWhitespace;
|
||||
|
||||
Token PrevTok;
|
||||
Token PrevPrevTok;
|
||||
|
||||
public:
|
||||
PrintPPOutputPPCallbacks(Preprocessor &pp, raw_ostream &os, bool lineMarkers,
|
||||
bool defines, bool DumpIncludeDirectives,
|
||||
bool UseLineDirectives, bool MinimizeWhitespace)
|
||||
bool UseLineDirectives)
|
||||
: PP(pp), SM(PP.getSourceManager()), ConcatInfo(PP), OS(os),
|
||||
DisableLineMarkers(lineMarkers), DumpDefines(defines),
|
||||
DumpIncludeDirectives(DumpIncludeDirectives),
|
||||
UseLineDirectives(UseLineDirectives),
|
||||
MinimizeWhitespace(MinimizeWhitespace) {
|
||||
UseLineDirectives(UseLineDirectives) {
|
||||
CurLine = 0;
|
||||
CurFilename += "<uninit>";
|
||||
EmittedTokensOnThisLine = false;
|
||||
@ -116,13 +110,8 @@ class PrintPPOutputPPCallbacks : public PPCallbacks {
|
||||
FileType = SrcMgr::C_User;
|
||||
Initialized = false;
|
||||
IsFirstFileEntered = false;
|
||||
|
||||
PrevTok.startToken();
|
||||
PrevPrevTok.startToken();
|
||||
}
|
||||
|
||||
bool isMinimizeWhitespace() const { return MinimizeWhitespace; }
|
||||
|
||||
void setEmittedTokensOnThisLine() { EmittedTokensOnThisLine = true; }
|
||||
bool hasEmittedTokensOnThisLine() const { return EmittedTokensOnThisLine; }
|
||||
|
||||
@ -131,12 +120,7 @@ class PrintPPOutputPPCallbacks : public PPCallbacks {
|
||||
return EmittedDirectiveOnThisLine;
|
||||
}
|
||||
|
||||
/// Ensure that the output stream position is at the beginning of a new line
|
||||
/// and inserts one if it does not. It is intended to ensure that directives
|
||||
/// inserted by the directives not from the input source (such as #line) are
|
||||
/// in the first column. To insert newlines that represent the input, use
|
||||
/// MoveToLine(/*...*/, /*RequireStartOfLine=*/true).
|
||||
void startNewLineIfNeeded();
|
||||
bool startNewLineIfNeeded(bool ShouldUpdateCurrentLine = true);
|
||||
|
||||
void FileChanged(SourceLocation Loc, FileChangeReason Reason,
|
||||
SrcMgr::CharacteristicKind FileType,
|
||||
@ -164,45 +148,18 @@ class PrintPPOutputPPCallbacks : public PPCallbacks {
|
||||
void PragmaAssumeNonNullBegin(SourceLocation Loc) override;
|
||||
void PragmaAssumeNonNullEnd(SourceLocation Loc) override;
|
||||
|
||||
/// Insert whitespace before emitting the next token.
|
||||
///
|
||||
/// @param Tok Next token to be emitted.
|
||||
/// @param RequireSpace Ensure at least one whitespace is emitted. Useful
|
||||
/// if non-tokens have been emitted to the stream.
|
||||
/// @param RequireSameLine Never emit newlines. Useful when semantics depend
|
||||
/// on being on the same line, such as directives.
|
||||
void HandleWhitespaceBeforeTok(const Token &Tok, bool RequireSpace,
|
||||
bool RequireSameLine);
|
||||
bool HandleFirstTokOnLine(Token &Tok);
|
||||
|
||||
/// Move to the line of the provided source location. This will
|
||||
/// return true if a newline was inserted or if
|
||||
/// the requested location is the first token on the first line.
|
||||
/// In these cases the next output will be the first column on the line and
|
||||
/// make it possible to insert indention. The newline was inserted
|
||||
/// implicitly when at the beginning of the file.
|
||||
///
|
||||
/// @param Tok Token where to move to.
|
||||
/// @param RequiresStartOfLine Whether the next line depends on being in the
|
||||
/// first column, such as a directive.
|
||||
///
|
||||
/// @return Whether column adjustments are necessary.
|
||||
bool MoveToLine(const Token &Tok, bool RequireStartOfLine) {
|
||||
PresumedLoc PLoc = SM.getPresumedLoc(Tok.getLocation());
|
||||
if (PLoc.isInvalid())
|
||||
return false;
|
||||
bool IsFirstInFile = Tok.isAtStartOfLine() && PLoc.getLine() == 1;
|
||||
return MoveToLine(PLoc.getLine(), RequireStartOfLine) || IsFirstInFile;
|
||||
}
|
||||
|
||||
/// Move to the line of the provided source location. Returns true if a new
|
||||
/// line was inserted.
|
||||
bool MoveToLine(SourceLocation Loc, bool RequireStartOfLine) {
|
||||
/// return true if the output stream required adjustment or if
|
||||
/// the requested location is on the first line.
|
||||
bool MoveToLine(SourceLocation Loc) {
|
||||
PresumedLoc PLoc = SM.getPresumedLoc(Loc);
|
||||
if (PLoc.isInvalid())
|
||||
return false;
|
||||
return MoveToLine(PLoc.getLine(), RequireStartOfLine);
|
||||
return MoveToLine(PLoc.getLine()) || (PLoc.getLine() == 1);
|
||||
}
|
||||
bool MoveToLine(unsigned LineNo, bool RequireStartOfLine);
|
||||
bool MoveToLine(unsigned LineNo);
|
||||
|
||||
bool AvoidConcat(const Token &PrevPrevTok, const Token &PrevTok,
|
||||
const Token &Tok) {
|
||||
@ -230,7 +187,7 @@ class PrintPPOutputPPCallbacks : public PPCallbacks {
|
||||
void PrintPPOutputPPCallbacks::WriteLineInfo(unsigned LineNo,
|
||||
const char *Extra,
|
||||
unsigned ExtraLen) {
|
||||
startNewLineIfNeeded();
|
||||
startNewLineIfNeeded(/*ShouldUpdateCurrentLine=*/false);
|
||||
|
||||
// Emit #line directives or GNU line markers depending on what mode we're in.
|
||||
if (UseLineDirectives) {
|
||||
@ -257,57 +214,43 @@ void PrintPPOutputPPCallbacks::WriteLineInfo(unsigned LineNo,
|
||||
/// object. We can do this by emitting some number of \n's, or be emitting a
|
||||
/// #line directive. This returns false if already at the specified line, true
|
||||
/// if some newlines were emitted.
|
||||
bool PrintPPOutputPPCallbacks::MoveToLine(unsigned LineNo,
|
||||
bool RequireStartOfLine) {
|
||||
// If it is required to start a new line or finish the current, insert
|
||||
// vertical whitespace now and take it into account when moving to the
|
||||
// expected line.
|
||||
bool StartedNewLine = false;
|
||||
if ((RequireStartOfLine && EmittedTokensOnThisLine) ||
|
||||
EmittedDirectiveOnThisLine) {
|
||||
OS << '\n';
|
||||
StartedNewLine = true;
|
||||
CurLine += 1;
|
||||
EmittedTokensOnThisLine = false;
|
||||
EmittedDirectiveOnThisLine = false;
|
||||
}
|
||||
|
||||
bool PrintPPOutputPPCallbacks::MoveToLine(unsigned LineNo) {
|
||||
// If this line is "close enough" to the original line, just print newlines,
|
||||
// otherwise print a #line directive.
|
||||
if (CurLine == LineNo) {
|
||||
// Nothing to do if we are already on the correct line.
|
||||
} else if (!StartedNewLine && (!MinimizeWhitespace || !DisableLineMarkers) &&
|
||||
LineNo - CurLine == 1) {
|
||||
// Printing a single line has priority over printing a #line directive, even
|
||||
// when minimizing whitespace which otherwise would print #line directives
|
||||
// for every single line.
|
||||
OS << '\n';
|
||||
StartedNewLine = true;
|
||||
} else if (!MinimizeWhitespace && LineNo - CurLine <= 8) {
|
||||
const char *NewLines = "\n\n\n\n\n\n\n\n";
|
||||
OS.write(NewLines, LineNo - CurLine);
|
||||
StartedNewLine = true;
|
||||
if (LineNo-CurLine <= 8) {
|
||||
if (LineNo-CurLine == 1)
|
||||
OS << '\n';
|
||||
else if (LineNo == CurLine)
|
||||
return false; // Spelling line moved, but expansion line didn't.
|
||||
else {
|
||||
const char *NewLines = "\n\n\n\n\n\n\n\n";
|
||||
OS.write(NewLines, LineNo-CurLine);
|
||||
}
|
||||
} else if (!DisableLineMarkers) {
|
||||
// Emit a #line or line marker.
|
||||
WriteLineInfo(LineNo, nullptr, 0);
|
||||
StartedNewLine = true;
|
||||
}
|
||||
|
||||
if (StartedNewLine) {
|
||||
EmittedTokensOnThisLine = false;
|
||||
EmittedDirectiveOnThisLine = false;
|
||||
} else {
|
||||
// Okay, we're in -P mode, which turns off line markers. However, we still
|
||||
// need to emit a newline between tokens on different lines.
|
||||
startNewLineIfNeeded(/*ShouldUpdateCurrentLine=*/false);
|
||||
}
|
||||
|
||||
CurLine = LineNo;
|
||||
return StartedNewLine;
|
||||
return true;
|
||||
}
|
||||
|
||||
void PrintPPOutputPPCallbacks::startNewLineIfNeeded() {
|
||||
bool
|
||||
PrintPPOutputPPCallbacks::startNewLineIfNeeded(bool ShouldUpdateCurrentLine) {
|
||||
if (EmittedTokensOnThisLine || EmittedDirectiveOnThisLine) {
|
||||
OS << '\n';
|
||||
EmittedTokensOnThisLine = false;
|
||||
EmittedDirectiveOnThisLine = false;
|
||||
if (ShouldUpdateCurrentLine)
|
||||
++CurLine;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// FileChanged - Whenever the preprocessor enters or exits a #include file
|
||||
@ -330,7 +273,7 @@ void PrintPPOutputPPCallbacks::FileChanged(SourceLocation Loc,
|
||||
if (Reason == PPCallbacks::EnterFile) {
|
||||
SourceLocation IncludeLoc = UserLoc.getIncludeLoc();
|
||||
if (IncludeLoc.isValid())
|
||||
MoveToLine(IncludeLoc, /*RequireStartOfLine=*/false);
|
||||
MoveToLine(IncludeLoc);
|
||||
} else if (Reason == PPCallbacks::SystemHeaderPragma) {
|
||||
// GCC emits the # directive for this directive on the line AFTER the
|
||||
// directive and emits a bunch of spaces that aren't needed. This is because
|
||||
@ -347,8 +290,7 @@ void PrintPPOutputPPCallbacks::FileChanged(SourceLocation Loc,
|
||||
FileType = NewFileType;
|
||||
|
||||
if (DisableLineMarkers) {
|
||||
if (!MinimizeWhitespace)
|
||||
startNewLineIfNeeded();
|
||||
startNewLineIfNeeded(/*ShouldUpdateCurrentLine=*/false);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -394,13 +336,15 @@ void PrintPPOutputPPCallbacks::InclusionDirective(
|
||||
// In -dI mode, dump #include directives prior to dumping their content or
|
||||
// interpretation.
|
||||
if (DumpIncludeDirectives) {
|
||||
MoveToLine(HashLoc, /*RequireStartOfLine=*/true);
|
||||
startNewLineIfNeeded();
|
||||
MoveToLine(HashLoc);
|
||||
const std::string TokenText = PP.getSpelling(IncludeTok);
|
||||
assert(!TokenText.empty());
|
||||
OS << "#" << TokenText << " "
|
||||
<< (IsAngled ? '<' : '"') << FileName << (IsAngled ? '>' : '"')
|
||||
<< " /* clang -E -dI */";
|
||||
setEmittedDirectiveOnThisLine();
|
||||
startNewLineIfNeeded();
|
||||
}
|
||||
|
||||
// When preprocessing, turn implicit imports into module import pragmas.
|
||||
@ -409,13 +353,17 @@ void PrintPPOutputPPCallbacks::InclusionDirective(
|
||||
case tok::pp_include:
|
||||
case tok::pp_import:
|
||||
case tok::pp_include_next:
|
||||
MoveToLine(HashLoc, /*RequireStartOfLine=*/true);
|
||||
startNewLineIfNeeded();
|
||||
MoveToLine(HashLoc);
|
||||
OS << "#pragma clang module import " << Imported->getFullModuleName(true)
|
||||
<< " /* clang -E: implicit import for "
|
||||
<< "#" << PP.getSpelling(IncludeTok) << " "
|
||||
<< (IsAngled ? '<' : '"') << FileName << (IsAngled ? '>' : '"')
|
||||
<< " */";
|
||||
setEmittedDirectiveOnThisLine();
|
||||
// Since we want a newline after the pragma, but not a #<line>, start a
|
||||
// new line immediately.
|
||||
EmittedTokensOnThisLine = true;
|
||||
startNewLineIfNeeded();
|
||||
break;
|
||||
|
||||
case tok::pp___include_macros:
|
||||
@ -450,11 +398,11 @@ void PrintPPOutputPPCallbacks::EndModule(const Module *M) {
|
||||
/// Ident - Handle #ident directives when read by the preprocessor.
|
||||
///
|
||||
void PrintPPOutputPPCallbacks::Ident(SourceLocation Loc, StringRef S) {
|
||||
MoveToLine(Loc, /*RequireStartOfLine=*/true);
|
||||
MoveToLine(Loc);
|
||||
|
||||
OS.write("#ident ", strlen("#ident "));
|
||||
OS.write(S.begin(), S.size());
|
||||
setEmittedTokensOnThisLine();
|
||||
EmittedTokensOnThisLine = true;
|
||||
}
|
||||
|
||||
/// MacroDefined - This hook is called whenever a macro definition is seen.
|
||||
@ -466,7 +414,7 @@ void PrintPPOutputPPCallbacks::MacroDefined(const Token &MacroNameTok,
|
||||
// Ignore __FILE__ etc.
|
||||
MI->isBuiltinMacro()) return;
|
||||
|
||||
MoveToLine(MI->getDefinitionLoc(), /*RequireStartOfLine=*/true);
|
||||
MoveToLine(MI->getDefinitionLoc());
|
||||
PrintMacroDefinition(*MacroNameTok.getIdentifierInfo(), *MI, PP, OS);
|
||||
setEmittedDirectiveOnThisLine();
|
||||
}
|
||||
@ -477,7 +425,7 @@ void PrintPPOutputPPCallbacks::MacroUndefined(const Token &MacroNameTok,
|
||||
// Only print out macro definitions in -dD mode.
|
||||
if (!DumpDefines) return;
|
||||
|
||||
MoveToLine(MacroNameTok.getLocation(), /*RequireStartOfLine=*/true);
|
||||
MoveToLine(MacroNameTok.getLocation());
|
||||
OS << "#undef " << MacroNameTok.getIdentifierInfo()->getName();
|
||||
setEmittedDirectiveOnThisLine();
|
||||
}
|
||||
@ -498,7 +446,8 @@ void PrintPPOutputPPCallbacks::PragmaMessage(SourceLocation Loc,
|
||||
StringRef Namespace,
|
||||
PragmaMessageKind Kind,
|
||||
StringRef Str) {
|
||||
MoveToLine(Loc, /*RequireStartOfLine=*/true);
|
||||
startNewLineIfNeeded();
|
||||
MoveToLine(Loc);
|
||||
OS << "#pragma ";
|
||||
if (!Namespace.empty())
|
||||
OS << Namespace << ' ';
|
||||
@ -523,7 +472,8 @@ void PrintPPOutputPPCallbacks::PragmaMessage(SourceLocation Loc,
|
||||
|
||||
void PrintPPOutputPPCallbacks::PragmaDebug(SourceLocation Loc,
|
||||
StringRef DebugType) {
|
||||
MoveToLine(Loc, /*RequireStartOfLine=*/true);
|
||||
startNewLineIfNeeded();
|
||||
MoveToLine(Loc);
|
||||
|
||||
OS << "#pragma clang __debug ";
|
||||
OS << DebugType;
|
||||
@ -533,14 +483,16 @@ void PrintPPOutputPPCallbacks::PragmaDebug(SourceLocation Loc,
|
||||
|
||||
void PrintPPOutputPPCallbacks::
|
||||
PragmaDiagnosticPush(SourceLocation Loc, StringRef Namespace) {
|
||||
MoveToLine(Loc, /*RequireStartOfLine=*/true);
|
||||
startNewLineIfNeeded();
|
||||
MoveToLine(Loc);
|
||||
OS << "#pragma " << Namespace << " diagnostic push";
|
||||
setEmittedDirectiveOnThisLine();
|
||||
}
|
||||
|
||||
void PrintPPOutputPPCallbacks::
|
||||
PragmaDiagnosticPop(SourceLocation Loc, StringRef Namespace) {
|
||||
MoveToLine(Loc, /*RequireStartOfLine=*/true);
|
||||
startNewLineIfNeeded();
|
||||
MoveToLine(Loc);
|
||||
OS << "#pragma " << Namespace << " diagnostic pop";
|
||||
setEmittedDirectiveOnThisLine();
|
||||
}
|
||||
@ -549,7 +501,8 @@ void PrintPPOutputPPCallbacks::PragmaDiagnostic(SourceLocation Loc,
|
||||
StringRef Namespace,
|
||||
diag::Severity Map,
|
||||
StringRef Str) {
|
||||
MoveToLine(Loc, /*RequireStartOfLine=*/true);
|
||||
startNewLineIfNeeded();
|
||||
MoveToLine(Loc);
|
||||
OS << "#pragma " << Namespace << " diagnostic ";
|
||||
switch (Map) {
|
||||
case diag::Severity::Remark:
|
||||
@ -575,7 +528,8 @@ void PrintPPOutputPPCallbacks::PragmaDiagnostic(SourceLocation Loc,
|
||||
void PrintPPOutputPPCallbacks::PragmaWarning(SourceLocation Loc,
|
||||
StringRef WarningSpec,
|
||||
ArrayRef<int> Ids) {
|
||||
MoveToLine(Loc, /*RequireStartOfLine=*/true);
|
||||
startNewLineIfNeeded();
|
||||
MoveToLine(Loc);
|
||||
OS << "#pragma warning(" << WarningSpec << ':';
|
||||
for (ArrayRef<int>::iterator I = Ids.begin(), E = Ids.end(); I != E; ++I)
|
||||
OS << ' ' << *I;
|
||||
@ -585,7 +539,8 @@ void PrintPPOutputPPCallbacks::PragmaWarning(SourceLocation Loc,
|
||||
|
||||
void PrintPPOutputPPCallbacks::PragmaWarningPush(SourceLocation Loc,
|
||||
int Level) {
|
||||
MoveToLine(Loc, /*RequireStartOfLine=*/true);
|
||||
startNewLineIfNeeded();
|
||||
MoveToLine(Loc);
|
||||
OS << "#pragma warning(push";
|
||||
if (Level >= 0)
|
||||
OS << ", " << Level;
|
||||
@ -594,14 +549,16 @@ void PrintPPOutputPPCallbacks::PragmaWarningPush(SourceLocation Loc,
|
||||
}
|
||||
|
||||
void PrintPPOutputPPCallbacks::PragmaWarningPop(SourceLocation Loc) {
|
||||
MoveToLine(Loc, /*RequireStartOfLine=*/true);
|
||||
startNewLineIfNeeded();
|
||||
MoveToLine(Loc);
|
||||
OS << "#pragma warning(pop)";
|
||||
setEmittedDirectiveOnThisLine();
|
||||
}
|
||||
|
||||
void PrintPPOutputPPCallbacks::PragmaExecCharsetPush(SourceLocation Loc,
|
||||
StringRef Str) {
|
||||
MoveToLine(Loc, /*RequireStartOfLine=*/true);
|
||||
startNewLineIfNeeded();
|
||||
MoveToLine(Loc);
|
||||
OS << "#pragma character_execution_set(push";
|
||||
if (!Str.empty())
|
||||
OS << ", " << Str;
|
||||
@ -610,80 +567,64 @@ void PrintPPOutputPPCallbacks::PragmaExecCharsetPush(SourceLocation Loc,
|
||||
}
|
||||
|
||||
void PrintPPOutputPPCallbacks::PragmaExecCharsetPop(SourceLocation Loc) {
|
||||
MoveToLine(Loc, /*RequireStartOfLine=*/true);
|
||||
startNewLineIfNeeded();
|
||||
MoveToLine(Loc);
|
||||
OS << "#pragma character_execution_set(pop)";
|
||||
setEmittedDirectiveOnThisLine();
|
||||
}
|
||||
|
||||
void PrintPPOutputPPCallbacks::
|
||||
PragmaAssumeNonNullBegin(SourceLocation Loc) {
|
||||
MoveToLine(Loc, /*RequireStartOfLine=*/true);
|
||||
startNewLineIfNeeded();
|
||||
MoveToLine(Loc);
|
||||
OS << "#pragma clang assume_nonnull begin";
|
||||
setEmittedDirectiveOnThisLine();
|
||||
}
|
||||
|
||||
void PrintPPOutputPPCallbacks::
|
||||
PragmaAssumeNonNullEnd(SourceLocation Loc) {
|
||||
MoveToLine(Loc, /*RequireStartOfLine=*/true);
|
||||
startNewLineIfNeeded();
|
||||
MoveToLine(Loc);
|
||||
OS << "#pragma clang assume_nonnull end";
|
||||
setEmittedDirectiveOnThisLine();
|
||||
}
|
||||
|
||||
void PrintPPOutputPPCallbacks::HandleWhitespaceBeforeTok(const Token &Tok,
|
||||
bool RequireSpace,
|
||||
bool RequireSameLine) {
|
||||
// These tokens are not expanded to anything and don't need whitespace before
|
||||
// them.
|
||||
if (Tok.is(tok::eof) ||
|
||||
(Tok.isAnnotation() && !Tok.is(tok::annot_header_unit) &&
|
||||
!Tok.is(tok::annot_module_begin) && !Tok.is(tok::annot_module_end)))
|
||||
return;
|
||||
/// HandleFirstTokOnLine - When emitting a preprocessed file in -E mode, this
|
||||
/// is called for the first token on each new line. If this really is the start
|
||||
/// of a new logical line, handle it and return true, otherwise return false.
|
||||
/// This may not be the start of a logical line because the "start of line"
|
||||
/// marker is set for spelling lines, not expansion ones.
|
||||
bool PrintPPOutputPPCallbacks::HandleFirstTokOnLine(Token &Tok) {
|
||||
// Figure out what line we went to and insert the appropriate number of
|
||||
// newline characters.
|
||||
if (!MoveToLine(Tok.getLocation()))
|
||||
return false;
|
||||
|
||||
if (!RequireSameLine && MoveToLine(Tok, /*RequireStartOfLine=*/false)) {
|
||||
if (MinimizeWhitespace) {
|
||||
// Avoid interpreting hash as a directive under -fpreprocessed.
|
||||
if (Tok.is(tok::hash))
|
||||
OS << ' ';
|
||||
} else {
|
||||
// Print out space characters so that the first token on a line is
|
||||
// indented for easy reading.
|
||||
unsigned ColNo = SM.getExpansionColumnNumber(Tok.getLocation());
|
||||
// Print out space characters so that the first token on a line is
|
||||
// indented for easy reading.
|
||||
unsigned ColNo = SM.getExpansionColumnNumber(Tok.getLocation());
|
||||
|
||||
// The first token on a line can have a column number of 1, yet still
|
||||
// expect leading white space, if a macro expansion in column 1 starts
|
||||
// with an empty macro argument, or an empty nested macro expansion. In
|
||||
// this case, move the token to column 2.
|
||||
if (ColNo == 1 && Tok.hasLeadingSpace())
|
||||
ColNo = 2;
|
||||
// The first token on a line can have a column number of 1, yet still expect
|
||||
// leading white space, if a macro expansion in column 1 starts with an empty
|
||||
// macro argument, or an empty nested macro expansion. In this case, move the
|
||||
// token to column 2.
|
||||
if (ColNo == 1 && Tok.hasLeadingSpace())
|
||||
ColNo = 2;
|
||||
|
||||
// This hack prevents stuff like:
|
||||
// #define HASH #
|
||||
// HASH define foo bar
|
||||
// From having the # character end up at column 1, which makes it so it
|
||||
// is not handled as a #define next time through the preprocessor if in
|
||||
// -fpreprocessed mode.
|
||||
if (ColNo <= 1 && Tok.is(tok::hash))
|
||||
OS << ' ';
|
||||
// This hack prevents stuff like:
|
||||
// #define HASH #
|
||||
// HASH define foo bar
|
||||
// From having the # character end up at column 1, which makes it so it
|
||||
// is not handled as a #define next time through the preprocessor if in
|
||||
// -fpreprocessed mode.
|
||||
if (ColNo <= 1 && Tok.is(tok::hash))
|
||||
OS << ' ';
|
||||
|
||||
// Otherwise, indent the appropriate number of spaces.
|
||||
for (; ColNo > 1; --ColNo)
|
||||
OS << ' ';
|
||||
}
|
||||
} else {
|
||||
// Insert whitespace between the previous and next token if either
|
||||
// - The caller requires it
|
||||
// - The input had whitespace between them and we are not in
|
||||
// whitespace-minimization mode
|
||||
// - The whitespace is necessary to keep the tokens apart and there is not
|
||||
// already a newline between them
|
||||
if (RequireSpace || (!MinimizeWhitespace && Tok.hasLeadingSpace()) ||
|
||||
((EmittedTokensOnThisLine || EmittedTokensOnThisLine) &&
|
||||
AvoidConcat(PrevPrevTok, PrevTok, Tok)))
|
||||
OS << ' ';
|
||||
}
|
||||
// Otherwise, indent the appropriate number of spaces.
|
||||
for (; ColNo > 1; --ColNo)
|
||||
OS << ' ';
|
||||
|
||||
PrevPrevTok = PrevTok;
|
||||
PrevTok = Tok;
|
||||
return true;
|
||||
}
|
||||
|
||||
void PrintPPOutputPPCallbacks::HandleNewlinesInToken(const char *TokStr,
|
||||
@ -727,9 +668,9 @@ struct UnknownPragmaHandler : public PragmaHandler {
|
||||
Token &PragmaTok) override {
|
||||
// Figure out what line we went to and insert the appropriate number of
|
||||
// newline characters.
|
||||
Callbacks->MoveToLine(PragmaTok.getLocation(), /*RequireStartOfLine=*/true);
|
||||
Callbacks->startNewLineIfNeeded();
|
||||
Callbacks->MoveToLine(PragmaTok.getLocation());
|
||||
Callbacks->OS.write(Prefix, strlen(Prefix));
|
||||
Callbacks->setEmittedTokensOnThisLine();
|
||||
|
||||
if (ShouldExpandTokens) {
|
||||
// The first token does not have expanded macros. Expand them, if
|
||||
@ -741,16 +682,21 @@ struct UnknownPragmaHandler : public PragmaHandler {
|
||||
/*IsReinject=*/false);
|
||||
PP.Lex(PragmaTok);
|
||||
}
|
||||
Token PrevToken;
|
||||
Token PrevPrevToken;
|
||||
PrevToken.startToken();
|
||||
PrevPrevToken.startToken();
|
||||
|
||||
// Read and print all of the pragma tokens.
|
||||
bool IsFirst = true;
|
||||
while (PragmaTok.isNot(tok::eod)) {
|
||||
Callbacks->HandleWhitespaceBeforeTok(PragmaTok, /*RequireSpace=*/IsFirst,
|
||||
/*RequireSameLine=*/true);
|
||||
IsFirst = false;
|
||||
if (PragmaTok.hasLeadingSpace() ||
|
||||
Callbacks->AvoidConcat(PrevPrevToken, PrevToken, PragmaTok))
|
||||
Callbacks->OS << ' ';
|
||||
std::string TokSpell = PP.getSpelling(PragmaTok);
|
||||
Callbacks->OS.write(&TokSpell[0], TokSpell.size());
|
||||
Callbacks->setEmittedTokensOnThisLine();
|
||||
|
||||
PrevPrevToken = PrevToken;
|
||||
PrevToken = PragmaTok;
|
||||
|
||||
if (ShouldExpandTokens)
|
||||
PP.Lex(PragmaTok);
|
||||
@ -769,41 +715,44 @@ static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok,
|
||||
bool DropComments = PP.getLangOpts().TraditionalCPP &&
|
||||
!PP.getCommentRetentionState();
|
||||
|
||||
bool IsStartOfLine = false;
|
||||
char Buffer[256];
|
||||
Token PrevPrevTok, PrevTok;
|
||||
PrevPrevTok.startToken();
|
||||
PrevTok.startToken();
|
||||
while (1) {
|
||||
// Two lines joined with line continuation ('\' as last character on the
|
||||
// line) must be emitted as one line even though Tok.getLine() returns two
|
||||
// different values. In this situation Tok.isAtStartOfLine() is false even
|
||||
// though it may be the first token on the lexical line. When
|
||||
// dropping/skipping a token that is at the start of a line, propagate the
|
||||
// start-of-line-ness to the next token to not append it to the previous
|
||||
// line.
|
||||
IsStartOfLine = IsStartOfLine || Tok.isAtStartOfLine();
|
||||
if (Callbacks->hasEmittedDirectiveOnThisLine()) {
|
||||
Callbacks->startNewLineIfNeeded();
|
||||
Callbacks->MoveToLine(Tok.getLocation());
|
||||
}
|
||||
|
||||
Callbacks->HandleWhitespaceBeforeTok(Tok, /*RequireSpace=*/false,
|
||||
/*RequireSameLine=*/!IsStartOfLine);
|
||||
// If this token is at the start of a line, emit newlines if needed.
|
||||
if (Tok.isAtStartOfLine() && Callbacks->HandleFirstTokOnLine(Tok)) {
|
||||
// done.
|
||||
} else if (Tok.hasLeadingSpace() ||
|
||||
// If we haven't emitted a token on this line yet, PrevTok isn't
|
||||
// useful to look at and no concatenation could happen anyway.
|
||||
(Callbacks->hasEmittedTokensOnThisLine() &&
|
||||
// Don't print "-" next to "-", it would form "--".
|
||||
Callbacks->AvoidConcat(PrevPrevTok, PrevTok, Tok))) {
|
||||
OS << ' ';
|
||||
}
|
||||
|
||||
if (DropComments && Tok.is(tok::comment)) {
|
||||
// Skip comments. Normally the preprocessor does not generate
|
||||
// tok::comment nodes at all when not keeping comments, but under
|
||||
// -traditional-cpp the lexer keeps /all/ whitespace, including comments.
|
||||
PP.Lex(Tok);
|
||||
continue;
|
||||
SourceLocation StartLoc = Tok.getLocation();
|
||||
Callbacks->MoveToLine(StartLoc.getLocWithOffset(Tok.getLength()));
|
||||
} else if (Tok.is(tok::eod)) {
|
||||
// Don't print end of directive tokens, since they are typically newlines
|
||||
// that mess up our line tracking. These come from unknown pre-processor
|
||||
// directives or hash-prefixed comments in standalone assembly files.
|
||||
PP.Lex(Tok);
|
||||
// FIXME: The token on the next line after #include should have
|
||||
// Tok.isAtStartOfLine() set.
|
||||
IsStartOfLine = true;
|
||||
continue;
|
||||
} else if (Tok.is(tok::annot_module_include)) {
|
||||
// PrintPPOutputPPCallbacks::InclusionDirective handles producing
|
||||
// appropriate output here. Ignore this token entirely.
|
||||
PP.Lex(Tok);
|
||||
IsStartOfLine = true;
|
||||
continue;
|
||||
} else if (Tok.is(tok::annot_module_begin)) {
|
||||
// FIXME: We retrieve this token after the FileChanged callback, and
|
||||
@ -815,13 +764,11 @@ static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok,
|
||||
Callbacks->BeginModule(
|
||||
reinterpret_cast<Module *>(Tok.getAnnotationValue()));
|
||||
PP.Lex(Tok);
|
||||
IsStartOfLine = true;
|
||||
continue;
|
||||
} else if (Tok.is(tok::annot_module_end)) {
|
||||
Callbacks->EndModule(
|
||||
reinterpret_cast<Module *>(Tok.getAnnotationValue()));
|
||||
PP.Lex(Tok);
|
||||
IsStartOfLine = true;
|
||||
continue;
|
||||
} else if (Tok.is(tok::annot_header_unit)) {
|
||||
// This is a header-name that has been (effectively) converted into a
|
||||
@ -849,17 +796,8 @@ static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok,
|
||||
|
||||
// Tokens that can contain embedded newlines need to adjust our current
|
||||
// line number.
|
||||
// FIXME: The token may end with a newline in which case
|
||||
// setEmittedDirectiveOnThisLine/setEmittedTokensOnThisLine afterwards is
|
||||
// wrong.
|
||||
if (Tok.getKind() == tok::comment || Tok.getKind() == tok::unknown)
|
||||
Callbacks->HandleNewlinesInToken(TokPtr, Len);
|
||||
if (Tok.is(tok::comment) && Len >= 2 && TokPtr[0] == '/' &&
|
||||
TokPtr[1] == '/') {
|
||||
// It's a line comment;
|
||||
// Ensure that we don't concatenate anything behind it.
|
||||
Callbacks->setEmittedDirectiveOnThisLine();
|
||||
}
|
||||
} else {
|
||||
std::string S = PP.getSpelling(Tok);
|
||||
OS.write(S.data(), S.size());
|
||||
@ -868,17 +806,13 @@ static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok,
|
||||
// line number.
|
||||
if (Tok.getKind() == tok::comment || Tok.getKind() == tok::unknown)
|
||||
Callbacks->HandleNewlinesInToken(S.data(), S.size());
|
||||
if (Tok.is(tok::comment) && S.size() >= 2 && S[0] == '/' && S[1] == '/') {
|
||||
// It's a line comment;
|
||||
// Ensure that we don't concatenate anything behind it.
|
||||
Callbacks->setEmittedDirectiveOnThisLine();
|
||||
}
|
||||
}
|
||||
Callbacks->setEmittedTokensOnThisLine();
|
||||
IsStartOfLine = false;
|
||||
|
||||
if (Tok.is(tok::eof)) break;
|
||||
|
||||
PrevPrevTok = PrevTok;
|
||||
PrevTok = Tok;
|
||||
PP.Lex(Tok);
|
||||
}
|
||||
}
|
||||
@ -936,8 +870,7 @@ void clang::DoPrintPreprocessedInput(Preprocessor &PP, raw_ostream *OS,
|
||||
|
||||
PrintPPOutputPPCallbacks *Callbacks = new PrintPPOutputPPCallbacks(
|
||||
PP, *OS, !Opts.ShowLineMarkers, Opts.ShowMacros,
|
||||
Opts.ShowIncludeDirectives, Opts.UseLineDirectives,
|
||||
Opts.MinimizeWhitespace);
|
||||
Opts.ShowIncludeDirectives, Opts.UseLineDirectives);
|
||||
|
||||
// Expand macros in pragmas with -fms-extensions. The assumption is that
|
||||
// the majority of pragmas in such a file will be Microsoft pragmas.
|
||||
|
@ -574,6 +574,9 @@ void _WriteStatusReg(int, __int64);
|
||||
unsigned short __cdecl _byteswap_ushort(unsigned short val);
|
||||
unsigned long __cdecl _byteswap_ulong (unsigned long val);
|
||||
unsigned __int64 __cdecl _byteswap_uint64(unsigned __int64 val);
|
||||
|
||||
__int64 __mulh(__int64 __a, __int64 __b);
|
||||
unsigned __int64 __umulh(unsigned __int64 __a, unsigned __int64 __b);
|
||||
#endif
|
||||
|
||||
/*----------------------------------------------------------------------------*\
|
||||
|
@ -2811,11 +2811,11 @@ bool Lexer::LexEndOfFile(Token &Result, const char *CurPtr) {
|
||||
ConditionalStack.pop_back();
|
||||
}
|
||||
|
||||
SourceLocation EndLoc = getSourceLocation(BufferEnd);
|
||||
// C99 5.1.1.2p2: If the file is non-empty and didn't end in a newline, issue
|
||||
// a pedwarn.
|
||||
if (CurPtr != BufferStart && (CurPtr[-1] != '\n' && CurPtr[-1] != '\r')) {
|
||||
DiagnosticsEngine &Diags = PP->getDiagnostics();
|
||||
SourceLocation EndLoc = getSourceLocation(BufferEnd);
|
||||
unsigned DiagID;
|
||||
|
||||
if (LangOpts.CPlusPlus11) {
|
||||
@ -2838,7 +2838,7 @@ bool Lexer::LexEndOfFile(Token &Result, const char *CurPtr) {
|
||||
BufferPtr = CurPtr;
|
||||
|
||||
// Finally, let the preprocessor handle this.
|
||||
return PP->HandleEndOfFile(Result, isPragmaLexer());
|
||||
return PP->HandleEndOfFile(Result, EndLoc, isPragmaLexer());
|
||||
}
|
||||
|
||||
/// isNextPPTokenLParen - Return 1 if the next unexpanded token lexed from
|
||||
|
@ -2022,6 +2022,10 @@ Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport(
|
||||
IsFrameworkFound, IsImportDecl, IsMapped, LookupFrom, LookupFromFile,
|
||||
LookupFilename, RelativePath, SearchPath, SuggestedModule, isAngled);
|
||||
|
||||
// Record the header's filename for later use.
|
||||
if (File)
|
||||
CurLexer->addInclude(OriginalFilename, File->getFileEntry(), FilenameLoc);
|
||||
|
||||
if (usingPCHWithThroughHeader() && SkippingUntilPCHThroughHeader) {
|
||||
if (File && isPCHThroughHeader(&File->getFileEntry()))
|
||||
SkippingUntilPCHThroughHeader = false;
|
||||
|
@ -12,6 +12,7 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Basic/FileManager.h"
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
#include "clang/Lex/HeaderSearch.h"
|
||||
#include "clang/Lex/LexDiagnostic.h"
|
||||
@ -22,6 +23,7 @@
|
||||
#include "llvm/Support/FileSystem.h"
|
||||
#include "llvm/Support/MemoryBufferRef.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
|
||||
using namespace clang;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -299,10 +301,46 @@ void Preprocessor::diagnoseMissingHeaderInUmbrellaDir(const Module &Mod) {
|
||||
}
|
||||
}
|
||||
|
||||
void Preprocessor::ResolvePragmaIncludeInstead(
|
||||
const SourceLocation Location) const {
|
||||
assert(Location.isValid());
|
||||
if (CurLexer == nullptr)
|
||||
return;
|
||||
|
||||
if (SourceMgr.isInSystemHeader(Location))
|
||||
return;
|
||||
|
||||
for (const auto &Include : CurLexer->getIncludeHistory()) {
|
||||
StringRef Filename = Include.getKey();
|
||||
const PreprocessorLexer::IncludeInfo &Info = Include.getValue();
|
||||
ArrayRef<SmallString<32>> Aliases =
|
||||
HeaderInfo.getFileInfo(Info.File).Aliases.getArrayRef();
|
||||
|
||||
if (Aliases.empty())
|
||||
continue;
|
||||
|
||||
switch (Aliases.size()) {
|
||||
case 1:
|
||||
Diag(Info.Location, diag::err_pragma_include_instead_system_reserved)
|
||||
<< Filename << 0 << Aliases[0];
|
||||
continue;
|
||||
case 2:
|
||||
Diag(Info.Location, diag::err_pragma_include_instead_system_reserved)
|
||||
<< Filename << 1 << Aliases[0] << Aliases[1];
|
||||
continue;
|
||||
default: {
|
||||
Diag(Info.Location, diag::err_pragma_include_instead_system_reserved)
|
||||
<< Filename << 2 << ("{'" + llvm::join(Aliases, "', '") + "'}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// HandleEndOfFile - This callback is invoked when the lexer hits the end of
|
||||
/// the current file. This either returns the EOF token or pops a level off
|
||||
/// the include stack and keeps going.
|
||||
bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) {
|
||||
bool Preprocessor::HandleEndOfFile(Token &Result, SourceLocation EndLoc,
|
||||
bool isEndOfMacro) {
|
||||
assert(!CurTokenLexer &&
|
||||
"Ending a file when currently in a macro!");
|
||||
|
||||
@ -372,6 +410,9 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) {
|
||||
}
|
||||
}
|
||||
|
||||
if (EndLoc.isValid())
|
||||
ResolvePragmaIncludeInstead(EndLoc);
|
||||
|
||||
// Complain about reaching a true EOF within arc_cf_code_audited.
|
||||
// We don't want to complain about reaching the end of a macro
|
||||
// instantiation or a _Pragma.
|
||||
@ -560,7 +601,7 @@ bool Preprocessor::HandleEndOfTokenLexer(Token &Result) {
|
||||
TokenLexerCache[NumCachedTokenLexers++] = std::move(CurTokenLexer);
|
||||
|
||||
// Handle this like a #include file being popped off the stack.
|
||||
return HandleEndOfFile(Result, true);
|
||||
return HandleEndOfFile(Result, {}, true);
|
||||
}
|
||||
|
||||
/// RemoveTopOfLexerStack - Pop the current lexer/macro exp off the top of the
|
||||
|
@ -1453,15 +1453,6 @@ static bool isTargetEnvironment(const TargetInfo &TI,
|
||||
return TI.getTriple().getEnvironment() == Env.getEnvironment();
|
||||
}
|
||||
|
||||
static void remapMacroPath(
|
||||
SmallString<256> &Path,
|
||||
const std::map<std::string, std::string, std::greater<std::string>>
|
||||
&MacroPrefixMap) {
|
||||
for (const auto &Entry : MacroPrefixMap)
|
||||
if (llvm::sys::path::replace_path_prefix(Path, Entry.first, Entry.second))
|
||||
break;
|
||||
}
|
||||
|
||||
/// ExpandBuiltinMacro - If an identifier token is read that is to be expanded
|
||||
/// as a builtin macro, handle it and return the next token as 'Tok'.
|
||||
void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
|
||||
@ -1543,7 +1534,7 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
|
||||
} else {
|
||||
FN += PLoc.getFilename();
|
||||
}
|
||||
remapMacroPath(FN, PPOpts->MacroPrefixMap);
|
||||
getLangOpts().remapPathPrefix(FN);
|
||||
Lexer::Stringify(FN);
|
||||
OS << '"' << FN << '"';
|
||||
}
|
||||
|
@ -13,6 +13,7 @@
|
||||
|
||||
#include "clang/Lex/Pragma.h"
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
#include "clang/Basic/DiagnosticLex.h"
|
||||
#include "clang/Basic/FileManager.h"
|
||||
#include "clang/Basic/IdentifierTable.h"
|
||||
#include "clang/Basic/LLVM.h"
|
||||
@ -35,11 +36,12 @@
|
||||
#include "clang/Lex/TokenLexer.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringSwitch.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ADT/StringSwitch.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/Timer.h"
|
||||
@ -495,43 +497,88 @@ void Preprocessor::HandlePragmaSystemHeader(Token &SysHeaderTok) {
|
||||
SrcMgr::C_System);
|
||||
}
|
||||
|
||||
/// HandlePragmaDependency - Handle \#pragma GCC dependency "foo" blah.
|
||||
void Preprocessor::HandlePragmaDependency(Token &DependencyTok) {
|
||||
static llvm::Optional<Token> LexHeader(Preprocessor &PP,
|
||||
Optional<FileEntryRef> &File,
|
||||
bool SuppressIncludeNotFoundError) {
|
||||
Token FilenameTok;
|
||||
if (LexHeaderName(FilenameTok, /*AllowConcatenation*/false))
|
||||
return;
|
||||
if (PP.LexHeaderName(FilenameTok, /*AllowConcatenation*/ false))
|
||||
return llvm::None;
|
||||
|
||||
// If the next token wasn't a header-name, diagnose the error.
|
||||
if (FilenameTok.isNot(tok::header_name)) {
|
||||
Diag(FilenameTok.getLocation(), diag::err_pp_expects_filename);
|
||||
return;
|
||||
PP.Diag(FilenameTok.getLocation(), diag::err_pp_expects_filename);
|
||||
return llvm::None;
|
||||
}
|
||||
|
||||
// Reserve a buffer to get the spelling.
|
||||
SmallString<128> FilenameBuffer;
|
||||
bool Invalid = false;
|
||||
StringRef Filename = getSpelling(FilenameTok, FilenameBuffer, &Invalid);
|
||||
StringRef Filename = PP.getSpelling(FilenameTok, FilenameBuffer, &Invalid);
|
||||
if (Invalid)
|
||||
return;
|
||||
return llvm::None;
|
||||
|
||||
bool isAngled =
|
||||
GetIncludeFilenameSpelling(FilenameTok.getLocation(), Filename);
|
||||
PP.GetIncludeFilenameSpelling(FilenameTok.getLocation(), Filename);
|
||||
// If GetIncludeFilenameSpelling set the start ptr to null, there was an
|
||||
// error.
|
||||
if (Filename.empty())
|
||||
return;
|
||||
return llvm::None;
|
||||
|
||||
// Search include directories for this file.
|
||||
const DirectoryLookup *CurDir;
|
||||
Optional<FileEntryRef> File =
|
||||
LookupFile(FilenameTok.getLocation(), Filename, isAngled, nullptr,
|
||||
nullptr, CurDir, nullptr, nullptr, nullptr, nullptr, nullptr);
|
||||
File = PP.LookupFile(FilenameTok.getLocation(), Filename, isAngled, nullptr,
|
||||
nullptr, CurDir, nullptr, nullptr, nullptr, nullptr,
|
||||
nullptr);
|
||||
if (!File) {
|
||||
if (!SuppressIncludeNotFoundError)
|
||||
Diag(FilenameTok, diag::err_pp_file_not_found) << Filename;
|
||||
PP.Diag(FilenameTok, diag::err_pp_file_not_found) << Filename;
|
||||
return llvm::None;
|
||||
}
|
||||
|
||||
return FilenameTok;
|
||||
}
|
||||
|
||||
/// HandlePragmaIncludeInstead - Handle \#pragma clang include_instead(header).
|
||||
void Preprocessor::HandlePragmaIncludeInstead(Token &Tok) {
|
||||
// Get the current file lexer we're looking at. Ignore _Pragma 'files' etc.
|
||||
PreprocessorLexer *TheLexer = getCurrentFileLexer();
|
||||
|
||||
if (!SourceMgr.isInSystemHeader(Tok.getLocation())) {
|
||||
Diag(Tok, diag::err_pragma_include_instead_not_sysheader);
|
||||
return;
|
||||
}
|
||||
|
||||
Lex(Tok);
|
||||
if (Tok.isNot(tok::l_paren)) {
|
||||
Diag(Tok, diag::err_expected) << "(";
|
||||
return;
|
||||
}
|
||||
|
||||
Optional<FileEntryRef> File;
|
||||
llvm::Optional<Token> FilenameTok =
|
||||
LexHeader(*this, File, SuppressIncludeNotFoundError);
|
||||
if (!FilenameTok)
|
||||
return;
|
||||
|
||||
Lex(Tok);
|
||||
if (Tok.isNot(tok::r_paren)) {
|
||||
Diag(Tok, diag::err_expected) << ")";
|
||||
return;
|
||||
}
|
||||
|
||||
SmallString<128> FilenameBuffer;
|
||||
StringRef Filename = getSpelling(*FilenameTok, FilenameBuffer);
|
||||
HeaderInfo.AddFileAlias(TheLexer->getFileEntry(), Filename);
|
||||
}
|
||||
|
||||
/// HandlePragmaDependency - Handle \#pragma GCC dependency "foo" blah.
|
||||
void Preprocessor::HandlePragmaDependency(Token &DependencyTok) {
|
||||
Optional<FileEntryRef> File;
|
||||
llvm::Optional<Token> FilenameTok =
|
||||
LexHeader(*this, File, SuppressIncludeNotFoundError);
|
||||
if (!FilenameTok)
|
||||
return;
|
||||
|
||||
const FileEntry *CurFile = getCurrentFileLexer()->getFileEntry();
|
||||
|
||||
// If this file is older than the file it depends on, emit a diagnostic.
|
||||
@ -547,7 +594,7 @@ void Preprocessor::HandlePragmaDependency(Token &DependencyTok) {
|
||||
// Remove the trailing ' ' if present.
|
||||
if (!Message.empty())
|
||||
Message.erase(Message.end()-1);
|
||||
Diag(FilenameTok, diag::pp_out_of_date_dependency) << Message;
|
||||
Diag(*FilenameTok, diag::pp_out_of_date_dependency) << Message;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1022,6 +1069,18 @@ struct PragmaSystemHeaderHandler : public PragmaHandler {
|
||||
}
|
||||
};
|
||||
|
||||
/// PragmaIncludeInsteadHandler - "\#pragma clang include_instead(header)" marks
|
||||
/// the current file as non-includable if the including header is not a system
|
||||
/// header.
|
||||
struct PragmaIncludeInsteadHandler : public PragmaHandler {
|
||||
PragmaIncludeInsteadHandler() : PragmaHandler("include_instead") {}
|
||||
|
||||
void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
|
||||
Token &IIToken) override {
|
||||
PP.HandlePragmaIncludeInstead(IIToken);
|
||||
}
|
||||
};
|
||||
|
||||
struct PragmaDependencyHandler : public PragmaHandler {
|
||||
PragmaDependencyHandler() : PragmaHandler("dependency") {}
|
||||
|
||||
@ -1934,6 +1993,7 @@ void Preprocessor::RegisterBuiltinPragmas() {
|
||||
// #pragma clang ...
|
||||
AddPragmaHandler("clang", new PragmaPoisonHandler());
|
||||
AddPragmaHandler("clang", new PragmaSystemHeaderHandler());
|
||||
AddPragmaHandler("clang", new PragmaIncludeInsteadHandler());
|
||||
AddPragmaHandler("clang", new PragmaDebugHandler());
|
||||
AddPragmaHandler("clang", new PragmaDependencyHandler());
|
||||
AddPragmaHandler("clang", new PragmaDiagnosticHandler("clang"));
|
||||
|
@ -716,12 +716,6 @@ IdentifierInfo *Preprocessor::LookUpIdentifierInfo(Token &Identifier) const {
|
||||
}
|
||||
|
||||
// Update the token info (identifier info and appropriate token kind).
|
||||
// FIXME: the raw_identifier may contain leading whitespace which is removed
|
||||
// from the cleaned identifier token. The SourceLocation should be updated to
|
||||
// refer to the non-whitespace character. For instance, the text "\\\nB" (a
|
||||
// line continuation before 'B') is parsed as a single tok::raw_identifier and
|
||||
// is cleaned to tok::identifier "B". After cleaning the token's length is
|
||||
// still 3 and the SourceLocation refers to the location of the backslash.
|
||||
Identifier.setIdentifierInfo(II);
|
||||
if (getLangOpts().MSVCCompat && II->isCPlusPlusOperatorKeyword() &&
|
||||
getSourceManager().isInSystemHeader(Identifier.getLocation()))
|
||||
|
@ -3952,8 +3952,12 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
|
||||
Tok.getIdentifierInfo()->revertTokenIDToIdentifier();
|
||||
Tok.setKind(tok::identifier);
|
||||
goto DoneWithDeclSpec;
|
||||
}
|
||||
isInvalid = DS.SetTypePipe(true, Loc, PrevSpec, DiagID, Policy);
|
||||
} else if (!getLangOpts().OpenCLPipes) {
|
||||
DiagID = diag::err_opencl_unknown_type_specifier;
|
||||
PrevSpec = Tok.getIdentifierInfo()->getNameStart();
|
||||
isInvalid = true;
|
||||
} else
|
||||
isInvalid = DS.SetTypePipe(true, Loc, PrevSpec, DiagID, Policy);
|
||||
break;
|
||||
// We only need to enumerate each image type once.
|
||||
#define IMAGE_READ_WRITE_TYPE(Type, Id, Ext)
|
||||
@ -5126,8 +5130,10 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) {
|
||||
switch (Tok.getKind()) {
|
||||
default: return false;
|
||||
|
||||
// OpenCL 2.0 and later define this keyword.
|
||||
case tok::kw_pipe:
|
||||
return getLangOpts().OpenCLPipe;
|
||||
return (getLangOpts().OpenCL && getLangOpts().OpenCLVersion >= 200) ||
|
||||
getLangOpts().OpenCLCPlusPlus;
|
||||
|
||||
case tok::identifier: // foo::bar
|
||||
// Unfortunate hack to support "Class.factoryMethod" notation.
|
||||
@ -5656,7 +5662,9 @@ static bool isPtrOperatorToken(tok::TokenKind Kind, const LangOptions &Lang,
|
||||
if (Kind == tok::star || Kind == tok::caret)
|
||||
return true;
|
||||
|
||||
if (Kind == tok::kw_pipe && Lang.OpenCLPipe)
|
||||
// OpenCL 2.0 and later define this keyword.
|
||||
if (Kind == tok::kw_pipe &&
|
||||
((Lang.OpenCL && Lang.OpenCLVersion >= 200) || Lang.OpenCLCPlusPlus))
|
||||
return true;
|
||||
|
||||
if (!Lang.CPlusPlus)
|
||||
|
@ -327,7 +327,8 @@ void Sema::Initialize() {
|
||||
if (getLangOpts().OpenCLCPlusPlus || getLangOpts().OpenCLVersion >= 200) {
|
||||
addImplicitTypedef("clk_event_t", Context.OCLClkEventTy);
|
||||
addImplicitTypedef("queue_t", Context.OCLQueueTy);
|
||||
addImplicitTypedef("reserve_id_t", Context.OCLReserveIDTy);
|
||||
if (getLangOpts().OpenCLPipes)
|
||||
addImplicitTypedef("reserve_id_t", Context.OCLReserveIDTy);
|
||||
addImplicitTypedef("atomic_int", Context.getAtomicType(Context.IntTy));
|
||||
addImplicitTypedef("atomic_uint",
|
||||
Context.getAtomicType(Context.UnsignedIntTy));
|
||||
|
@ -742,22 +742,15 @@ Optional<NormalizedConstraint>
|
||||
NormalizedConstraint::fromConstraintExprs(Sema &S, NamedDecl *D,
|
||||
ArrayRef<const Expr *> E) {
|
||||
assert(E.size() != 0);
|
||||
auto First = fromConstraintExpr(S, D, E[0]);
|
||||
if (E.size() == 1)
|
||||
return First;
|
||||
auto Second = fromConstraintExpr(S, D, E[1]);
|
||||
if (!Second)
|
||||
auto Conjunction = fromConstraintExpr(S, D, E[0]);
|
||||
if (!Conjunction)
|
||||
return None;
|
||||
llvm::Optional<NormalizedConstraint> Conjunction;
|
||||
Conjunction.emplace(S.Context, std::move(*First), std::move(*Second),
|
||||
CCK_Conjunction);
|
||||
for (unsigned I = 2; I < E.size(); ++I) {
|
||||
for (unsigned I = 1; I < E.size(); ++I) {
|
||||
auto Next = fromConstraintExpr(S, D, E[I]);
|
||||
if (!Next)
|
||||
return llvm::Optional<NormalizedConstraint>{};
|
||||
NormalizedConstraint NewConjunction(S.Context, std::move(*Conjunction),
|
||||
return None;
|
||||
*Conjunction = NormalizedConstraint(S.Context, std::move(*Conjunction),
|
||||
std::move(*Next), CCK_Conjunction);
|
||||
*Conjunction = std::move(NewConjunction);
|
||||
}
|
||||
return Conjunction;
|
||||
}
|
||||
|
@ -12472,6 +12472,8 @@ bool Sema::CheckUsingDeclRedeclaration(SourceLocation UsingLoc,
|
||||
return false;
|
||||
}
|
||||
|
||||
const NestedNameSpecifier *CNNS =
|
||||
Context.getCanonicalNestedNameSpecifier(Qual);
|
||||
for (LookupResult::iterator I = Prev.begin(), E = Prev.end(); I != E; ++I) {
|
||||
NamedDecl *D = *I;
|
||||
|
||||
@ -12497,8 +12499,7 @@ bool Sema::CheckUsingDeclRedeclaration(SourceLocation UsingLoc,
|
||||
// using decls differ if they name different scopes (but note that
|
||||
// template instantiation can cause this check to trigger when it
|
||||
// didn't before instantiation).
|
||||
if (Context.getCanonicalNestedNameSpecifier(Qual) !=
|
||||
Context.getCanonicalNestedNameSpecifier(DQual))
|
||||
if (CNNS != Context.getCanonicalNestedNameSpecifier(DQual))
|
||||
continue;
|
||||
|
||||
Diag(NameLoc, diag::err_using_decl_redeclaration) << SS.getRange();
|
||||
|
@ -1079,7 +1079,7 @@ NamedDecl *Sema::ActOnTypeParameter(Scope *S, bool Typename,
|
||||
return Param;
|
||||
|
||||
// Check the template argument itself.
|
||||
if (CheckTemplateArgument(Param, DefaultTInfo)) {
|
||||
if (CheckTemplateArgument(DefaultTInfo)) {
|
||||
Param->setInvalidDecl();
|
||||
return Param;
|
||||
}
|
||||
@ -5042,7 +5042,7 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param,
|
||||
}
|
||||
}
|
||||
|
||||
if (CheckTemplateArgument(Param, TSI))
|
||||
if (CheckTemplateArgument(TSI))
|
||||
return true;
|
||||
|
||||
// Add the converted template type argument.
|
||||
@ -5661,7 +5661,7 @@ bool Sema::CheckTemplateArgumentList(
|
||||
TemplateArgumentListInfo NewArgs = TemplateArgs;
|
||||
|
||||
// Make sure we get the template parameter list from the most
|
||||
// recentdeclaration, since that is the only one that has is guaranteed to
|
||||
// recent declaration, since that is the only one that is guaranteed to
|
||||
// have all the default template argument information.
|
||||
TemplateParameterList *Params =
|
||||
cast<TemplateDecl>(Template->getMostRecentDecl())
|
||||
@ -6208,8 +6208,7 @@ bool UnnamedLocalNoLinkageFinder::VisitNestedNameSpecifier(
|
||||
///
|
||||
/// This routine implements the semantics of C++ [temp.arg.type]. It
|
||||
/// returns true if an error occurred, and false otherwise.
|
||||
bool Sema::CheckTemplateArgument(TemplateTypeParmDecl *Param,
|
||||
TypeSourceInfo *ArgInfo) {
|
||||
bool Sema::CheckTemplateArgument(TypeSourceInfo *ArgInfo) {
|
||||
assert(ArgInfo && "invalid TypeSourceInfo");
|
||||
QualType Arg = ArgInfo->getType();
|
||||
SourceRange SR = ArgInfo->getTypeLoc().getSourceRange();
|
||||
|
@ -1934,25 +1934,23 @@ TemplateInstantiator::TransformExprRequirement(concepts::ExprRequirement *Req) {
|
||||
return Req;
|
||||
|
||||
Sema::SFINAETrap Trap(SemaRef);
|
||||
TemplateDeductionInfo Info(Req->getExpr()->getBeginLoc());
|
||||
|
||||
llvm::PointerUnion<Expr *, concepts::Requirement::SubstitutionDiagnostic *>
|
||||
TransExpr;
|
||||
if (Req->isExprSubstitutionFailure())
|
||||
TransExpr = Req->getExprSubstitutionDiagnostic();
|
||||
else {
|
||||
Sema::InstantiatingTemplate ExprInst(SemaRef, Req->getExpr()->getBeginLoc(),
|
||||
Req, Info,
|
||||
Req->getExpr()->getSourceRange());
|
||||
Expr *E = Req->getExpr();
|
||||
TemplateDeductionInfo Info(E->getBeginLoc());
|
||||
Sema::InstantiatingTemplate ExprInst(SemaRef, E->getBeginLoc(), Req, Info,
|
||||
E->getSourceRange());
|
||||
if (ExprInst.isInvalid())
|
||||
return nullptr;
|
||||
ExprResult TransExprRes = TransformExpr(Req->getExpr());
|
||||
ExprResult TransExprRes = TransformExpr(E);
|
||||
if (TransExprRes.isInvalid() || Trap.hasErrorOccurred())
|
||||
TransExpr = createSubstDiag(SemaRef, Info,
|
||||
[&] (llvm::raw_ostream& OS) {
|
||||
Req->getExpr()->printPretty(OS, nullptr,
|
||||
SemaRef.getPrintingPolicy());
|
||||
});
|
||||
TransExpr = createSubstDiag(SemaRef, Info, [&](llvm::raw_ostream &OS) {
|
||||
E->printPretty(OS, nullptr, SemaRef.getPrintingPolicy());
|
||||
});
|
||||
else
|
||||
TransExpr = TransExprRes.get();
|
||||
}
|
||||
@ -1966,6 +1964,7 @@ TemplateInstantiator::TransformExprRequirement(concepts::ExprRequirement *Req) {
|
||||
else if (RetReq.isTypeConstraint()) {
|
||||
TemplateParameterList *OrigTPL =
|
||||
RetReq.getTypeConstraintTemplateParameterList();
|
||||
TemplateDeductionInfo Info(OrigTPL->getTemplateLoc());
|
||||
Sema::InstantiatingTemplate TPLInst(SemaRef, OrigTPL->getTemplateLoc(),
|
||||
Req, Info, OrigTPL->getSourceRange());
|
||||
if (TPLInst.isInvalid())
|
||||
|
@ -1525,18 +1525,20 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
|
||||
break;
|
||||
case DeclSpec::TST_float: Result = Context.FloatTy; break;
|
||||
case DeclSpec::TST_double:
|
||||
if (S.getLangOpts().OpenCL) {
|
||||
if (!S.getOpenCLOptions().isSupported("cl_khr_fp64", S.getLangOpts()))
|
||||
S.Diag(DS.getTypeSpecTypeLoc(),
|
||||
diag::err_opencl_double_requires_extension)
|
||||
<< (S.getLangOpts().OpenCLVersion >= 300);
|
||||
else if (!S.getOpenCLOptions().isAvailableOption("cl_khr_fp64", S.getLangOpts()))
|
||||
S.Diag(DS.getTypeSpecTypeLoc(), diag::ext_opencl_double_without_pragma);
|
||||
}
|
||||
if (DS.getTypeSpecWidth() == TypeSpecifierWidth::Long)
|
||||
Result = Context.LongDoubleTy;
|
||||
else
|
||||
Result = Context.DoubleTy;
|
||||
if (S.getLangOpts().OpenCL) {
|
||||
if (!S.getOpenCLOptions().isSupported("cl_khr_fp64", S.getLangOpts()))
|
||||
S.Diag(DS.getTypeSpecTypeLoc(), diag::err_opencl_requires_extension)
|
||||
<< 0 << Result
|
||||
<< (S.getLangOpts().OpenCLVersion == 300
|
||||
? "cl_khr_fp64 and __opencl_c_fp64"
|
||||
: "cl_khr_fp64");
|
||||
else if (!S.getOpenCLOptions().isAvailableOption("cl_khr_fp64", S.getLangOpts()))
|
||||
S.Diag(DS.getTypeSpecTypeLoc(), diag::ext_opencl_double_without_pragma);
|
||||
}
|
||||
break;
|
||||
case DeclSpec::TST_float128:
|
||||
if (!S.Context.getTargetInfo().hasFloat128Type() &&
|
||||
@ -1724,21 +1726,28 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
|
||||
|
||||
if (S.getLangOpts().OpenCL) {
|
||||
const auto &OpenCLOptions = S.getOpenCLOptions();
|
||||
StringRef OptName;
|
||||
bool IsOpenCLC30 = (S.getLangOpts().OpenCLVersion == 300);
|
||||
// OpenCL C v3.0 s6.3.3 - OpenCL image types require __opencl_c_images
|
||||
// support
|
||||
// support.
|
||||
// OpenCL C v3.0 s6.2.1 - OpenCL 3d image write types requires support
|
||||
// for OpenCL C 2.0, or OpenCL C 3.0 or newer and the
|
||||
// __opencl_c_3d_image_writes feature. OpenCL C v3.0 API s4.2 - For devices
|
||||
// that support OpenCL 3.0, cl_khr_3d_image_writes must be returned when and
|
||||
// only when the optional feature is supported
|
||||
if ((Result->isImageType() || Result->isSamplerT()) &&
|
||||
(S.getLangOpts().OpenCLVersion >= 300 &&
|
||||
!OpenCLOptions.isSupported("__opencl_c_images", S.getLangOpts())))
|
||||
OptName = "__opencl_c_images";
|
||||
else if (Result->isOCLImage3dWOType() &&
|
||||
!OpenCLOptions.isSupported("cl_khr_3d_image_writes",
|
||||
S.getLangOpts()))
|
||||
OptName = "cl_khr_3d_image_writes";
|
||||
|
||||
if (!OptName.empty()) {
|
||||
(IsOpenCLC30 &&
|
||||
!OpenCLOptions.isSupported("__opencl_c_images", S.getLangOpts()))) {
|
||||
S.Diag(DS.getTypeSpecTypeLoc(), diag::err_opencl_requires_extension)
|
||||
<< 0 << Result << OptName;
|
||||
<< 0 << Result << "__opencl_c_images";
|
||||
declarator.setInvalidType();
|
||||
} else if (Result->isOCLImage3dWOType() &&
|
||||
!OpenCLOptions.isSupported("cl_khr_3d_image_writes",
|
||||
S.getLangOpts())) {
|
||||
S.Diag(DS.getTypeSpecTypeLoc(), diag::err_opencl_requires_extension)
|
||||
<< 0 << Result
|
||||
<< (IsOpenCLC30
|
||||
? "cl_khr_3d_image_writes and __opencl_c_3d_image_writes"
|
||||
: "cl_khr_3d_image_writes");
|
||||
declarator.setInvalidType();
|
||||
}
|
||||
}
|
||||
|
@ -129,6 +129,7 @@ INSTR_PROF_VALUE_NODE(PtrToNodeT, llvm::Type::getInt8PtrTy(Ctx), Next, \
|
||||
#endif
|
||||
INSTR_PROF_RAW_HEADER(uint64_t, Magic, __llvm_profile_get_magic())
|
||||
INSTR_PROF_RAW_HEADER(uint64_t, Version, __llvm_profile_get_version())
|
||||
INSTR_PROF_RAW_HEADER(uint64_t, BinaryIdsSize, __llvm_write_binary_ids(NULL))
|
||||
INSTR_PROF_RAW_HEADER(uint64_t, DataSize, DataSize)
|
||||
INSTR_PROF_RAW_HEADER(uint64_t, PaddingBytesBeforeCounters, PaddingBytesBeforeCounters)
|
||||
INSTR_PROF_RAW_HEADER(uint64_t, CountersSize, CountersSize)
|
||||
@ -137,7 +138,6 @@ INSTR_PROF_RAW_HEADER(uint64_t, NamesSize, NamesSize)
|
||||
INSTR_PROF_RAW_HEADER(uint64_t, CountersDelta, (uintptr_t)CountersBegin)
|
||||
INSTR_PROF_RAW_HEADER(uint64_t, NamesDelta, (uintptr_t)NamesBegin)
|
||||
INSTR_PROF_RAW_HEADER(uint64_t, ValueKindLast, IPVK_Last)
|
||||
INSTR_PROF_RAW_HEADER(uint64_t, BinaryIdsSize, __llvm_write_binary_ids(NULL))
|
||||
#undef INSTR_PROF_RAW_HEADER
|
||||
/* INSTR_PROF_RAW_HEADER end */
|
||||
|
||||
@ -646,7 +646,7 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
|
||||
(uint64_t)'f' << 16 | (uint64_t)'R' << 8 | (uint64_t)129
|
||||
|
||||
/* Raw profile format version (start from 1). */
|
||||
#define INSTR_PROF_RAW_VERSION 6
|
||||
#define INSTR_PROF_RAW_VERSION 7
|
||||
/* Indexed profile format version (start from 1). */
|
||||
#define INSTR_PROF_INDEX_VERSION 7
|
||||
/* Coverage mapping format version (start from 0). */
|
||||
|
@ -116,7 +116,7 @@ uint64_t __llvm_profile_get_size_for_buffer_internal(
|
||||
DataSize, CountersSize, NamesSize, &PaddingBytesBeforeCounters,
|
||||
&PaddingBytesAfterCounters, &PaddingBytesAfterNames);
|
||||
|
||||
return sizeof(__llvm_profile_header) +
|
||||
return sizeof(__llvm_profile_header) + __llvm_write_binary_ids(NULL) +
|
||||
(DataSize * sizeof(__llvm_profile_data)) + PaddingBytesBeforeCounters +
|
||||
(CountersSize * sizeof(uint64_t)) + PaddingBytesAfterCounters +
|
||||
NamesSize + PaddingBytesAfterNames;
|
||||
|
@ -22,6 +22,7 @@ void (*VPMergeHook)(ValueProfData *, __llvm_profile_data *);
|
||||
COMPILER_RT_VISIBILITY
|
||||
uint64_t lprofGetLoadModuleSignature() {
|
||||
/* A very fast way to compute a module signature. */
|
||||
uint64_t Version = __llvm_profile_get_version();
|
||||
uint64_t CounterSize = (uint64_t)(__llvm_profile_end_counters() -
|
||||
__llvm_profile_begin_counters());
|
||||
uint64_t DataSize = __llvm_profile_get_data_size(__llvm_profile_begin_data(),
|
||||
@ -33,7 +34,7 @@ uint64_t lprofGetLoadModuleSignature() {
|
||||
const __llvm_profile_data *FirstD = __llvm_profile_begin_data();
|
||||
|
||||
return (NamesSize << 40) + (CounterSize << 30) + (DataSize << 20) +
|
||||
(NumVnodes << 10) + (DataSize > 0 ? FirstD->NameRef : 0);
|
||||
(NumVnodes << 10) + (DataSize > 0 ? FirstD->NameRef : 0) + Version;
|
||||
}
|
||||
|
||||
/* Returns 1 if profile is not structurally compatible. */
|
||||
@ -44,7 +45,8 @@ int __llvm_profile_check_compatibility(const char *ProfileData,
|
||||
__llvm_profile_header *Header = (__llvm_profile_header *)ProfileData;
|
||||
__llvm_profile_data *SrcDataStart, *SrcDataEnd, *SrcData, *DstData;
|
||||
SrcDataStart =
|
||||
(__llvm_profile_data *)(ProfileData + sizeof(__llvm_profile_header));
|
||||
(__llvm_profile_data *)(ProfileData + sizeof(__llvm_profile_header) +
|
||||
Header->BinaryIdsSize);
|
||||
SrcDataEnd = SrcDataStart + Header->DataSize;
|
||||
|
||||
if (ProfileSize < sizeof(__llvm_profile_header))
|
||||
@ -63,7 +65,7 @@ int __llvm_profile_check_compatibility(const char *ProfileData,
|
||||
Header->ValueKindLast != IPVK_Last)
|
||||
return 1;
|
||||
|
||||
if (ProfileSize < sizeof(__llvm_profile_header) +
|
||||
if (ProfileSize < sizeof(__llvm_profile_header) + Header->BinaryIdsSize +
|
||||
Header->DataSize * sizeof(__llvm_profile_data) +
|
||||
Header->NamesSize + Header->CountersSize)
|
||||
return 1;
|
||||
@ -91,7 +93,8 @@ int __llvm_profile_merge_from_buffer(const char *ProfileData,
|
||||
const char *SrcValueProfDataStart, *SrcValueProfData;
|
||||
|
||||
SrcDataStart =
|
||||
(__llvm_profile_data *)(ProfileData + sizeof(__llvm_profile_header));
|
||||
(__llvm_profile_data *)(ProfileData + sizeof(__llvm_profile_header) +
|
||||
Header->BinaryIdsSize);
|
||||
SrcDataEnd = SrcDataStart + Header->DataSize;
|
||||
SrcCountersStart = (uint64_t *)SrcDataEnd;
|
||||
SrcNameStart = (const char *)(SrcCountersStart + Header->CountersSize);
|
||||
|
@ -17,6 +17,15 @@
|
||||
#include "InstrProfiling.h"
|
||||
#include "InstrProfilingInternal.h"
|
||||
|
||||
#if defined(__FreeBSD__) && !defined(ElfW)
|
||||
/*
|
||||
* FreeBSD's elf.h and link.h headers do not define the ElfW(type) macro yet.
|
||||
* If this is added to all supported FreeBSD versions in the future, this
|
||||
* compatibility macro can be removed.
|
||||
*/
|
||||
#define ElfW(type) __ElfN(type)
|
||||
#endif
|
||||
|
||||
#define PROF_DATA_START INSTR_PROF_SECT_START(INSTR_PROF_DATA_COMMON)
|
||||
#define PROF_DATA_STOP INSTR_PROF_SECT_STOP(INSTR_PROF_DATA_COMMON)
|
||||
#define PROF_NAME_START INSTR_PROF_SECT_START(INSTR_PROF_NAME_COMMON)
|
||||
@ -76,6 +85,7 @@ COMPILER_RT_VISIBILITY ValueProfNode *__llvm_profile_end_vnodes(void) {
|
||||
COMPILER_RT_VISIBILITY ValueProfNode *CurrentVNode = &PROF_VNODES_START;
|
||||
COMPILER_RT_VISIBILITY ValueProfNode *EndVNode = &PROF_VNODES_STOP;
|
||||
|
||||
#ifdef NT_GNU_BUILD_ID
|
||||
static size_t RoundUp(size_t size, size_t align) {
|
||||
return (size + align - 1) & ~(align - 1);
|
||||
}
|
||||
@ -179,5 +189,14 @@ COMPILER_RT_VISIBILITY int __llvm_write_binary_ids(ProfDataWriter *Writer) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else /* !NT_GNU_BUILD_ID */
|
||||
/*
|
||||
* Fallback implementation for targets that don't support the GNU
|
||||
* extensions NT_GNU_BUILD_ID and __ehdr_start.
|
||||
*/
|
||||
COMPILER_RT_VISIBILITY int __llvm_write_binary_ids(ProfDataWriter *Writer) {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -354,6 +354,16 @@
|
||||
# define _LIBCPP_NO_CFI
|
||||
#endif
|
||||
|
||||
// If the compiler supports using_if_exists, pretend we have those functions and they'll
|
||||
// be picked up if the C library provides them.
|
||||
//
|
||||
// TODO: Once we drop support for Clang 12, we can assume the compiler supports using_if_exists
|
||||
// for platforms that don't have a conforming C11 library, so we can drop this whole thing.
|
||||
#if __has_attribute(using_if_exists)
|
||||
# define _LIBCPP_HAS_TIMESPEC_GET
|
||||
# define _LIBCPP_HAS_QUICK_EXIT
|
||||
# define _LIBCPP_HAS_ALIGNED_ALLOC
|
||||
#else
|
||||
#if (defined(__ISO_C_VISIBLE) && (__ISO_C_VISIBLE >= 2011)) || __cplusplus >= 201103L
|
||||
# if defined(__FreeBSD__)
|
||||
# define _LIBCPP_HAS_ALIGNED_ALLOC
|
||||
@ -408,6 +418,7 @@
|
||||
# endif
|
||||
# endif // __APPLE__
|
||||
#endif
|
||||
#endif // __has_attribute(using_if_exists)
|
||||
|
||||
#ifndef _LIBCPP_CXX03_LANG
|
||||
# define _LIBCPP_ALIGNOF(_Tp) alignof(_Tp)
|
||||
|
@ -59,7 +59,7 @@ int timespec_get( struct timespec *ts, int base); // C++17
|
||||
// we're detecting this here instead of in <__config> because we can't include
|
||||
// system headers from <__config>, since it leads to circular module dependencies.
|
||||
// This is also meant to be a very temporary workaround until the SDKs are fixed.
|
||||
#if defined(__APPLE__)
|
||||
#if defined(__APPLE__) && !__has_attribute(using_if_exists)
|
||||
# include <sys/cdefs.h>
|
||||
# if defined(_LIBCPP_HAS_TIMESPEC_GET) && (__DARWIN_C_LEVEL < __DARWIN_C_FULL)
|
||||
# define _LIBCPP_HAS_TIMESPEC_GET_NOT_ACTUALLY_PROVIDED
|
||||
|
@ -55,14 +55,14 @@ namespace std {
|
||||
|
||||
*/
|
||||
|
||||
// Make sure all feature tests macros are always available.
|
||||
#include <version>
|
||||
// Only enable the contents of the header when libc++ was build with LIBCXX_ENABLE_INCOMPLETE_FEATURES enabled
|
||||
#if !defined(_LIBCPP_HAS_NO_INCOMPLETE_FORMAT)
|
||||
|
||||
#include <__config>
|
||||
#include <__format/format_error.h>
|
||||
#include <__format/format_parse_context.h>
|
||||
#include <version>
|
||||
|
||||
#if defined(_LIBCPP_HAS_NO_INCOMPLETE_FORMAT)
|
||||
# error "The Format library is not supported since libc++ has been configured with LIBCXX_ENABLE_INCOMPLETE_FEATURES disabled"
|
||||
#endif
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||
# pragma GCC system_header
|
||||
@ -81,4 +81,6 @@ _LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
_LIBCPP_POP_MACROS
|
||||
|
||||
#endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_FORMAT)
|
||||
|
||||
#endif // _LIBCPP_FORMAT
|
||||
|
@ -607,8 +607,15 @@ public:
|
||||
static_assert((is_same<_CharT, typename traits_type::char_type>::value),
|
||||
"traits_type::char_type must be the same type as CharT");
|
||||
|
||||
#ifdef _LIBCPP_CXX03_LANG
|
||||
// Preserve the ability to compare with literal 0,
|
||||
// and implicitly convert to bool, but not implicitly convert to int.
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
operator void*() const {return fail() ? nullptr : (void*)this;}
|
||||
#else
|
||||
_LIBCPP_INLINE_VISIBILITY
|
||||
explicit operator bool() const {return !fail();}
|
||||
#endif
|
||||
|
||||
_LIBCPP_INLINE_VISIBILITY bool operator!() const {return fail();}
|
||||
_LIBCPP_INLINE_VISIBILITY iostate rdstate() const {return ios_base::rdstate();}
|
||||
|
@ -160,6 +160,11 @@ namespace std::ranges {
|
||||
|
||||
*/
|
||||
|
||||
// Make sure all feature tests macros are always available.
|
||||
#include <version>
|
||||
// Only enable the contents of the header when libc++ was build with LIBCXX_ENABLE_INCOMPLETE_FEATURES enabled
|
||||
#if !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)
|
||||
|
||||
#include <__config>
|
||||
#include <__ranges/access.h>
|
||||
#include <__ranges/all.h>
|
||||
@ -181,11 +186,6 @@ namespace std::ranges {
|
||||
#include <initializer_list> // Required by the standard.
|
||||
#include <iterator> // Required by the standard.
|
||||
#include <type_traits>
|
||||
#include <version>
|
||||
|
||||
#if defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)
|
||||
# error "The Ranges library is not supported since libc++ has been configured with LIBCXX_ENABLE_INCOMPLETE_FEATURES disabled"
|
||||
#endif
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||
#pragma GCC system_header
|
||||
@ -204,4 +204,6 @@ _LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
_LIBCPP_POP_MACROS
|
||||
|
||||
#endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)
|
||||
|
||||
#endif // _LIBCPP_RANGES
|
||||
|
@ -38,6 +38,10 @@ enum ELFKind {
|
||||
ELF64BEKind
|
||||
};
|
||||
|
||||
// For -Bno-symbolic, -Bsymbolic-non-weak-functions, -Bsymbolic-functions,
|
||||
// -Bsymbolic.
|
||||
enum class BsymbolicKind { None, NonWeakFunctions, Functions, All };
|
||||
|
||||
// For --build-id.
|
||||
enum class BuildIdKind { None, Fast, Md5, Sha1, Hexstring, Uuid };
|
||||
|
||||
@ -82,7 +86,8 @@ struct SymbolVersion {
|
||||
struct VersionDefinition {
|
||||
llvm::StringRef name;
|
||||
uint16_t id;
|
||||
std::vector<SymbolVersion> patterns;
|
||||
std::vector<SymbolVersion> nonLocalPatterns;
|
||||
std::vector<SymbolVersion> localPatterns;
|
||||
};
|
||||
|
||||
// This struct contains the global configuration for the linker.
|
||||
@ -144,8 +149,7 @@ struct Configuration {
|
||||
bool armHasMovtMovw = false;
|
||||
bool armJ1J2BranchEncoding = false;
|
||||
bool asNeeded = false;
|
||||
bool bsymbolic = false;
|
||||
bool bsymbolicFunctions = false;
|
||||
BsymbolicKind bsymbolic = BsymbolicKind::None;
|
||||
bool callGraphProfileSort;
|
||||
bool checkSections;
|
||||
bool checkDynamicRelocs;
|
||||
|
@ -1006,12 +1006,15 @@ static void readConfigs(opt::InputArgList &args) {
|
||||
OPT_no_allow_multiple_definition, false) ||
|
||||
hasZOption(args, "muldefs");
|
||||
config->auxiliaryList = args::getStrings(args, OPT_auxiliary);
|
||||
if (opt::Arg *arg = args.getLastArg(OPT_Bno_symbolic, OPT_Bsymbolic_functions,
|
||||
OPT_Bsymbolic)) {
|
||||
if (arg->getOption().matches(OPT_Bsymbolic_functions))
|
||||
config->bsymbolicFunctions = true;
|
||||
if (opt::Arg *arg =
|
||||
args.getLastArg(OPT_Bno_symbolic, OPT_Bsymbolic_non_weak_functions,
|
||||
OPT_Bsymbolic_functions, OPT_Bsymbolic)) {
|
||||
if (arg->getOption().matches(OPT_Bsymbolic_non_weak_functions))
|
||||
config->bsymbolic = BsymbolicKind::NonWeakFunctions;
|
||||
else if (arg->getOption().matches(OPT_Bsymbolic_functions))
|
||||
config->bsymbolic = BsymbolicKind::Functions;
|
||||
else if (arg->getOption().matches(OPT_Bsymbolic))
|
||||
config->bsymbolic = true;
|
||||
config->bsymbolic = BsymbolicKind::All;
|
||||
}
|
||||
config->checkSections =
|
||||
args.hasFlag(OPT_check_sections, OPT_no_check_sections, true);
|
||||
@ -1348,18 +1351,19 @@ static void readConfigs(opt::InputArgList &args) {
|
||||
}
|
||||
|
||||
assert(config->versionDefinitions.empty());
|
||||
config->versionDefinitions.push_back({"local", (uint16_t)VER_NDX_LOCAL, {}});
|
||||
config->versionDefinitions.push_back(
|
||||
{"global", (uint16_t)VER_NDX_GLOBAL, {}});
|
||||
{"local", (uint16_t)VER_NDX_LOCAL, {}, {}});
|
||||
config->versionDefinitions.push_back(
|
||||
{"global", (uint16_t)VER_NDX_GLOBAL, {}, {}});
|
||||
|
||||
// If --retain-symbol-file is used, we'll keep only the symbols listed in
|
||||
// the file and discard all others.
|
||||
if (auto *arg = args.getLastArg(OPT_retain_symbols_file)) {
|
||||
config->versionDefinitions[VER_NDX_LOCAL].patterns.push_back(
|
||||
config->versionDefinitions[VER_NDX_LOCAL].nonLocalPatterns.push_back(
|
||||
{"*", /*isExternCpp=*/false, /*hasWildcard=*/true});
|
||||
if (Optional<MemoryBufferRef> buffer = readFile(arg->getValue()))
|
||||
for (StringRef s : args::getLines(*buffer))
|
||||
config->versionDefinitions[VER_NDX_GLOBAL].patterns.push_back(
|
||||
config->versionDefinitions[VER_NDX_GLOBAL].nonLocalPatterns.push_back(
|
||||
{s, /*isExternCpp=*/false, /*hasWildcard=*/false});
|
||||
}
|
||||
|
||||
@ -1374,7 +1378,8 @@ static void readConfigs(opt::InputArgList &args) {
|
||||
// When producing an executable, --dynamic-list specifies non-local defined
|
||||
// symbols which are required to be exported. When producing a shared object,
|
||||
// symbols not specified by --dynamic-list are non-preemptible.
|
||||
config->symbolic = config->bsymbolic || args.hasArg(OPT_dynamic_list);
|
||||
config->symbolic =
|
||||
config->bsymbolic == BsymbolicKind::All || args.hasArg(OPT_dynamic_list);
|
||||
for (auto *arg : args.filtered(OPT_dynamic_list))
|
||||
if (Optional<MemoryBufferRef> buffer = readFile(arg->getValue()))
|
||||
readDynamicList(*buffer);
|
||||
@ -2065,23 +2070,37 @@ static void redirectSymbols(ArrayRef<WrappedSymbol> wrapped) {
|
||||
if (suffix1[0] != '@' || suffix1[1] == '@')
|
||||
continue;
|
||||
|
||||
// Check whether the default version foo@@v1 exists. If it exists, the
|
||||
// symbol can be found by the name "foo" in the symbol table.
|
||||
Symbol *maybeDefault = symtab->find(name);
|
||||
if (!maybeDefault)
|
||||
// Check the existing symbol foo. We have two special cases to handle:
|
||||
//
|
||||
// * There is a definition of foo@v1 and foo@@v1.
|
||||
// * There is a definition of foo@v1 and foo.
|
||||
Defined *sym2 = dyn_cast_or_null<Defined>(symtab->find(name));
|
||||
if (!sym2)
|
||||
continue;
|
||||
const char *suffix2 = maybeDefault->getVersionSuffix();
|
||||
if (suffix2[0] != '@' || suffix2[1] != '@' ||
|
||||
strcmp(suffix1 + 1, suffix2 + 2) != 0)
|
||||
continue;
|
||||
|
||||
// foo@v1 and foo@@v1 should be merged, so redirect foo@v1 to foo@@v1.
|
||||
map.try_emplace(sym, maybeDefault);
|
||||
// If both foo@v1 and foo@@v1 are defined and non-weak, report a duplicate
|
||||
// definition error.
|
||||
maybeDefault->resolve(*sym);
|
||||
// Eliminate foo@v1 from the symbol table.
|
||||
sym->symbolKind = Symbol::PlaceholderKind;
|
||||
const char *suffix2 = sym2->getVersionSuffix();
|
||||
if (suffix2[0] == '@' && suffix2[1] == '@' &&
|
||||
strcmp(suffix1 + 1, suffix2 + 2) == 0) {
|
||||
// foo@v1 and foo@@v1 should be merged, so redirect foo@v1 to foo@@v1.
|
||||
map.try_emplace(sym, sym2);
|
||||
// If both foo@v1 and foo@@v1 are defined and non-weak, report a duplicate
|
||||
// definition error.
|
||||
sym2->resolve(*sym);
|
||||
// Eliminate foo@v1 from the symbol table.
|
||||
sym->symbolKind = Symbol::PlaceholderKind;
|
||||
} else if (auto *sym1 = dyn_cast<Defined>(sym)) {
|
||||
if (sym2->versionId > VER_NDX_GLOBAL
|
||||
? config->versionDefinitions[sym2->versionId].name == suffix1 + 1
|
||||
: sym1->section == sym2->section && sym1->value == sym2->value) {
|
||||
// Due to an assembler design flaw, if foo is defined, .symver foo,
|
||||
// foo@v1 defines both foo and foo@v1. Unless foo is bound to a
|
||||
// different version, GNU ld makes foo@v1 canonical and elimiates foo.
|
||||
// Emulate its behavior, otherwise we would have foo or foo@@v1 beside
|
||||
// foo@v1. foo@v1 and foo combining does not apply if they are not
|
||||
// defined in the same place.
|
||||
map.try_emplace(sym2, sym);
|
||||
sym2->symbolKind = Symbol::PlaceholderKind;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (map.empty())
|
||||
|
@ -849,17 +849,8 @@ void LinkerScript::diagnoseOrphanHandling() const {
|
||||
}
|
||||
|
||||
uint64_t LinkerScript::advance(uint64_t size, unsigned alignment) {
|
||||
bool isTbss =
|
||||
(ctx->outSec->flags & SHF_TLS) && ctx->outSec->type == SHT_NOBITS;
|
||||
uint64_t start = isTbss ? dot + ctx->threadBssOffset : dot;
|
||||
start = alignTo(start, alignment);
|
||||
uint64_t end = start + size;
|
||||
|
||||
if (isTbss)
|
||||
ctx->threadBssOffset = end - dot;
|
||||
else
|
||||
dot = end;
|
||||
return end;
|
||||
dot = alignTo(dot, alignment) + size;
|
||||
return dot;
|
||||
}
|
||||
|
||||
void LinkerScript::output(InputSection *s) {
|
||||
@ -931,13 +922,24 @@ static OutputSection *findFirstSection(PhdrEntry *load) {
|
||||
// This function assigns offsets to input sections and an output section
|
||||
// for a single sections command (e.g. ".text { *(.text); }").
|
||||
void LinkerScript::assignOffsets(OutputSection *sec) {
|
||||
const bool isTbss = (sec->flags & SHF_TLS) && sec->type == SHT_NOBITS;
|
||||
const bool sameMemRegion = ctx->memRegion == sec->memRegion;
|
||||
const bool prevLMARegionIsDefault = ctx->lmaRegion == nullptr;
|
||||
const uint64_t savedDot = dot;
|
||||
ctx->memRegion = sec->memRegion;
|
||||
ctx->lmaRegion = sec->lmaRegion;
|
||||
|
||||
if (sec->flags & SHF_ALLOC) {
|
||||
if (!(sec->flags & SHF_ALLOC)) {
|
||||
// Non-SHF_ALLOC sections have zero addresses.
|
||||
dot = 0;
|
||||
} else if (isTbss) {
|
||||
// Allow consecutive SHF_TLS SHT_NOBITS output sections. The address range
|
||||
// starts from the end address of the previous tbss section.
|
||||
if (ctx->tbssAddr == 0)
|
||||
ctx->tbssAddr = dot;
|
||||
else
|
||||
dot = ctx->tbssAddr;
|
||||
} else {
|
||||
if (ctx->memRegion)
|
||||
dot = ctx->memRegion->curPos;
|
||||
if (sec->addrExpr)
|
||||
@ -950,9 +952,6 @@ void LinkerScript::assignOffsets(OutputSection *sec) {
|
||||
if (ctx->memRegion && ctx->memRegion->curPos < dot)
|
||||
expandMemoryRegion(ctx->memRegion, dot - ctx->memRegion->curPos,
|
||||
ctx->memRegion->name, sec->name);
|
||||
} else {
|
||||
// Non-SHF_ALLOC sections have zero addresses.
|
||||
dot = 0;
|
||||
}
|
||||
|
||||
switchTo(sec);
|
||||
@ -1008,8 +1007,13 @@ void LinkerScript::assignOffsets(OutputSection *sec) {
|
||||
|
||||
// Non-SHF_ALLOC sections do not affect the addresses of other OutputSections
|
||||
// as they are not part of the process image.
|
||||
if (!(sec->flags & SHF_ALLOC))
|
||||
if (!(sec->flags & SHF_ALLOC)) {
|
||||
dot = savedDot;
|
||||
} else if (isTbss) {
|
||||
// NOBITS TLS sections are similar. Additionally save the end address.
|
||||
ctx->tbssAddr = dot;
|
||||
dot = savedDot;
|
||||
}
|
||||
}
|
||||
|
||||
static bool isDiscardable(OutputSection &sec) {
|
||||
|
@ -247,11 +247,11 @@ class LinkerScript final {
|
||||
// not be used outside of the scope of a call to the above functions.
|
||||
struct AddressState {
|
||||
AddressState();
|
||||
uint64_t threadBssOffset = 0;
|
||||
OutputSection *outSec = nullptr;
|
||||
MemoryRegion *memRegion = nullptr;
|
||||
MemoryRegion *lmaRegion = nullptr;
|
||||
uint64_t lmaOffset = 0;
|
||||
uint64_t tbssAddr = 0;
|
||||
};
|
||||
|
||||
llvm::DenseMap<StringRef, OutputSection *> nameToOutputSection;
|
||||
|
@ -43,6 +43,9 @@ def Bsymbolic: F<"Bsymbolic">, HelpText<"Bind default visibility defined symbols
|
||||
def Bsymbolic_functions: F<"Bsymbolic-functions">,
|
||||
HelpText<"Bind default visibility defined function symbols locally for -shared">;
|
||||
|
||||
def Bsymbolic_non_weak_functions: F<"Bsymbolic-non-weak-functions">,
|
||||
HelpText<"Bind default visibility defined STB_GLOBAL function symbols locally for -shared">;
|
||||
|
||||
def Bdynamic: F<"Bdynamic">, HelpText<"Link against shared libraries (default)">;
|
||||
|
||||
def Bstatic: F<"Bstatic">, HelpText<"Do not link against shared libraries">;
|
||||
|
@ -527,6 +527,13 @@ static SmallSet<SharedSymbol *, 4> getSymbolsAt(SharedSymbol &ss) {
|
||||
if (auto *alias = dyn_cast_or_null<SharedSymbol>(sym))
|
||||
ret.insert(alias);
|
||||
}
|
||||
|
||||
// The loop does not check SHT_GNU_verneed, so ret does not contain
|
||||
// non-default version symbols. If ss has a non-default version, ret won't
|
||||
// contain ss. Just add ss unconditionally. If a non-default version alias is
|
||||
// separately copy relocated, it and ss will have different addresses.
|
||||
// Fortunately this case is impractical and fails with GNU ld as well.
|
||||
ret.insert(&ss);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1496,9 +1496,9 @@ void ScriptParser::readAnonymousDeclaration() {
|
||||
std::vector<SymbolVersion> globals;
|
||||
std::tie(locals, globals) = readSymbols();
|
||||
for (const SymbolVersion &pat : locals)
|
||||
config->versionDefinitions[VER_NDX_LOCAL].patterns.push_back(pat);
|
||||
config->versionDefinitions[VER_NDX_LOCAL].localPatterns.push_back(pat);
|
||||
for (const SymbolVersion &pat : globals)
|
||||
config->versionDefinitions[VER_NDX_GLOBAL].patterns.push_back(pat);
|
||||
config->versionDefinitions[VER_NDX_GLOBAL].nonLocalPatterns.push_back(pat);
|
||||
|
||||
expect(";");
|
||||
}
|
||||
@ -1510,13 +1510,12 @@ void ScriptParser::readVersionDeclaration(StringRef verStr) {
|
||||
std::vector<SymbolVersion> locals;
|
||||
std::vector<SymbolVersion> globals;
|
||||
std::tie(locals, globals) = readSymbols();
|
||||
for (const SymbolVersion &pat : locals)
|
||||
config->versionDefinitions[VER_NDX_LOCAL].patterns.push_back(pat);
|
||||
|
||||
// Create a new version definition and add that to the global symbols.
|
||||
VersionDefinition ver;
|
||||
ver.name = verStr;
|
||||
ver.patterns = globals;
|
||||
ver.nonLocalPatterns = std::move(globals);
|
||||
ver.localPatterns = std::move(locals);
|
||||
ver.id = config->versionDefinitions.size();
|
||||
config->versionDefinitions.push_back(ver);
|
||||
|
||||
|
@ -134,9 +134,20 @@ static bool canBeVersioned(const Symbol &sym) {
|
||||
StringMap<std::vector<Symbol *>> &SymbolTable::getDemangledSyms() {
|
||||
if (!demangledSyms) {
|
||||
demangledSyms.emplace();
|
||||
std::string demangled;
|
||||
for (Symbol *sym : symVector)
|
||||
if (canBeVersioned(*sym))
|
||||
(*demangledSyms)[demangleItanium(sym->getName())].push_back(sym);
|
||||
if (canBeVersioned(*sym)) {
|
||||
StringRef name = sym->getName();
|
||||
size_t pos = name.find('@');
|
||||
if (pos == std::string::npos)
|
||||
demangled = demangleItanium(name);
|
||||
else if (pos + 1 == name.size() || name[pos + 1] == '@')
|
||||
demangled = demangleItanium(name.substr(0, pos));
|
||||
else
|
||||
demangled =
|
||||
(demangleItanium(name.substr(0, pos)) + name.substr(pos)).str();
|
||||
(*demangledSyms)[demangled].push_back(sym);
|
||||
}
|
||||
}
|
||||
return *demangledSyms;
|
||||
}
|
||||
@ -150,19 +161,29 @@ std::vector<Symbol *> SymbolTable::findByVersion(SymbolVersion ver) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<Symbol *> SymbolTable::findAllByVersion(SymbolVersion ver) {
|
||||
std::vector<Symbol *> SymbolTable::findAllByVersion(SymbolVersion ver,
|
||||
bool includeNonDefault) {
|
||||
std::vector<Symbol *> res;
|
||||
SingleStringMatcher m(ver.name);
|
||||
auto check = [&](StringRef name) {
|
||||
size_t pos = name.find('@');
|
||||
if (!includeNonDefault)
|
||||
return pos == StringRef::npos;
|
||||
return !(pos + 1 < name.size() && name[pos + 1] == '@');
|
||||
};
|
||||
|
||||
if (ver.isExternCpp) {
|
||||
for (auto &p : getDemangledSyms())
|
||||
if (m.match(p.first()))
|
||||
res.insert(res.end(), p.second.begin(), p.second.end());
|
||||
for (Symbol *sym : p.second)
|
||||
if (check(sym->getName()))
|
||||
res.push_back(sym);
|
||||
return res;
|
||||
}
|
||||
|
||||
for (Symbol *sym : symVector)
|
||||
if (canBeVersioned(*sym) && m.match(sym->getName()))
|
||||
if (canBeVersioned(*sym) && check(sym->getName()) &&
|
||||
m.match(sym->getName()))
|
||||
res.push_back(sym);
|
||||
return res;
|
||||
}
|
||||
@ -172,7 +193,7 @@ void SymbolTable::handleDynamicList() {
|
||||
for (SymbolVersion &ver : config->dynamicList) {
|
||||
std::vector<Symbol *> syms;
|
||||
if (ver.hasWildcard)
|
||||
syms = findAllByVersion(ver);
|
||||
syms = findAllByVersion(ver, /*includeNonDefault=*/true);
|
||||
else
|
||||
syms = findByVersion(ver);
|
||||
|
||||
@ -181,21 +202,13 @@ void SymbolTable::handleDynamicList() {
|
||||
}
|
||||
}
|
||||
|
||||
// Set symbol versions to symbols. This function handles patterns
|
||||
// containing no wildcard characters.
|
||||
void SymbolTable::assignExactVersion(SymbolVersion ver, uint16_t versionId,
|
||||
StringRef versionName) {
|
||||
if (ver.hasWildcard)
|
||||
return;
|
||||
|
||||
// Set symbol versions to symbols. This function handles patterns containing no
|
||||
// wildcard characters. Return false if no symbol definition matches ver.
|
||||
bool SymbolTable::assignExactVersion(SymbolVersion ver, uint16_t versionId,
|
||||
StringRef versionName,
|
||||
bool includeNonDefault) {
|
||||
// Get a list of symbols which we need to assign the version to.
|
||||
std::vector<Symbol *> syms = findByVersion(ver);
|
||||
if (syms.empty()) {
|
||||
if (!config->undefinedVersion)
|
||||
error("version script assignment of '" + versionName + "' to symbol '" +
|
||||
ver.name + "' failed: symbol not defined");
|
||||
return;
|
||||
}
|
||||
|
||||
auto getName = [](uint16_t ver) -> std::string {
|
||||
if (ver == VER_NDX_LOCAL)
|
||||
@ -207,10 +220,11 @@ void SymbolTable::assignExactVersion(SymbolVersion ver, uint16_t versionId,
|
||||
|
||||
// Assign the version.
|
||||
for (Symbol *sym : syms) {
|
||||
// Skip symbols containing version info because symbol versions
|
||||
// specified by symbol names take precedence over version scripts.
|
||||
// See parseSymbolVersion().
|
||||
if (sym->getName().contains('@'))
|
||||
// For a non-local versionId, skip symbols containing version info because
|
||||
// symbol versions specified by symbol names take precedence over version
|
||||
// scripts. See parseSymbolVersion().
|
||||
if (!includeNonDefault && versionId != VER_NDX_LOCAL &&
|
||||
sym->getName().contains('@'))
|
||||
continue;
|
||||
|
||||
// If the version has not been assigned, verdefIndex is -1. Use an arbitrary
|
||||
@ -225,13 +239,15 @@ void SymbolTable::assignExactVersion(SymbolVersion ver, uint16_t versionId,
|
||||
warn("attempt to reassign symbol '" + ver.name + "' of " +
|
||||
getName(sym->versionId) + " to " + getName(versionId));
|
||||
}
|
||||
return !syms.empty();
|
||||
}
|
||||
|
||||
void SymbolTable::assignWildcardVersion(SymbolVersion ver, uint16_t versionId) {
|
||||
void SymbolTable::assignWildcardVersion(SymbolVersion ver, uint16_t versionId,
|
||||
bool includeNonDefault) {
|
||||
// Exact matching takes precedence over fuzzy matching,
|
||||
// so we set a version to a symbol only if no version has been assigned
|
||||
// to the symbol. This behavior is compatible with GNU.
|
||||
for (Symbol *sym : findAllByVersion(ver))
|
||||
for (Symbol *sym : findAllByVersion(ver, includeNonDefault))
|
||||
if (sym->verdefIndex == UINT32_C(-1)) {
|
||||
sym->verdefIndex = 0;
|
||||
sym->versionId = versionId;
|
||||
@ -244,26 +260,60 @@ void SymbolTable::assignWildcardVersion(SymbolVersion ver, uint16_t versionId) {
|
||||
// script file, the script does not actually define any symbol version,
|
||||
// but just specifies symbols visibilities.
|
||||
void SymbolTable::scanVersionScript() {
|
||||
SmallString<128> buf;
|
||||
// First, we assign versions to exact matching symbols,
|
||||
// i.e. version definitions not containing any glob meta-characters.
|
||||
for (VersionDefinition &v : config->versionDefinitions)
|
||||
for (SymbolVersion &pat : v.patterns)
|
||||
assignExactVersion(pat, v.id, v.name);
|
||||
std::vector<Symbol *> syms;
|
||||
for (VersionDefinition &v : config->versionDefinitions) {
|
||||
auto assignExact = [&](SymbolVersion pat, uint16_t id, StringRef ver) {
|
||||
bool found =
|
||||
assignExactVersion(pat, id, ver, /*includeNonDefault=*/false);
|
||||
buf.clear();
|
||||
found |= assignExactVersion({(pat.name + "@" + v.name).toStringRef(buf),
|
||||
pat.isExternCpp, /*hasWildCard=*/false},
|
||||
id, ver, /*includeNonDefault=*/true);
|
||||
if (!found && !config->undefinedVersion)
|
||||
errorOrWarn("version script assignment of '" + ver + "' to symbol '" +
|
||||
pat.name + "' failed: symbol not defined");
|
||||
};
|
||||
for (SymbolVersion &pat : v.nonLocalPatterns)
|
||||
if (!pat.hasWildcard)
|
||||
assignExact(pat, v.id, v.name);
|
||||
for (SymbolVersion pat : v.localPatterns)
|
||||
if (!pat.hasWildcard)
|
||||
assignExact(pat, VER_NDX_LOCAL, "local");
|
||||
}
|
||||
|
||||
// Next, assign versions to wildcards that are not "*". Note that because the
|
||||
// last match takes precedence over previous matches, we iterate over the
|
||||
// definitions in the reverse order.
|
||||
for (VersionDefinition &v : llvm::reverse(config->versionDefinitions))
|
||||
for (SymbolVersion &pat : v.patterns)
|
||||
auto assignWildcard = [&](SymbolVersion pat, uint16_t id, StringRef ver) {
|
||||
assignWildcardVersion(pat, id, /*includeNonDefault=*/false);
|
||||
buf.clear();
|
||||
assignWildcardVersion({(pat.name + "@" + ver).toStringRef(buf),
|
||||
pat.isExternCpp, /*hasWildCard=*/true},
|
||||
id,
|
||||
/*includeNonDefault=*/true);
|
||||
};
|
||||
for (VersionDefinition &v : llvm::reverse(config->versionDefinitions)) {
|
||||
for (SymbolVersion &pat : v.nonLocalPatterns)
|
||||
if (pat.hasWildcard && pat.name != "*")
|
||||
assignWildcardVersion(pat, v.id);
|
||||
assignWildcard(pat, v.id, v.name);
|
||||
for (SymbolVersion &pat : v.localPatterns)
|
||||
if (pat.hasWildcard && pat.name != "*")
|
||||
assignWildcard(pat, VER_NDX_LOCAL, v.name);
|
||||
}
|
||||
|
||||
// Then, assign versions to "*". In GNU linkers they have lower priority than
|
||||
// other wildcards.
|
||||
for (VersionDefinition &v : config->versionDefinitions)
|
||||
for (SymbolVersion &pat : v.patterns)
|
||||
for (VersionDefinition &v : config->versionDefinitions) {
|
||||
for (SymbolVersion &pat : v.nonLocalPatterns)
|
||||
if (pat.hasWildcard && pat.name == "*")
|
||||
assignWildcardVersion(pat, v.id);
|
||||
assignWildcard(pat, v.id, v.name);
|
||||
for (SymbolVersion &pat : v.localPatterns)
|
||||
if (pat.hasWildcard && pat.name == "*")
|
||||
assignWildcard(pat, VER_NDX_LOCAL, v.name);
|
||||
}
|
||||
|
||||
// Symbol themselves might know their versions because symbols
|
||||
// can contain versions in the form of <name>@<version>.
|
||||
|
@ -65,12 +65,14 @@ class SymbolTable {
|
||||
|
||||
private:
|
||||
std::vector<Symbol *> findByVersion(SymbolVersion ver);
|
||||
std::vector<Symbol *> findAllByVersion(SymbolVersion ver);
|
||||
std::vector<Symbol *> findAllByVersion(SymbolVersion ver,
|
||||
bool includeNonDefault);
|
||||
|
||||
llvm::StringMap<std::vector<Symbol *>> &getDemangledSyms();
|
||||
void assignExactVersion(SymbolVersion ver, uint16_t versionId,
|
||||
StringRef versionName);
|
||||
void assignWildcardVersion(SymbolVersion ver, uint16_t versionId);
|
||||
bool assignExactVersion(SymbolVersion ver, uint16_t versionId,
|
||||
StringRef versionName, bool includeNonDefault);
|
||||
void assignWildcardVersion(SymbolVersion ver, uint16_t versionId,
|
||||
bool includeNonDefault);
|
||||
|
||||
// The order the global symbols are in is not defined. We can use an arbitrary
|
||||
// order, but it has to be reproducible. That is true even when cross linking.
|
||||
|
@ -208,6 +208,9 @@ OutputSection *Symbol::getOutputSection() const {
|
||||
// If a symbol name contains '@', the characters after that is
|
||||
// a symbol version name. This function parses that.
|
||||
void Symbol::parseSymbolVersion() {
|
||||
// Return if localized by a local: pattern in a version script.
|
||||
if (versionId == VER_NDX_LOCAL)
|
||||
return;
|
||||
StringRef s = getName();
|
||||
size_t pos = s.find('@');
|
||||
if (pos == 0 || pos == StringRef::npos)
|
||||
@ -368,8 +371,12 @@ bool elf::computeIsPreemptible(const Symbol &sym) {
|
||||
|
||||
// If -Bsymbolic or --dynamic-list is specified, or -Bsymbolic-functions is
|
||||
// specified and the symbol is STT_FUNC, the symbol is preemptible iff it is
|
||||
// in the dynamic list.
|
||||
if (config->symbolic || (config->bsymbolicFunctions && sym.isFunc()))
|
||||
// in the dynamic list. -Bsymbolic-non-weak-functions is a non-weak subset of
|
||||
// -Bsymbolic-functions.
|
||||
if (config->symbolic ||
|
||||
(config->bsymbolic == BsymbolicKind::Functions && sym.isFunc()) ||
|
||||
(config->bsymbolic == BsymbolicKind::NonWeakFunctions && sym.isFunc() &&
|
||||
sym.binding != STB_WEAK))
|
||||
return sym.inDynamicList;
|
||||
return true;
|
||||
}
|
||||
|
@ -1356,7 +1356,7 @@ template <class ELFT> void DynamicSection<ELFT>::finalizeContents() {
|
||||
// Set DT_FLAGS and DT_FLAGS_1.
|
||||
uint32_t dtFlags = 0;
|
||||
uint32_t dtFlags1 = 0;
|
||||
if (config->bsymbolic)
|
||||
if (config->bsymbolic == BsymbolicKind::All)
|
||||
dtFlags |= DF_SYMBOLIC;
|
||||
if (config->zGlobal)
|
||||
dtFlags1 |= DF_1_GLOBAL;
|
||||
|
@ -24,12 +24,90 @@ Non-comprehensive list of changes in this release
|
||||
ELF Improvements
|
||||
----------------
|
||||
|
||||
* ``-z start-stop-gc`` is now supported and becomes the default.
|
||||
(`D96914 <https://reviews.llvm.org/D96914>`_)
|
||||
(`rG6d2d3bd0 <https://reviews.llvm.org/rG6d2d3bd0a61f5fc7fd9f61f48bc30e9ca77cc619>`_)
|
||||
* ``--shuffle-sections=<seed>`` has been changed to ``--shuffle-sections=<section-glob>=<seed>``.
|
||||
If seed is -1, the matched input sections are reversed.
|
||||
(`D98445 <https://reviews.llvm.org/D98445>`_)
|
||||
(`D98679 <https://reviews.llvm.org/D98679>`_)
|
||||
* ``-Bsymbolic -Bsymbolic-functions`` has been changed to behave the same as ``-Bsymbolic-functions``. This matches GNU ld.
|
||||
(`D102461 <https://reviews.llvm.org/D102461>`_)
|
||||
* ``-Bno-symbolic`` has been added.
|
||||
(`D102461 <https://reviews.llvm.org/D102461>`_)
|
||||
* A new linker script command ``OVERWRITE_SECTIONS`` has been added.
|
||||
(`D103303 <https://reviews.llvm.org/D103303>`_)
|
||||
* ``-Bsymbolic-non-weak-functions`` has been added as a ``STB_GLOBAL`` subset of ``-Bsymbolic-functions``.
|
||||
(`D102570 <https://reviews.llvm.org/D102570>`_)
|
||||
* ``--no-allow-shlib-undefined`` has been improved to catch more cases.
|
||||
(`D101996 <https://reviews.llvm.org/D101996>`_)
|
||||
* ``__rela_iplt_start`` is no longer defined for -pie/-shared.
|
||||
This makes GCC/Clang ``-static-pie`` built executables work.
|
||||
(`rG8cb78e99 <https://reviews.llvm.org/rf8cb78e99aae9aa3f89f7bfe667db2c5b767f21f>`_)
|
||||
* IRELATIVE/TLSDESC relocations now support ``-z rel``.
|
||||
(`D100544 <https://reviews.llvm.org/D100544>`_)
|
||||
* Section groups with a zero flag are now supported.
|
||||
This is used by ``comdat nodeduplicate`` in LLVM IR.
|
||||
(`D96636 <https://reviews.llvm.org/D96636>`_)
|
||||
(`D106228 <https://reviews.llvm.org/D106228>`_)
|
||||
* Defined symbols are now resolved before undefined symbols to stabilize the bheavior of archive member extraction.
|
||||
(`D95985 <https://reviews.llvm.org/D95985>`_)
|
||||
* ``STB_WEAK`` symbols are now preferred over COMMON symbols as a fix to a ``--fortran-common`` regression.
|
||||
(`D105945 <https://reviews.llvm.org/D105945>`_)
|
||||
* Absolute relocations referencing undef weak now produce dynamic relocations for -pie, matching GOT-generating relocations.
|
||||
(`D105164 <https://reviews.llvm.org/D105164>`_)
|
||||
* Exported symbols are now communicated to the LTO library so as to make LTO
|
||||
based whole program devirtualization (``-flto=thin -fwhole-program-vtables``)
|
||||
work with shared objects.
|
||||
(`D91583 <https://reviews.llvm.org/D91583>`_)
|
||||
* Whole program devirtualization now respects ``local:`` version nodes in a version script.
|
||||
(`D98220 <https://reviews.llvm.org/D98220>`_)
|
||||
(`D98686 <https://reviews.llvm.org/D98686>`_)
|
||||
* ``local:`` version nodes in a version script now apply to non-default version symbols.
|
||||
(`D107234 <https://reviews.llvm.org/D107234>`_)
|
||||
* If an object file defines both ``foo`` and ``foo@v1``, now only ``foo@v1`` will be in the output.
|
||||
(`D107235 <https://reviews.llvm.org/D107235>`_)
|
||||
* Copy relocations on non-default version symbols are now supported.
|
||||
(`D107535 <https://reviews.llvm.org/D107535>`_)
|
||||
|
||||
Linker script changes:
|
||||
|
||||
* ``.``, ``$``, and double quotes can now be used in symbol names in expressions.
|
||||
(`D98306 <https://reviews.llvm.org/D98306>`_)
|
||||
(`rGe7a7ad13 <https://reviews.llvm.org/rGe7a7ad134fe182aad190cb3ebc441164470e92f5>`_)
|
||||
* Fixed value of ``.`` in the output section description of ``.tbss``.
|
||||
(`D107288 <https://reviews.llvm.org/D107288>`_)
|
||||
* ``NOLOAD`` sections can now be placed in a ``PT_LOAD`` program header.
|
||||
(`D103815 <https://reviews.llvm.org/D103815>`_)
|
||||
* ``OUTPUT_FORMAT(default, big, little)`` now consults ``-EL`` and ``-EB``.
|
||||
(`D96214 <https://reviews.llvm.org/D96214>`_)
|
||||
* The ``OVERWRITE_SECTIONS`` command has been added.
|
||||
(`D103303 <https://reviews.llvm.org/D103303>`_)
|
||||
* The section order within an ``INSERT AFTER`` command is now preserved.
|
||||
(`D105158 <https://reviews.llvm.org/D105158>`_)
|
||||
|
||||
Architecture specific changes:
|
||||
|
||||
* aarch64_be is now supported.
|
||||
(`D96188 <https://reviews.llvm.org/D96188>`_)
|
||||
* The AMDGPU port now supports ``--amdhsa-code-object-version=4`` object files;
|
||||
(`D95811 <https://reviews.llvm.org/D95811>`_)
|
||||
* The ARM port now accounts for PC biases in range extension thunk creation.
|
||||
(`D97550 <https://reviews.llvm.org/D97550>`_)
|
||||
* The AVR port now computes ``e_flags``.
|
||||
(`D99754 <https://reviews.llvm.org/D99754>`_)
|
||||
* The Mips port now omits unneeded dynamic relocations for PIE non-preemptible TLS.
|
||||
(`D101382 <https://reviews.llvm.org/D101382>`_)
|
||||
* The PowerPC port now supports ``--power10-stubs=no`` to omit Power10 instructions from call stubs.
|
||||
(`D94625 <https://reviews.llvm.org/D94625>`_)
|
||||
* Fixed a thunk creation bug in the PowerPC port when TOC/NOTOC calls are mixed.
|
||||
(`D101837 <https://reviews.llvm.org/D101837>`_)
|
||||
* The RISC-V port now resolves undefined weak relocations to the current location if not using PLT.
|
||||
(`D103001 <https://reviews.llvm.org/D103001>`_)
|
||||
* ``R_386_GOTOFF`` relocations from .debug_info are now allowed to be compatible with GCC.
|
||||
(`D95994 <https://reviews.llvm.org/D95994>`_)
|
||||
* ``gotEntrySize`` has been added to improve support for the ILP32 ABI of x86-64.
|
||||
(`D102569 <https://reviews.llvm.org/D102569>`_)
|
||||
|
||||
Breaking changes
|
||||
----------------
|
||||
@ -40,17 +118,75 @@ Breaking changes
|
||||
COFF Improvements
|
||||
-----------------
|
||||
|
||||
* ...
|
||||
* Avoid thread exhaustion when running on 32 bit Windows.
|
||||
(`D105506 <https://reviews.llvm.org/D105506>`_)
|
||||
|
||||
* Improve terminating the process on Windows while a thread pool might be
|
||||
running. (`D102944 <https://reviews.llvm.org/D102944>`_)
|
||||
|
||||
MinGW Improvements
|
||||
------------------
|
||||
|
||||
* ...
|
||||
* Support for linking directly against a DLL without using an import library
|
||||
has been added. (`D104530 <https://reviews.llvm.org/D104530>`_ and
|
||||
`D104531 <https://reviews.llvm.org/D104531>`_)
|
||||
|
||||
MachO Improvements
|
||||
------------------
|
||||
* Fix linking with ``--export-all-symbols`` in combination with
|
||||
``-function-sections``. (`D101522 <https://reviews.llvm.org/D101522>`_ and
|
||||
`D101615 <https://reviews.llvm.org/D101615>`_)
|
||||
|
||||
* Item 1.
|
||||
* Fix automatic export of symbols from LTO objects.
|
||||
(`D101569 <https://reviews.llvm.org/D101569>`_)
|
||||
|
||||
* Accept more spellings of some options.
|
||||
(`D107237 <https://reviews.llvm.org/D107237>`_ and
|
||||
`D107253 <https://reviews.llvm.org/D107253>`_)
|
||||
|
||||
Mach-O Improvements
|
||||
-------------------
|
||||
|
||||
The Mach-O backend is now able to link several large, real-world programs,
|
||||
though we are still working out the kinks.
|
||||
|
||||
* arm64 is now supported as a target. (`D88629 <https://reviews.llvm.org/D88629>`_)
|
||||
* arm64_32 is now supported as a target. (`D99822 <https://reviews.llvm.org/D99822>`_)
|
||||
* Branch-range-extension thunks are now supported. (`D100818 <https://reviews.llvm.org/D100818>`_)
|
||||
* ``-dead_strip`` is now supported. (`D103324 <https://reviews.llvm.org/D103324>`_)
|
||||
* Support for identical code folding (``--icf=all``) has been added.
|
||||
(`D103292 <https://reviews.llvm.org/D103292>`_)
|
||||
* Support for special ``$start`` and ``$end`` symbols for segment & sections has been
|
||||
added. (`D106767 <https://reviews.llvm.org/D106767>`_, `D106629 <https://reviews.llvm.org/D106629>`_)
|
||||
* ``$ld$previous`` symbols are now supported. (`D103505 <https://reviews.llvm.org/D103505 >`_)
|
||||
* ``$ld$install_name`` symbols are now supported. (`D103746 <https://reviews.llvm.org/D103746>`_)
|
||||
* ``__mh_*_header`` symbols are now supported. (`D97007 <https://reviews.llvm.org/D97007>`_)
|
||||
* LC_CODE_SIGNATURE is now supported. (`D96164 <https://reviews.llvm.org/D96164>`_)
|
||||
* LC_FUNCTION_STARTS is now supported. (`D97260 <https://reviews.llvm.org/D97260>`_)
|
||||
* LC_DATA_IN_CODE is now supported. (`D103006 <https://reviews.llvm.org/D103006>`_)
|
||||
* Bind opcodes are more compactly encoded. (`D106128 <https://reviews.llvm.org/D106128>`_,
|
||||
`D105075 <https://reviews.llvm.org/D105075>`_)
|
||||
* LTO cache support has been added. (`D105922 <https://reviews.llvm.org/D105922>`_)
|
||||
* ``-application_extension`` is now supported. (`D105818 <https://reviews.llvm.org/D105818>`_)
|
||||
* ``-export_dynamic`` is now partially supported. (`D105482 <https://reviews.llvm.org/D105482>`_)
|
||||
* ``-arch_multiple`` is now supported. (`D105450 <https://reviews.llvm.org/D105450>`_)
|
||||
* ``-final_output`` is now supported. (`D105449 <https://reviews.llvm.org/D105449>`_)
|
||||
* ``-umbrella`` is now supported. (`D105448 <https://reviews.llvm.org/D105448>`_)
|
||||
* ``--print-dylib-search`` is now supported. (`D103985 <https://reviews.llvm.org/D103985>`_)
|
||||
* ``-force_load_swift_libs`` is now supported. (`D103709 <https://reviews.llvm.org/D103709>`_)
|
||||
* ``-reexport_framework``, ``-reexport_library``, ``-reexport-l`` are now supported.
|
||||
(`D103497 <https://reviews.llvm.org/D103497>`_)
|
||||
* ``.weak_def_can_be_hidden`` is now supported. (`D101080 <https://reviews.llvm.org/D101080>`_)
|
||||
* ``-add_ast_path`` is now supported. (`D100076 <https://reviews.llvm.org/D100076>`_)
|
||||
* ``-segprot`` is now supported. (`D99389 <https://reviews.llvm.org/D99389>`_)
|
||||
* ``-dependency_info`` is now partially supported. (`D98559 <https://reviews.llvm.org/D98559>`_)
|
||||
* ``--time-trace`` is now supported. (`D98419 <https://reviews.llvm.org/D98419>`_)
|
||||
* ``-mark_dead_strippable_dylib`` is now supported. (`D98262 <https://reviews.llvm.org/D98262>`_)
|
||||
* ``-[un]exported_symbol[s_list]`` is now supported. (`D98223 <https://reviews.llvm.org/D98223>`_)
|
||||
* ``-flat_namespace`` is now supported. (`D97641 <https://reviews.llvm.org/D97641>`_)
|
||||
* ``-rename_section`` and ``-rename_segment`` are now supported. (`D97600 <https://reviews.llvm.org/D97600>`_)
|
||||
* ``-bundle_loader`` is now supported. (`D95913 <https://reviews.llvm.org/D95913>`_)
|
||||
* ``-map`` is now partially supported. (`D98323 <https://reviews.llvm.org/D98323>`_)
|
||||
|
||||
There were numerous other bug-fixes as well.
|
||||
|
||||
WebAssembly Improvements
|
||||
------------------------
|
||||
|
@ -85,6 +85,9 @@ flag.
|
||||
.It Fl Bsymbolic-functions
|
||||
Bind default visibility defined function symbols locally for
|
||||
.Fl shared.
|
||||
.It Fl Bsymbolic-non-weak-functions
|
||||
Bind default visibility defined STB_GLOBAL function symbols locally for
|
||||
.Fl shared.
|
||||
.It Fl -build-id Ns = Ns Ar value
|
||||
Generate a build ID note.
|
||||
.Ar value
|
||||
|
@ -7,8 +7,11 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "CommandObjectMemoryTag.h"
|
||||
#include "lldb/Host/OptionParser.h"
|
||||
#include "lldb/Interpreter/CommandReturnObject.h"
|
||||
#include "lldb/Interpreter/OptionArgParser.h"
|
||||
#include "lldb/Interpreter/OptionGroupFormat.h"
|
||||
#include "lldb/Interpreter/OptionValueString.h"
|
||||
#include "lldb/Target/Process.h"
|
||||
|
||||
using namespace lldb;
|
||||
@ -21,7 +24,8 @@ class CommandObjectMemoryTagRead : public CommandObjectParsed {
|
||||
public:
|
||||
CommandObjectMemoryTagRead(CommandInterpreter &interpreter)
|
||||
: CommandObjectParsed(interpreter, "tag",
|
||||
"Read memory tags for the given range of memory.",
|
||||
"Read memory tags for the given range of memory."
|
||||
" Mismatched tags will be marked.",
|
||||
nullptr,
|
||||
eCommandRequiresTarget | eCommandRequiresProcess |
|
||||
eCommandProcessMustBePaused) {
|
||||
@ -97,16 +101,17 @@ class CommandObjectMemoryTagRead : public CommandObjectParsed {
|
||||
return false;
|
||||
}
|
||||
|
||||
result.AppendMessageWithFormatv("Logical tag: {0:x}",
|
||||
tag_manager->GetLogicalTag(start_addr));
|
||||
lldb::addr_t logical_tag = tag_manager->GetLogicalTag(start_addr);
|
||||
result.AppendMessageWithFormatv("Logical tag: {0:x}", logical_tag);
|
||||
result.AppendMessage("Allocation tags:");
|
||||
|
||||
addr_t addr = tagged_range->GetRangeBase();
|
||||
for (auto tag : *tags) {
|
||||
addr_t next_addr = addr + tag_manager->GetGranuleSize();
|
||||
// Showing tagged adresses here until we have non address bit handling
|
||||
result.AppendMessageWithFormatv("[{0:x}, {1:x}): {2:x}", addr, next_addr,
|
||||
tag);
|
||||
result.AppendMessageWithFormatv("[{0:x}, {1:x}): {2:x}{3}", addr,
|
||||
next_addr, tag,
|
||||
logical_tag == tag ? "" : " (mismatch)");
|
||||
addr = next_addr;
|
||||
}
|
||||
|
||||
@ -115,6 +120,168 @@ class CommandObjectMemoryTagRead : public CommandObjectParsed {
|
||||
}
|
||||
};
|
||||
|
||||
#define LLDB_OPTIONS_memory_tag_write
|
||||
#include "CommandOptions.inc"
|
||||
|
||||
class CommandObjectMemoryTagWrite : public CommandObjectParsed {
|
||||
public:
|
||||
class OptionGroupTagWrite : public OptionGroup {
|
||||
public:
|
||||
OptionGroupTagWrite() : OptionGroup(), m_end_addr(LLDB_INVALID_ADDRESS) {}
|
||||
|
||||
~OptionGroupTagWrite() override = default;
|
||||
|
||||
llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
|
||||
return llvm::makeArrayRef(g_memory_tag_write_options);
|
||||
}
|
||||
|
||||
Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
|
||||
ExecutionContext *execution_context) override {
|
||||
Status status;
|
||||
const int short_option =
|
||||
g_memory_tag_write_options[option_idx].short_option;
|
||||
|
||||
switch (short_option) {
|
||||
case 'e':
|
||||
m_end_addr = OptionArgParser::ToAddress(execution_context, option_value,
|
||||
LLDB_INVALID_ADDRESS, &status);
|
||||
break;
|
||||
default:
|
||||
llvm_unreachable("Unimplemented option");
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
void OptionParsingStarting(ExecutionContext *execution_context) override {
|
||||
m_end_addr = LLDB_INVALID_ADDRESS;
|
||||
}
|
||||
|
||||
lldb::addr_t m_end_addr;
|
||||
};
|
||||
|
||||
CommandObjectMemoryTagWrite(CommandInterpreter &interpreter)
|
||||
: CommandObjectParsed(interpreter, "tag",
|
||||
"Write memory tags starting from the granule that "
|
||||
"contains the given address.",
|
||||
nullptr,
|
||||
eCommandRequiresTarget | eCommandRequiresProcess |
|
||||
eCommandProcessMustBePaused),
|
||||
m_option_group(), m_tag_write_options() {
|
||||
// Address
|
||||
m_arguments.push_back(
|
||||
CommandArgumentEntry{CommandArgumentData(eArgTypeAddressOrExpression)});
|
||||
// One or more tag values
|
||||
m_arguments.push_back(CommandArgumentEntry{
|
||||
CommandArgumentData(eArgTypeValue, eArgRepeatPlus)});
|
||||
|
||||
m_option_group.Append(&m_tag_write_options);
|
||||
m_option_group.Finalize();
|
||||
}
|
||||
|
||||
~CommandObjectMemoryTagWrite() override = default;
|
||||
|
||||
Options *GetOptions() override { return &m_option_group; }
|
||||
|
||||
protected:
|
||||
bool DoExecute(Args &command, CommandReturnObject &result) override {
|
||||
if (command.GetArgumentCount() < 2) {
|
||||
result.AppendError("wrong number of arguments; expected "
|
||||
"<address-expression> <tag> [<tag> [...]]");
|
||||
return false;
|
||||
}
|
||||
|
||||
Status error;
|
||||
addr_t start_addr = OptionArgParser::ToAddress(
|
||||
&m_exe_ctx, command[0].ref(), LLDB_INVALID_ADDRESS, &error);
|
||||
if (start_addr == LLDB_INVALID_ADDRESS) {
|
||||
result.AppendErrorWithFormatv("Invalid address expression, {0}",
|
||||
error.AsCString());
|
||||
return false;
|
||||
}
|
||||
|
||||
command.Shift(); // shift off start address
|
||||
|
||||
std::vector<lldb::addr_t> tags;
|
||||
for (auto &entry : command) {
|
||||
lldb::addr_t tag_value;
|
||||
// getAsInteger returns true on failure
|
||||
if (entry.ref().getAsInteger(0, tag_value)) {
|
||||
result.AppendErrorWithFormat(
|
||||
"'%s' is not a valid unsigned decimal string value.\n",
|
||||
entry.c_str());
|
||||
return false;
|
||||
}
|
||||
tags.push_back(tag_value);
|
||||
}
|
||||
|
||||
Process *process = m_exe_ctx.GetProcessPtr();
|
||||
llvm::Expected<const MemoryTagManager *> tag_manager_or_err =
|
||||
process->GetMemoryTagManager();
|
||||
|
||||
if (!tag_manager_or_err) {
|
||||
result.SetError(Status(tag_manager_or_err.takeError()));
|
||||
return false;
|
||||
}
|
||||
|
||||
const MemoryTagManager *tag_manager = *tag_manager_or_err;
|
||||
|
||||
MemoryRegionInfos memory_regions;
|
||||
// If this fails the list of regions is cleared, so we don't need to read
|
||||
// the return status here.
|
||||
process->GetMemoryRegions(memory_regions);
|
||||
|
||||
// We have to assume start_addr is not granule aligned.
|
||||
// So if we simply made a range:
|
||||
// (start_addr, start_addr + (N * granule_size))
|
||||
// We would end up with a range that isn't N granules but N+1
|
||||
// granules. To avoid this we'll align the start first using the method that
|
||||
// doesn't check memory attributes. (if the final range is untagged we'll
|
||||
// handle that error later)
|
||||
lldb::addr_t aligned_start_addr =
|
||||
tag_manager->ExpandToGranule(MemoryTagManager::TagRange(start_addr, 1))
|
||||
.GetRangeBase();
|
||||
|
||||
lldb::addr_t end_addr = 0;
|
||||
// When you have an end address you want to align the range like tag read
|
||||
// does. Meaning, align the start down (which we've done) and align the end
|
||||
// up.
|
||||
if (m_tag_write_options.m_end_addr != LLDB_INVALID_ADDRESS)
|
||||
end_addr = m_tag_write_options.m_end_addr;
|
||||
else
|
||||
// Without an end address assume number of tags matches number of granules
|
||||
// to write to
|
||||
end_addr =
|
||||
aligned_start_addr + (tags.size() * tag_manager->GetGranuleSize());
|
||||
|
||||
// Now we've aligned the start address so if we ask for another range
|
||||
// using the number of tags N, we'll get back a range that is also N
|
||||
// granules in size.
|
||||
llvm::Expected<MemoryTagManager::TagRange> tagged_range =
|
||||
tag_manager->MakeTaggedRange(aligned_start_addr, end_addr,
|
||||
memory_regions);
|
||||
|
||||
if (!tagged_range) {
|
||||
result.SetError(Status(tagged_range.takeError()));
|
||||
return false;
|
||||
}
|
||||
|
||||
Status status = process->WriteMemoryTags(tagged_range->GetRangeBase(),
|
||||
tagged_range->GetByteSize(), tags);
|
||||
|
||||
if (status.Fail()) {
|
||||
result.SetError(status);
|
||||
return false;
|
||||
}
|
||||
|
||||
result.SetStatus(eReturnStatusSuccessFinishResult);
|
||||
return true;
|
||||
}
|
||||
|
||||
OptionGroupOptions m_option_group;
|
||||
OptionGroupTagWrite m_tag_write_options;
|
||||
};
|
||||
|
||||
CommandObjectMemoryTag::CommandObjectMemoryTag(CommandInterpreter &interpreter)
|
||||
: CommandObjectMultiword(
|
||||
interpreter, "tag", "Commands for manipulating memory tags",
|
||||
@ -123,6 +290,11 @@ CommandObjectMemoryTag::CommandObjectMemoryTag(CommandInterpreter &interpreter)
|
||||
new CommandObjectMemoryTagRead(interpreter));
|
||||
read_command_object->SetCommandName("memory tag read");
|
||||
LoadSubCommand("read", read_command_object);
|
||||
|
||||
CommandObjectSP write_command_object(
|
||||
new CommandObjectMemoryTagWrite(interpreter));
|
||||
write_command_object->SetCommandName("memory tag write");
|
||||
LoadSubCommand("write", write_command_object);
|
||||
}
|
||||
|
||||
CommandObjectMemoryTag::~CommandObjectMemoryTag() = default;
|
||||
|
@ -504,6 +504,14 @@ let Command = "memory write" in {
|
||||
Desc<"Start writing bytes from an offset within the input file.">;
|
||||
}
|
||||
|
||||
let Command = "memory tag write" in {
|
||||
def memory_write_end_addr : Option<"end-addr", "e">, Group<1>,
|
||||
Arg<"AddressOrExpression">, Desc<
|
||||
"Set tags for start address to end-addr, repeating tags as needed"
|
||||
" to cover the range. (instead of calculating the range from the"
|
||||
" number of tags given)">;
|
||||
}
|
||||
|
||||
let Command = "register read" in {
|
||||
def register_read_alternate : Option<"alternate", "A">,
|
||||
Desc<"Display register names using the alternate register name if there "
|
||||
|
@ -3474,15 +3474,31 @@ GDBRemoteCommunicationServerLLGS::Handle_qMemTags(
|
||||
if (packet.GetBytesLeft() < 1 || packet.GetChar() != ':')
|
||||
return SendIllFormedResponse(packet, invalid_type_err);
|
||||
|
||||
int32_t type =
|
||||
packet.GetS32(std::numeric_limits<int32_t>::max(), /*base=*/16);
|
||||
if (type == std::numeric_limits<int32_t>::max() ||
|
||||
// Type is a signed integer but packed into the packet as its raw bytes.
|
||||
// However, our GetU64 uses strtoull which allows +/-. We do not want this.
|
||||
const char *first_type_char = packet.Peek();
|
||||
if (first_type_char && (*first_type_char == '+' || *first_type_char == '-'))
|
||||
return SendIllFormedResponse(packet, invalid_type_err);
|
||||
|
||||
// Extract type as unsigned then cast to signed.
|
||||
// Using a uint64_t here so that we have some value outside of the 32 bit
|
||||
// range to use as the invalid return value.
|
||||
uint64_t raw_type =
|
||||
packet.GetU64(std::numeric_limits<uint64_t>::max(), /*base=*/16);
|
||||
|
||||
if ( // Make sure the cast below would be valid
|
||||
raw_type > std::numeric_limits<uint32_t>::max() ||
|
||||
// To catch inputs like "123aardvark" that will parse but clearly aren't
|
||||
// valid in this case.
|
||||
packet.GetBytesLeft()) {
|
||||
return SendIllFormedResponse(packet, invalid_type_err);
|
||||
}
|
||||
|
||||
// First narrow to 32 bits otherwise the copy into type would take
|
||||
// the wrong 4 bytes on big endian.
|
||||
uint32_t raw_type_32 = raw_type;
|
||||
int32_t type = reinterpret_cast<int32_t &>(raw_type_32);
|
||||
|
||||
StreamGDBRemote response;
|
||||
std::vector<uint8_t> tags;
|
||||
Status error = m_current_process->ReadMemoryTags(type, addr, length, tags);
|
||||
@ -3552,7 +3568,11 @@ GDBRemoteCommunicationServerLLGS::Handle_QMemTags(
|
||||
packet.GetU64(std::numeric_limits<uint64_t>::max(), /*base=*/16);
|
||||
if (raw_type > std::numeric_limits<uint32_t>::max())
|
||||
return SendIllFormedResponse(packet, invalid_type_err);
|
||||
int32_t type = static_cast<int32_t>(raw_type);
|
||||
|
||||
// First narrow to 32 bits. Otherwise the copy below would get the wrong
|
||||
// 4 bytes on big endian.
|
||||
uint32_t raw_type_32 = raw_type;
|
||||
int32_t type = reinterpret_cast<int32_t &>(raw_type_32);
|
||||
|
||||
// Tag data
|
||||
if (packet.GetBytesLeft() < 1 || packet.GetChar() != ':')
|
||||
|
@ -744,6 +744,10 @@ constexpr unsigned MaxAnalysisRecursionDepth = 6;
|
||||
/// minimum/maximum flavor.
|
||||
CmpInst::Predicate getInverseMinMaxPred(SelectPatternFlavor SPF);
|
||||
|
||||
/// Return the minimum or maximum constant value for the specified integer
|
||||
/// min/max flavor and type.
|
||||
APInt getMinMaxLimit(SelectPatternFlavor SPF, unsigned BitWidth);
|
||||
|
||||
/// Check if the values in \p VL are select instructions that can be converted
|
||||
/// to a min or max (vector) intrinsic. Returns the intrinsic ID, if such a
|
||||
/// conversion is possible, together with a bool indicating whether all select
|
||||
|
@ -1396,6 +1396,11 @@ class TargetLoweringBase {
|
||||
return NVT;
|
||||
}
|
||||
|
||||
virtual EVT getAsmOperandValueType(const DataLayout &DL, Type *Ty,
|
||||
bool AllowUnknown = false) const {
|
||||
return getValueType(DL, Ty, AllowUnknown);
|
||||
}
|
||||
|
||||
/// Return the EVT corresponding to this LLVM type. This is fixed by the LLVM
|
||||
/// operations except for the pointer size. If AllowUnknown is true, this
|
||||
/// will return MVT::Other for types with no EVT counterpart (e.g. structs),
|
||||
|
@ -216,6 +216,7 @@ def untyped : ValueType<8, 174>; // Produces an untyped value
|
||||
def funcref : ValueType<0, 175>; // WebAssembly's funcref type
|
||||
def externref : ValueType<0, 176>; // WebAssembly's externref type
|
||||
def x86amx : ValueType<8192, 177>; // X86 AMX value
|
||||
def i64x8 : ValueType<512, 178>; // 8 Consecutive GPRs (AArch64)
|
||||
|
||||
|
||||
def token : ValueType<0, 248>; // TokenTy
|
||||
|
@ -324,6 +324,9 @@ class Module {
|
||||
/// name is not found.
|
||||
GlobalValue *getNamedValue(StringRef Name) const;
|
||||
|
||||
/// Return the number of global values in the module.
|
||||
unsigned getNumNamedValues() const;
|
||||
|
||||
/// Return a unique non-zero ID for the specified metadata kind. This ID is
|
||||
/// uniqued across modules in the current LLVMContext.
|
||||
unsigned getMDKindID(StringRef Name) const;
|
||||
|
@ -1104,6 +1104,7 @@ namespace RawInstrProf {
|
||||
// Version 5: Bit 60 of FuncHash is reserved for the flag for the context
|
||||
// sensitive records.
|
||||
// Version 6: Added binary id.
|
||||
// Version 7: Reorder binary id and include version in signature.
|
||||
const uint64_t Version = INSTR_PROF_RAW_VERSION;
|
||||
|
||||
template <class IntPtrT> inline uint64_t getMagic();
|
||||
|
@ -129,6 +129,7 @@ INSTR_PROF_VALUE_NODE(PtrToNodeT, llvm::Type::getInt8PtrTy(Ctx), Next, \
|
||||
#endif
|
||||
INSTR_PROF_RAW_HEADER(uint64_t, Magic, __llvm_profile_get_magic())
|
||||
INSTR_PROF_RAW_HEADER(uint64_t, Version, __llvm_profile_get_version())
|
||||
INSTR_PROF_RAW_HEADER(uint64_t, BinaryIdsSize, __llvm_write_binary_ids(NULL))
|
||||
INSTR_PROF_RAW_HEADER(uint64_t, DataSize, DataSize)
|
||||
INSTR_PROF_RAW_HEADER(uint64_t, PaddingBytesBeforeCounters, PaddingBytesBeforeCounters)
|
||||
INSTR_PROF_RAW_HEADER(uint64_t, CountersSize, CountersSize)
|
||||
@ -137,7 +138,6 @@ INSTR_PROF_RAW_HEADER(uint64_t, NamesSize, NamesSize)
|
||||
INSTR_PROF_RAW_HEADER(uint64_t, CountersDelta, (uintptr_t)CountersBegin)
|
||||
INSTR_PROF_RAW_HEADER(uint64_t, NamesDelta, (uintptr_t)NamesBegin)
|
||||
INSTR_PROF_RAW_HEADER(uint64_t, ValueKindLast, IPVK_Last)
|
||||
INSTR_PROF_RAW_HEADER(uint64_t, BinaryIdsSize, __llvm_write_binary_ids(NULL))
|
||||
#undef INSTR_PROF_RAW_HEADER
|
||||
/* INSTR_PROF_RAW_HEADER end */
|
||||
|
||||
@ -646,7 +646,7 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
|
||||
(uint64_t)'f' << 16 | (uint64_t)'R' << 8 | (uint64_t)129
|
||||
|
||||
/* Raw profile format version (start from 1). */
|
||||
#define INSTR_PROF_RAW_VERSION 6
|
||||
#define INSTR_PROF_RAW_VERSION 7
|
||||
/* Indexed profile format version (start from 1). */
|
||||
#define INSTR_PROF_INDEX_VERSION 7
|
||||
/* Coverage mapping format version (start from 0). */
|
||||
|
@ -270,9 +270,10 @@ namespace llvm {
|
||||
funcref = 175, // WebAssembly's funcref type
|
||||
externref = 176, // WebAssembly's externref type
|
||||
x86amx = 177, // This is an X86 AMX value
|
||||
i64x8 = 178, // 8 Consecutive GPRs (AArch64)
|
||||
|
||||
FIRST_VALUETYPE = 1, // This is always the beginning of the list.
|
||||
LAST_VALUETYPE = x86amx, // This always remains at the end of the list.
|
||||
LAST_VALUETYPE = i64x8, // This always remains at the end of the list.
|
||||
VALUETYPE_SIZE = LAST_VALUETYPE + 1,
|
||||
|
||||
// This is the current maximum for LAST_VALUETYPE.
|
||||
@ -987,6 +988,7 @@ namespace llvm {
|
||||
case nxv16f16:
|
||||
case nxv8f32:
|
||||
case nxv4f64: return TypeSize::Scalable(256);
|
||||
case i64x8:
|
||||
case v512i1:
|
||||
case v64i8:
|
||||
case v32i16:
|
||||
|
@ -1855,6 +1855,10 @@ struct Attributor {
|
||||
///
|
||||
static void createShallowWrapper(Function &F);
|
||||
|
||||
/// Returns true if the function \p F can be internalized. i.e. it has a
|
||||
/// compatible linkage.
|
||||
static bool isInternalizable(Function &F);
|
||||
|
||||
/// Make another copy of the function \p F such that the copied version has
|
||||
/// internal linkage afterwards and can be analysed. Then we replace all uses
|
||||
/// of the original function to the copied one
|
||||
@ -1870,6 +1874,22 @@ struct Attributor {
|
||||
/// null pointer.
|
||||
static Function *internalizeFunction(Function &F, bool Force = false);
|
||||
|
||||
/// Make copies of each function in the set \p FnSet such that the copied
|
||||
/// version has internal linkage afterwards and can be analysed. Then we
|
||||
/// replace all uses of the original function to the copied one. The map
|
||||
/// \p FnMap contains a mapping of functions to their internalized versions.
|
||||
///
|
||||
/// Only non-locally linked functions that have `linkonce_odr` or `weak_odr`
|
||||
/// linkage can be internalized because these linkages guarantee that other
|
||||
/// definitions with the same name have the same semantics as this one.
|
||||
///
|
||||
/// This version will internalize all the functions in the set \p FnSet at
|
||||
/// once and then replace the uses. This prevents internalized functions being
|
||||
/// called by external functions when there is an internalized version in the
|
||||
/// module.
|
||||
static bool internalizeFunctions(SmallPtrSetImpl<Function *> &FnSet,
|
||||
DenseMap<Function *, Function *> &FnMap);
|
||||
|
||||
/// Return the data layout associated with the anchor scope.
|
||||
const DataLayout &getDataLayout() const { return InfoCache.DL; }
|
||||
|
||||
|
@ -51,11 +51,13 @@
|
||||
#define LLVM_TRANSFORMS_UTILS_PREDICATEINFO_H
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/SmallSet.h"
|
||||
#include "llvm/ADT/ilist.h"
|
||||
#include "llvm/ADT/ilist_node.h"
|
||||
#include "llvm/IR/Instructions.h"
|
||||
#include "llvm/IR/PassManager.h"
|
||||
#include "llvm/IR/Value.h"
|
||||
#include "llvm/IR/ValueHandle.h"
|
||||
#include "llvm/Pass.h"
|
||||
|
||||
namespace llvm {
|
||||
@ -176,7 +178,7 @@ class PredicateSwitch : public PredicateWithEdge {
|
||||
class PredicateInfo {
|
||||
public:
|
||||
PredicateInfo(Function &, DominatorTree &, AssumptionCache &);
|
||||
~PredicateInfo() = default;
|
||||
~PredicateInfo();
|
||||
|
||||
void verifyPredicateInfo() const;
|
||||
|
||||
@ -203,6 +205,8 @@ class PredicateInfo {
|
||||
// the Predicate Info, they belong to the ValueInfo structs in the ValueInfos
|
||||
// vector.
|
||||
DenseMap<const Value *, const PredicateBase *> PredicateMap;
|
||||
// The set of ssa_copy declarations we created with our custom mangling.
|
||||
SmallSet<AssertingVH<Function>, 20> CreatedDeclarations;
|
||||
};
|
||||
|
||||
// This pass does eager building and then printing of PredicateInfo. It is used
|
||||
|
@ -4080,6 +4080,22 @@ static Value *simplifySelectWithICmpCond(Value *CondVal, Value *TrueVal,
|
||||
std::swap(TrueVal, FalseVal);
|
||||
}
|
||||
|
||||
// Check for integer min/max with a limit constant:
|
||||
// X > MIN_INT ? X : MIN_INT --> X
|
||||
// X < MAX_INT ? X : MAX_INT --> X
|
||||
if (TrueVal->getType()->isIntOrIntVectorTy()) {
|
||||
Value *X, *Y;
|
||||
SelectPatternFlavor SPF =
|
||||
matchDecomposedSelectPattern(cast<ICmpInst>(CondVal), TrueVal, FalseVal,
|
||||
X, Y).Flavor;
|
||||
if (SelectPatternResult::isMinOrMax(SPF) && Pred == getMinMaxPred(SPF)) {
|
||||
APInt LimitC = getMinMaxLimit(getInverseMinMaxFlavor(SPF),
|
||||
X->getType()->getScalarSizeInBits());
|
||||
if (match(Y, m_SpecificInt(LimitC)))
|
||||
return X;
|
||||
}
|
||||
}
|
||||
|
||||
if (Pred == ICmpInst::ICMP_EQ && match(CmpRHS, m_Zero())) {
|
||||
Value *X;
|
||||
const APInt *Y;
|
||||
|
@ -893,9 +893,10 @@ bool TargetLibraryInfoImpl::isValidProtoForLibFunc(const FunctionType &FTy,
|
||||
FTy.getReturnType()->isIntegerTy(32);
|
||||
|
||||
case LibFunc_snprintf:
|
||||
return (NumParams == 3 && FTy.getParamType(0)->isPointerTy() &&
|
||||
FTy.getParamType(2)->isPointerTy() &&
|
||||
FTy.getReturnType()->isIntegerTy(32));
|
||||
return NumParams == 3 && FTy.getParamType(0)->isPointerTy() &&
|
||||
IsSizeTTy(FTy.getParamType(1)) &&
|
||||
FTy.getParamType(2)->isPointerTy() &&
|
||||
FTy.getReturnType()->isIntegerTy(32);
|
||||
|
||||
case LibFunc_snprintf_chk:
|
||||
return NumParams == 5 && FTy.getParamType(0)->isPointerTy() &&
|
||||
|
@ -6253,6 +6253,16 @@ CmpInst::Predicate llvm::getInverseMinMaxPred(SelectPatternFlavor SPF) {
|
||||
return getMinMaxPred(getInverseMinMaxFlavor(SPF));
|
||||
}
|
||||
|
||||
APInt llvm::getMinMaxLimit(SelectPatternFlavor SPF, unsigned BitWidth) {
|
||||
switch (SPF) {
|
||||
case SPF_SMAX: return APInt::getSignedMaxValue(BitWidth);
|
||||
case SPF_SMIN: return APInt::getSignedMinValue(BitWidth);
|
||||
case SPF_UMAX: return APInt::getMaxValue(BitWidth);
|
||||
case SPF_UMIN: return APInt::getMinValue(BitWidth);
|
||||
default: llvm_unreachable("Unexpected flavor");
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<Intrinsic::ID, bool>
|
||||
llvm::canConvertToMinOrMaxIntrinsic(ArrayRef<Value *> VL) {
|
||||
// Check if VL contains select instructions that can be folded into a min/max
|
||||
|
@ -325,7 +325,8 @@ bool InlineAsmLowering::lowerInlineAsm(
|
||||
return false;
|
||||
}
|
||||
|
||||
OpInfo.ConstraintVT = TLI->getValueType(DL, OpTy, true).getSimpleVT();
|
||||
OpInfo.ConstraintVT =
|
||||
TLI->getAsmOperandValueType(DL, OpTy, true).getSimpleVT();
|
||||
|
||||
} else if (OpInfo.Type == InlineAsm::isOutput && !OpInfo.isIndirect) {
|
||||
assert(!Call.getType()->isVoidTy() && "Bad inline asm!");
|
||||
@ -334,13 +335,17 @@ bool InlineAsmLowering::lowerInlineAsm(
|
||||
TLI->getSimpleValueType(DL, STy->getElementType(ResNo));
|
||||
} else {
|
||||
assert(ResNo == 0 && "Asm only has one result!");
|
||||
OpInfo.ConstraintVT = TLI->getSimpleValueType(DL, Call.getType());
|
||||
OpInfo.ConstraintVT =
|
||||
TLI->getAsmOperandValueType(DL, Call.getType()).getSimpleVT();
|
||||
}
|
||||
++ResNo;
|
||||
} else {
|
||||
OpInfo.ConstraintVT = MVT::Other;
|
||||
}
|
||||
|
||||
if (OpInfo.ConstraintVT == MVT::i64x8)
|
||||
return false;
|
||||
|
||||
// Compute the constraint code and ConstraintType to use.
|
||||
computeConstraintToUse(TLI, OpInfo);
|
||||
|
||||
|
@ -2439,9 +2439,7 @@ SDValue DAGCombiner::visitADDLike(SDNode *N) {
|
||||
N0.getOperand(0));
|
||||
|
||||
// fold (add (add (xor a, -1), b), 1) -> (sub b, a)
|
||||
if (N0.getOpcode() == ISD::ADD ||
|
||||
N0.getOpcode() == ISD::UADDO ||
|
||||
N0.getOpcode() == ISD::SADDO) {
|
||||
if (N0.getOpcode() == ISD::ADD) {
|
||||
SDValue A, Xor;
|
||||
|
||||
if (isBitwiseNot(N0.getOperand(0))) {
|
||||
@ -20562,8 +20560,12 @@ SDValue DAGCombiner::visitEXTRACT_SUBVECTOR(SDNode *N) {
|
||||
// otherwise => (extract_subvec V1, ExtIdx)
|
||||
uint64_t InsIdx = V.getConstantOperandVal(2);
|
||||
if (InsIdx * SmallVT.getScalarSizeInBits() ==
|
||||
ExtIdx * NVT.getScalarSizeInBits())
|
||||
ExtIdx * NVT.getScalarSizeInBits()) {
|
||||
if (LegalOperations && !TLI.isOperationLegal(ISD::BITCAST, NVT))
|
||||
return SDValue();
|
||||
|
||||
return DAG.getBitcast(NVT, V.getOperand(1));
|
||||
}
|
||||
return DAG.getNode(
|
||||
ISD::EXTRACT_SUBVECTOR, SDLoc(N), NVT,
|
||||
DAG.getBitcast(N->getOperand(0).getValueType(), V.getOperand(0)),
|
||||
|
@ -8176,7 +8176,7 @@ class SDISelAsmOperandInfo : public TargetLowering::AsmOperandInfo {
|
||||
}
|
||||
}
|
||||
|
||||
return TLI.getValueType(DL, OpTy, true);
|
||||
return TLI.getAsmOperandValueType(DL, OpTy, true);
|
||||
}
|
||||
};
|
||||
|
||||
@ -8479,8 +8479,8 @@ void SelectionDAGBuilder::visitInlineAsm(const CallBase &Call,
|
||||
DAG.getDataLayout(), STy->getElementType(ResNo));
|
||||
} else {
|
||||
assert(ResNo == 0 && "Asm only has one result!");
|
||||
OpInfo.ConstraintVT =
|
||||
TLI.getSimpleValueType(DAG.getDataLayout(), Call.getType());
|
||||
OpInfo.ConstraintVT = TLI.getAsmOperandValueType(
|
||||
DAG.getDataLayout(), Call.getType()).getSimpleVT();
|
||||
}
|
||||
++ResNo;
|
||||
} else {
|
||||
|
@ -1660,7 +1660,7 @@ static bool MIIsInTerminatorSequence(const MachineInstr &MI) {
|
||||
// physical registers if there is debug info associated with the terminator
|
||||
// of our mbb. We want to include said debug info in our terminator
|
||||
// sequence, so we return true in that case.
|
||||
return MI.isDebugValue();
|
||||
return MI.isDebugInstr();
|
||||
|
||||
// We have left the terminator sequence if we are not doing one of the
|
||||
// following:
|
||||
|
@ -4687,7 +4687,8 @@ TargetLowering::ParseConstraints(const DataLayout &DL,
|
||||
getSimpleValueType(DL, STy->getElementType(ResNo));
|
||||
} else {
|
||||
assert(ResNo == 0 && "Asm only has one result!");
|
||||
OpInfo.ConstraintVT = getSimpleValueType(DL, Call.getType());
|
||||
OpInfo.ConstraintVT =
|
||||
getAsmOperandValueType(DL, Call.getType()).getSimpleVT();
|
||||
}
|
||||
++ResNo;
|
||||
break;
|
||||
|
@ -677,8 +677,9 @@ calcUniqueIDUpdateFlagsAndSize(const GlobalObject *GO, StringRef SectionName,
|
||||
}
|
||||
|
||||
if (Retain) {
|
||||
if (Ctx.getAsmInfo()->useIntegratedAssembler() ||
|
||||
Ctx.getAsmInfo()->binutilsIsAtLeast(2, 36))
|
||||
if ((Ctx.getAsmInfo()->useIntegratedAssembler() ||
|
||||
Ctx.getAsmInfo()->binutilsIsAtLeast(2, 36)) &&
|
||||
!TM.getTargetTriple().isOSSolaris())
|
||||
Flags |= ELF::SHF_GNU_RETAIN;
|
||||
return NextUniqueID++;
|
||||
}
|
||||
@ -855,8 +856,10 @@ static MCSection *selectELFSectionForGlobal(
|
||||
EmitUniqueSection = true;
|
||||
Flags |= ELF::SHF_LINK_ORDER;
|
||||
}
|
||||
if (Retain && (Ctx.getAsmInfo()->useIntegratedAssembler() ||
|
||||
Ctx.getAsmInfo()->binutilsIsAtLeast(2, 36))) {
|
||||
if (Retain &&
|
||||
(Ctx.getAsmInfo()->useIntegratedAssembler() ||
|
||||
Ctx.getAsmInfo()->binutilsIsAtLeast(2, 36)) &&
|
||||
!TM.getTargetTriple().isOSSolaris()) {
|
||||
EmitUniqueSection = true;
|
||||
Flags |= ELF::SHF_GNU_RETAIN;
|
||||
}
|
||||
|
@ -167,6 +167,7 @@ std::string EVT::getEVTString() const {
|
||||
case MVT::Glue: return "glue";
|
||||
case MVT::x86mmx: return "x86mmx";
|
||||
case MVT::x86amx: return "x86amx";
|
||||
case MVT::i64x8: return "i64x8";
|
||||
case MVT::Metadata: return "Metadata";
|
||||
case MVT::Untyped: return "Untyped";
|
||||
case MVT::funcref: return "funcref";
|
||||
@ -198,6 +199,7 @@ Type *EVT::getTypeForEVT(LLVMContext &Context) const {
|
||||
case MVT::ppcf128: return Type::getPPC_FP128Ty(Context);
|
||||
case MVT::x86mmx: return Type::getX86_MMXTy(Context);
|
||||
case MVT::x86amx: return Type::getX86_AMXTy(Context);
|
||||
case MVT::i64x8: return IntegerType::get(Context, 512);
|
||||
case MVT::externref:
|
||||
return PointerType::get(StructType::create(Context), 10);
|
||||
case MVT::funcref:
|
||||
|
@ -349,200 +349,6 @@ static Constant *ExtractConstantBytes(Constant *C, unsigned ByteStart,
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrapper around getFoldedSizeOfImpl() that adds caching.
|
||||
static Constant *getFoldedSizeOf(Type *Ty, Type *DestTy, bool Folded,
|
||||
DenseMap<Type *, Constant *> &Cache);
|
||||
|
||||
/// Return a ConstantExpr with type DestTy for sizeof on Ty, with any known
|
||||
/// factors factored out. If Folded is false, return null if no factoring was
|
||||
/// possible, to avoid endlessly bouncing an unfoldable expression back into the
|
||||
/// top-level folder.
|
||||
static Constant *getFoldedSizeOfImpl(Type *Ty, Type *DestTy, bool Folded,
|
||||
DenseMap<Type *, Constant *> &Cache) {
|
||||
// This is the actual implementation of getFoldedSizeOf(). To get the caching
|
||||
// behavior, we need to call getFoldedSizeOf() when we recurse.
|
||||
|
||||
if (ArrayType *ATy = dyn_cast<ArrayType>(Ty)) {
|
||||
Constant *N = ConstantInt::get(DestTy, ATy->getNumElements());
|
||||
Constant *E = getFoldedSizeOf(ATy->getElementType(), DestTy, true, Cache);
|
||||
return ConstantExpr::getNUWMul(E, N);
|
||||
}
|
||||
|
||||
if (StructType *STy = dyn_cast<StructType>(Ty))
|
||||
if (!STy->isPacked()) {
|
||||
unsigned NumElems = STy->getNumElements();
|
||||
// An empty struct has size zero.
|
||||
if (NumElems == 0)
|
||||
return ConstantExpr::getNullValue(DestTy);
|
||||
// Check for a struct with all members having the same size.
|
||||
Constant *MemberSize =
|
||||
getFoldedSizeOf(STy->getElementType(0), DestTy, true, Cache);
|
||||
bool AllSame = true;
|
||||
for (unsigned i = 1; i != NumElems; ++i)
|
||||
if (MemberSize !=
|
||||
getFoldedSizeOf(STy->getElementType(i), DestTy, true, Cache)) {
|
||||
AllSame = false;
|
||||
break;
|
||||
}
|
||||
if (AllSame) {
|
||||
Constant *N = ConstantInt::get(DestTy, NumElems);
|
||||
return ConstantExpr::getNUWMul(MemberSize, N);
|
||||
}
|
||||
}
|
||||
|
||||
// Pointer size doesn't depend on the pointee type, so canonicalize them
|
||||
// to an arbitrary pointee.
|
||||
if (PointerType *PTy = dyn_cast<PointerType>(Ty))
|
||||
if (!PTy->getElementType()->isIntegerTy(1))
|
||||
return getFoldedSizeOf(
|
||||
PointerType::get(IntegerType::get(PTy->getContext(), 1),
|
||||
PTy->getAddressSpace()),
|
||||
DestTy, true, Cache);
|
||||
|
||||
// If there's no interesting folding happening, bail so that we don't create
|
||||
// a constant that looks like it needs folding but really doesn't.
|
||||
if (!Folded)
|
||||
return nullptr;
|
||||
|
||||
// Base case: Get a regular sizeof expression.
|
||||
Constant *C = ConstantExpr::getSizeOf(Ty);
|
||||
C = ConstantExpr::getCast(CastInst::getCastOpcode(C, false,
|
||||
DestTy, false),
|
||||
C, DestTy);
|
||||
return C;
|
||||
}
|
||||
|
||||
static Constant *getFoldedSizeOf(Type *Ty, Type *DestTy, bool Folded,
|
||||
DenseMap<Type *, Constant *> &Cache) {
|
||||
// Check for previously generated folded size constant.
|
||||
auto It = Cache.find(Ty);
|
||||
if (It != Cache.end())
|
||||
return It->second;
|
||||
return Cache[Ty] = getFoldedSizeOfImpl(Ty, DestTy, Folded, Cache);
|
||||
}
|
||||
|
||||
static Constant *getFoldedSizeOf(Type *Ty, Type *DestTy, bool Folded) {
|
||||
DenseMap<Type *, Constant *> Cache;
|
||||
return getFoldedSizeOf(Ty, DestTy, Folded, Cache);
|
||||
}
|
||||
|
||||
/// Return a ConstantExpr with type DestTy for alignof on Ty, with any known
|
||||
/// factors factored out. If Folded is false, return null if no factoring was
|
||||
/// possible, to avoid endlessly bouncing an unfoldable expression back into the
|
||||
/// top-level folder.
|
||||
static Constant *getFoldedAlignOf(Type *Ty, Type *DestTy, bool Folded) {
|
||||
// The alignment of an array is equal to the alignment of the
|
||||
// array element. Note that this is not always true for vectors.
|
||||
if (ArrayType *ATy = dyn_cast<ArrayType>(Ty)) {
|
||||
Constant *C = ConstantExpr::getAlignOf(ATy->getElementType());
|
||||
C = ConstantExpr::getCast(CastInst::getCastOpcode(C, false,
|
||||
DestTy,
|
||||
false),
|
||||
C, DestTy);
|
||||
return C;
|
||||
}
|
||||
|
||||
if (StructType *STy = dyn_cast<StructType>(Ty)) {
|
||||
// Packed structs always have an alignment of 1.
|
||||
if (STy->isPacked())
|
||||
return ConstantInt::get(DestTy, 1);
|
||||
|
||||
// Otherwise, struct alignment is the maximum alignment of any member.
|
||||
// Without target data, we can't compare much, but we can check to see
|
||||
// if all the members have the same alignment.
|
||||
unsigned NumElems = STy->getNumElements();
|
||||
// An empty struct has minimal alignment.
|
||||
if (NumElems == 0)
|
||||
return ConstantInt::get(DestTy, 1);
|
||||
// Check for a struct with all members having the same alignment.
|
||||
Constant *MemberAlign =
|
||||
getFoldedAlignOf(STy->getElementType(0), DestTy, true);
|
||||
bool AllSame = true;
|
||||
for (unsigned i = 1; i != NumElems; ++i)
|
||||
if (MemberAlign != getFoldedAlignOf(STy->getElementType(i), DestTy, true)) {
|
||||
AllSame = false;
|
||||
break;
|
||||
}
|
||||
if (AllSame)
|
||||
return MemberAlign;
|
||||
}
|
||||
|
||||
// Pointer alignment doesn't depend on the pointee type, so canonicalize them
|
||||
// to an arbitrary pointee.
|
||||
if (PointerType *PTy = dyn_cast<PointerType>(Ty))
|
||||
if (!PTy->getElementType()->isIntegerTy(1))
|
||||
return
|
||||
getFoldedAlignOf(PointerType::get(IntegerType::get(PTy->getContext(),
|
||||
1),
|
||||
PTy->getAddressSpace()),
|
||||
DestTy, true);
|
||||
|
||||
// If there's no interesting folding happening, bail so that we don't create
|
||||
// a constant that looks like it needs folding but really doesn't.
|
||||
if (!Folded)
|
||||
return nullptr;
|
||||
|
||||
// Base case: Get a regular alignof expression.
|
||||
Constant *C = ConstantExpr::getAlignOf(Ty);
|
||||
C = ConstantExpr::getCast(CastInst::getCastOpcode(C, false,
|
||||
DestTy, false),
|
||||
C, DestTy);
|
||||
return C;
|
||||
}
|
||||
|
||||
/// Return a ConstantExpr with type DestTy for offsetof on Ty and FieldNo, with
|
||||
/// any known factors factored out. If Folded is false, return null if no
|
||||
/// factoring was possible, to avoid endlessly bouncing an unfoldable expression
|
||||
/// back into the top-level folder.
|
||||
static Constant *getFoldedOffsetOf(Type *Ty, Constant *FieldNo, Type *DestTy,
|
||||
bool Folded) {
|
||||
if (ArrayType *ATy = dyn_cast<ArrayType>(Ty)) {
|
||||
Constant *N = ConstantExpr::getCast(CastInst::getCastOpcode(FieldNo, false,
|
||||
DestTy, false),
|
||||
FieldNo, DestTy);
|
||||
Constant *E = getFoldedSizeOf(ATy->getElementType(), DestTy, true);
|
||||
return ConstantExpr::getNUWMul(E, N);
|
||||
}
|
||||
|
||||
if (StructType *STy = dyn_cast<StructType>(Ty))
|
||||
if (!STy->isPacked()) {
|
||||
unsigned NumElems = STy->getNumElements();
|
||||
// An empty struct has no members.
|
||||
if (NumElems == 0)
|
||||
return nullptr;
|
||||
// Check for a struct with all members having the same size.
|
||||
Constant *MemberSize =
|
||||
getFoldedSizeOf(STy->getElementType(0), DestTy, true);
|
||||
bool AllSame = true;
|
||||
for (unsigned i = 1; i != NumElems; ++i)
|
||||
if (MemberSize !=
|
||||
getFoldedSizeOf(STy->getElementType(i), DestTy, true)) {
|
||||
AllSame = false;
|
||||
break;
|
||||
}
|
||||
if (AllSame) {
|
||||
Constant *N = ConstantExpr::getCast(CastInst::getCastOpcode(FieldNo,
|
||||
false,
|
||||
DestTy,
|
||||
false),
|
||||
FieldNo, DestTy);
|
||||
return ConstantExpr::getNUWMul(MemberSize, N);
|
||||
}
|
||||
}
|
||||
|
||||
// If there's no interesting folding happening, bail so that we don't create
|
||||
// a constant that looks like it needs folding but really doesn't.
|
||||
if (!Folded)
|
||||
return nullptr;
|
||||
|
||||
// Base case: Get a regular offsetof expression.
|
||||
Constant *C = ConstantExpr::getOffsetOf(Ty, FieldNo);
|
||||
C = ConstantExpr::getCast(CastInst::getCastOpcode(C, false,
|
||||
DestTy, false),
|
||||
C, DestTy);
|
||||
return C;
|
||||
}
|
||||
|
||||
Constant *llvm::ConstantFoldCastInstruction(unsigned opc, Constant *V,
|
||||
Type *DestTy) {
|
||||
if (isa<PoisonValue>(V))
|
||||
@ -666,53 +472,6 @@ Constant *llvm::ConstantFoldCastInstruction(unsigned opc, Constant *V,
|
||||
// Is it a null pointer value?
|
||||
if (V->isNullValue())
|
||||
return ConstantInt::get(DestTy, 0);
|
||||
// If this is a sizeof-like expression, pull out multiplications by
|
||||
// known factors to expose them to subsequent folding. If it's an
|
||||
// alignof-like expression, factor out known factors.
|
||||
if (ConstantExpr *CE = dyn_cast<ConstantExpr>(V))
|
||||
if (CE->getOpcode() == Instruction::GetElementPtr &&
|
||||
CE->getOperand(0)->isNullValue()) {
|
||||
// FIXME: Looks like getFoldedSizeOf(), getFoldedOffsetOf() and
|
||||
// getFoldedAlignOf() don't handle the case when DestTy is a vector of
|
||||
// pointers yet. We end up in asserts in CastInst::getCastOpcode (see
|
||||
// test/Analysis/ConstantFolding/cast-vector.ll). I've only seen this
|
||||
// happen in one "real" C-code test case, so it does not seem to be an
|
||||
// important optimization to handle vectors here. For now, simply bail
|
||||
// out.
|
||||
if (DestTy->isVectorTy())
|
||||
return nullptr;
|
||||
GEPOperator *GEPO = cast<GEPOperator>(CE);
|
||||
Type *Ty = GEPO->getSourceElementType();
|
||||
if (CE->getNumOperands() == 2) {
|
||||
// Handle a sizeof-like expression.
|
||||
Constant *Idx = CE->getOperand(1);
|
||||
bool isOne = isa<ConstantInt>(Idx) && cast<ConstantInt>(Idx)->isOne();
|
||||
if (Constant *C = getFoldedSizeOf(Ty, DestTy, !isOne)) {
|
||||
Idx = ConstantExpr::getCast(CastInst::getCastOpcode(Idx, true,
|
||||
DestTy, false),
|
||||
Idx, DestTy);
|
||||
return ConstantExpr::getMul(C, Idx);
|
||||
}
|
||||
} else if (CE->getNumOperands() == 3 &&
|
||||
CE->getOperand(1)->isNullValue()) {
|
||||
// Handle an alignof-like expression.
|
||||
if (StructType *STy = dyn_cast<StructType>(Ty))
|
||||
if (!STy->isPacked()) {
|
||||
ConstantInt *CI = cast<ConstantInt>(CE->getOperand(2));
|
||||
if (CI->isOne() &&
|
||||
STy->getNumElements() == 2 &&
|
||||
STy->getElementType(0)->isIntegerTy(1)) {
|
||||
return getFoldedAlignOf(STy->getElementType(1), DestTy, false);
|
||||
}
|
||||
}
|
||||
// Handle an offsetof-like expression.
|
||||
if (Ty->isStructTy() || Ty->isArrayTy()) {
|
||||
if (Constant *C = getFoldedOffsetOf(Ty, CE->getOperand(2),
|
||||
DestTy, false))
|
||||
return C;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Other pointer types cannot be casted
|
||||
return nullptr;
|
||||
case Instruction::UIToFP:
|
||||
|
@ -114,6 +114,10 @@ GlobalValue *Module::getNamedValue(StringRef Name) const {
|
||||
return cast_or_null<GlobalValue>(getValueSymbolTable().lookup(Name));
|
||||
}
|
||||
|
||||
unsigned Module::getNumNamedValues() const {
|
||||
return getValueSymbolTable().size();
|
||||
}
|
||||
|
||||
/// getMDKindID - Return a unique non-zero ID for the specified metadata kind.
|
||||
/// This ID is uniqued across modules in the current LLVMContext.
|
||||
unsigned Module::getMDKindID(StringRef Name) const {
|
||||
|
@ -366,6 +366,7 @@ Error RawInstrProfReader<IntPtrT>::readHeader(
|
||||
if (GET_VERSION(Version) != RawInstrProf::Version)
|
||||
return error(instrprof_error::unsupported_version);
|
||||
|
||||
BinaryIdsSize = swap(Header.BinaryIdsSize);
|
||||
CountersDelta = swap(Header.CountersDelta);
|
||||
NamesDelta = swap(Header.NamesDelta);
|
||||
auto DataSize = swap(Header.DataSize);
|
||||
@ -374,7 +375,6 @@ Error RawInstrProfReader<IntPtrT>::readHeader(
|
||||
auto PaddingBytesAfterCounters = swap(Header.PaddingBytesAfterCounters);
|
||||
NamesSize = swap(Header.NamesSize);
|
||||
ValueKindLast = swap(Header.ValueKindLast);
|
||||
BinaryIdsSize = swap(Header.BinaryIdsSize);
|
||||
|
||||
auto DataSizeInBytes = DataSize * sizeof(RawInstrProf::ProfileData<IntPtrT>);
|
||||
auto PaddingSize = getNumPaddingBytes(NamesSize);
|
||||
|
@ -653,6 +653,9 @@ bool AArch64AsmPrinter::printAsmMRegister(const MachineOperand &MO, char Mode,
|
||||
case 'x':
|
||||
Reg = getXRegFromWReg(Reg);
|
||||
break;
|
||||
case 't':
|
||||
Reg = getXRegFromXRegTuple(Reg);
|
||||
break;
|
||||
}
|
||||
|
||||
O << AArch64InstPrinter::getRegisterName(Reg);
|
||||
@ -749,6 +752,10 @@ bool AArch64AsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNum,
|
||||
AArch64::GPR64allRegClass.contains(Reg))
|
||||
return printAsmMRegister(MO, 'x', O);
|
||||
|
||||
// If this is an x register tuple, print an x register.
|
||||
if (AArch64::GPR64x8ClassRegClass.contains(Reg))
|
||||
return printAsmMRegister(MO, 't', O);
|
||||
|
||||
unsigned AltName = AArch64::NoRegAltName;
|
||||
const TargetRegisterClass *RegClass;
|
||||
if (AArch64::ZPRRegClass.contains(Reg)) {
|
||||
|
@ -246,6 +246,12 @@ AArch64TargetLowering::AArch64TargetLowering(const TargetMachine &TM,
|
||||
addRegisterClass(MVT::i32, &AArch64::GPR32allRegClass);
|
||||
addRegisterClass(MVT::i64, &AArch64::GPR64allRegClass);
|
||||
|
||||
if (Subtarget->hasLS64()) {
|
||||
addRegisterClass(MVT::i64x8, &AArch64::GPR64x8ClassRegClass);
|
||||
setOperationAction(ISD::LOAD, MVT::i64x8, Custom);
|
||||
setOperationAction(ISD::STORE, MVT::i64x8, Custom);
|
||||
}
|
||||
|
||||
if (Subtarget->hasFPARMv8()) {
|
||||
addRegisterClass(MVT::f16, &AArch64::FPR16RegClass);
|
||||
addRegisterClass(MVT::bf16, &AArch64::FPR16RegClass);
|
||||
@ -2023,6 +2029,8 @@ const char *AArch64TargetLowering::getTargetNodeName(unsigned Opcode) const {
|
||||
MAKE_CASE(AArch64ISD::LASTA)
|
||||
MAKE_CASE(AArch64ISD::LASTB)
|
||||
MAKE_CASE(AArch64ISD::REINTERPRET_CAST)
|
||||
MAKE_CASE(AArch64ISD::LS64_BUILD)
|
||||
MAKE_CASE(AArch64ISD::LS64_EXTRACT)
|
||||
MAKE_CASE(AArch64ISD::TBL)
|
||||
MAKE_CASE(AArch64ISD::FADD_PRED)
|
||||
MAKE_CASE(AArch64ISD::FADDA_PRED)
|
||||
@ -4345,9 +4353,17 @@ SDValue AArch64TargetLowering::LowerMGATHER(SDValue Op,
|
||||
if (IsFixedLength) {
|
||||
assert(Subtarget->useSVEForFixedLengthVectors() &&
|
||||
"Cannot lower when not using SVE for fixed vectors");
|
||||
IndexVT = getContainerForFixedLengthVector(DAG, IndexVT);
|
||||
MemVT = IndexVT.changeVectorElementType(MemVT.getVectorElementType());
|
||||
if (MemVT.getScalarSizeInBits() <= IndexVT.getScalarSizeInBits()) {
|
||||
IndexVT = getContainerForFixedLengthVector(DAG, IndexVT);
|
||||
MemVT = IndexVT.changeVectorElementType(MemVT.getVectorElementType());
|
||||
} else {
|
||||
MemVT = getContainerForFixedLengthVector(DAG, MemVT);
|
||||
IndexVT = MemVT.changeTypeToInteger();
|
||||
}
|
||||
InputVT = DAG.getValueType(MemVT.changeTypeToInteger());
|
||||
Mask = DAG.getNode(
|
||||
ISD::ZERO_EXTEND, DL,
|
||||
VT.changeVectorElementType(IndexVT.getVectorElementType()), Mask);
|
||||
}
|
||||
|
||||
if (PassThru->isUndef() || isZerosVector(PassThru.getNode()))
|
||||
@ -4442,8 +4458,13 @@ SDValue AArch64TargetLowering::LowerMSCATTER(SDValue Op,
|
||||
if (IsFixedLength) {
|
||||
assert(Subtarget->useSVEForFixedLengthVectors() &&
|
||||
"Cannot lower when not using SVE for fixed vectors");
|
||||
IndexVT = getContainerForFixedLengthVector(DAG, IndexVT);
|
||||
MemVT = IndexVT.changeVectorElementType(MemVT.getVectorElementType());
|
||||
if (MemVT.getScalarSizeInBits() <= IndexVT.getScalarSizeInBits()) {
|
||||
IndexVT = getContainerForFixedLengthVector(DAG, IndexVT);
|
||||
MemVT = IndexVT.changeVectorElementType(MemVT.getVectorElementType());
|
||||
} else {
|
||||
MemVT = getContainerForFixedLengthVector(DAG, MemVT);
|
||||
IndexVT = MemVT.changeTypeToInteger();
|
||||
}
|
||||
InputVT = DAG.getValueType(MemVT.changeTypeToInteger());
|
||||
|
||||
StoreVal =
|
||||
@ -4452,6 +4473,9 @@ SDValue AArch64TargetLowering::LowerMSCATTER(SDValue Op,
|
||||
ISD::ANY_EXTEND, DL,
|
||||
VT.changeVectorElementType(IndexVT.getVectorElementType()), StoreVal);
|
||||
StoreVal = convertToScalableVector(DAG, IndexVT, StoreVal);
|
||||
Mask = DAG.getNode(
|
||||
ISD::ZERO_EXTEND, DL,
|
||||
VT.changeVectorElementType(IndexVT.getVectorElementType()), Mask);
|
||||
} else if (VT.isFloatingPoint()) {
|
||||
// Handle FP data by casting the data so an integer scatter can be used.
|
||||
EVT StoreValVT = getPackedSVEVectorVT(VT.getVectorElementCount());
|
||||
@ -4605,17 +4629,51 @@ SDValue AArch64TargetLowering::LowerSTORE(SDValue Op,
|
||||
{StoreNode->getChain(), Lo, Hi, StoreNode->getBasePtr()},
|
||||
StoreNode->getMemoryVT(), StoreNode->getMemOperand());
|
||||
return Result;
|
||||
} else if (MemVT == MVT::i64x8) {
|
||||
SDValue Value = StoreNode->getValue();
|
||||
assert(Value->getValueType(0) == MVT::i64x8);
|
||||
SDValue Chain = StoreNode->getChain();
|
||||
SDValue Base = StoreNode->getBasePtr();
|
||||
EVT PtrVT = Base.getValueType();
|
||||
for (unsigned i = 0; i < 8; i++) {
|
||||
SDValue Part = DAG.getNode(AArch64ISD::LS64_EXTRACT, Dl, MVT::i64,
|
||||
Value, DAG.getConstant(i, Dl, MVT::i32));
|
||||
SDValue Ptr = DAG.getNode(ISD::ADD, Dl, PtrVT, Base,
|
||||
DAG.getConstant(i * 8, Dl, PtrVT));
|
||||
Chain = DAG.getStore(Chain, Dl, Part, Ptr, StoreNode->getPointerInfo(),
|
||||
StoreNode->getOriginalAlign());
|
||||
}
|
||||
return Chain;
|
||||
}
|
||||
|
||||
return SDValue();
|
||||
}
|
||||
|
||||
// Custom lowering for extending v4i8 vector loads.
|
||||
SDValue AArch64TargetLowering::LowerLOAD(SDValue Op,
|
||||
SelectionDAG &DAG) const {
|
||||
SDLoc DL(Op);
|
||||
LoadSDNode *LoadNode = cast<LoadSDNode>(Op);
|
||||
assert(LoadNode && "Expected custom lowering of a load node");
|
||||
|
||||
if (LoadNode->getMemoryVT() == MVT::i64x8) {
|
||||
SmallVector<SDValue, 8> Ops;
|
||||
SDValue Base = LoadNode->getBasePtr();
|
||||
SDValue Chain = LoadNode->getChain();
|
||||
EVT PtrVT = Base.getValueType();
|
||||
for (unsigned i = 0; i < 8; i++) {
|
||||
SDValue Ptr = DAG.getNode(ISD::ADD, DL, PtrVT, Base,
|
||||
DAG.getConstant(i * 8, DL, PtrVT));
|
||||
SDValue Part = DAG.getLoad(MVT::i64, DL, Chain, Ptr,
|
||||
LoadNode->getPointerInfo(),
|
||||
LoadNode->getOriginalAlign());
|
||||
Ops.push_back(Part);
|
||||
Chain = SDValue(Part.getNode(), 1);
|
||||
}
|
||||
SDValue Loaded = DAG.getNode(AArch64ISD::LS64_BUILD, DL, MVT::i64x8, Ops);
|
||||
return DAG.getMergeValues({Loaded, Chain}, DL);
|
||||
}
|
||||
|
||||
// Custom lowering for extending v4i8 vector loads.
|
||||
EVT VT = Op->getValueType(0);
|
||||
assert((VT == MVT::v4i16 || VT == MVT::v4i32) && "Expected v4i16 or v4i32");
|
||||
|
||||
@ -8173,6 +8231,8 @@ AArch64TargetLowering::getRegForInlineAsmConstraint(
|
||||
case 'r':
|
||||
if (VT.isScalableVector())
|
||||
return std::make_pair(0U, nullptr);
|
||||
if (Subtarget->hasLS64() && VT.getSizeInBits() == 512)
|
||||
return std::make_pair(0U, &AArch64::GPR64x8ClassRegClass);
|
||||
if (VT.getFixedSizeInBits() == 64)
|
||||
return std::make_pair(0U, &AArch64::GPR64commonRegClass);
|
||||
return std::make_pair(0U, &AArch64::GPR32commonRegClass);
|
||||
@ -8260,6 +8320,15 @@ AArch64TargetLowering::getRegForInlineAsmConstraint(
|
||||
return Res;
|
||||
}
|
||||
|
||||
EVT AArch64TargetLowering::getAsmOperandValueType(const DataLayout &DL,
|
||||
llvm::Type *Ty,
|
||||
bool AllowUnknown) const {
|
||||
if (Subtarget->hasLS64() && Ty->isIntegerTy(512))
|
||||
return EVT(MVT::i64x8);
|
||||
|
||||
return TargetLowering::getAsmOperandValueType(DL, Ty, AllowUnknown);
|
||||
}
|
||||
|
||||
/// LowerAsmOperandForConstraint - Lower the specified operand into the Ops
|
||||
/// vector. If it is invalid, don't add anything to Ops.
|
||||
void AArch64TargetLowering::LowerAsmOperandForConstraint(
|
||||
|
@ -330,6 +330,10 @@ enum NodeType : unsigned {
|
||||
// Cast between vectors of the same element type but differ in length.
|
||||
REINTERPRET_CAST,
|
||||
|
||||
// Nodes to build an LD64B / ST64B 64-bit quantity out of i64, and vice versa
|
||||
LS64_BUILD,
|
||||
LS64_EXTRACT,
|
||||
|
||||
LD1_MERGE_ZERO,
|
||||
LD1S_MERGE_ZERO,
|
||||
LDNF1_MERGE_ZERO,
|
||||
@ -824,6 +828,9 @@ class AArch64TargetLowering : public TargetLowering {
|
||||
bool isAllActivePredicate(SDValue N) const;
|
||||
EVT getPromotedVTForPredicate(EVT VT) const;
|
||||
|
||||
EVT getAsmOperandValueType(const DataLayout &DL, Type *Ty,
|
||||
bool AllowUnknown = false) const override;
|
||||
|
||||
private:
|
||||
/// Keep a pointer to the AArch64Subtarget around so that we can
|
||||
/// make the right decision when generating code for different targets.
|
||||
|
@ -1120,6 +1120,16 @@ bool AArch64InstrInfo::analyzeCompare(const MachineInstr &MI, Register &SrcReg,
|
||||
if (!MI.getOperand(1).isReg())
|
||||
return false;
|
||||
|
||||
auto NormalizeCmpValue = [](int64_t Value) -> int {
|
||||
// Comparison immediates may be 64-bit, but CmpValue is only an int.
|
||||
// Normalize to 0/1/2 return value, where 2 indicates any value apart from
|
||||
// 0 or 1.
|
||||
// TODO: Switch CmpValue to int64_t in the API to avoid this.
|
||||
if (Value == 0 || Value == 1)
|
||||
return Value;
|
||||
return 2;
|
||||
};
|
||||
|
||||
switch (MI.getOpcode()) {
|
||||
default:
|
||||
break;
|
||||
@ -1155,8 +1165,7 @@ bool AArch64InstrInfo::analyzeCompare(const MachineInstr &MI, Register &SrcReg,
|
||||
SrcReg = MI.getOperand(1).getReg();
|
||||
SrcReg2 = 0;
|
||||
CmpMask = ~0;
|
||||
// FIXME: In order to convert CmpValue to 0 or 1
|
||||
CmpValue = MI.getOperand(2).getImm() != 0;
|
||||
CmpValue = NormalizeCmpValue(MI.getOperand(2).getImm());
|
||||
return true;
|
||||
case AArch64::ANDSWri:
|
||||
case AArch64::ANDSXri:
|
||||
@ -1165,14 +1174,9 @@ bool AArch64InstrInfo::analyzeCompare(const MachineInstr &MI, Register &SrcReg,
|
||||
SrcReg = MI.getOperand(1).getReg();
|
||||
SrcReg2 = 0;
|
||||
CmpMask = ~0;
|
||||
// FIXME:The return val type of decodeLogicalImmediate is uint64_t,
|
||||
// while the type of CmpValue is int. When converting uint64_t to int,
|
||||
// the high 32 bits of uint64_t will be lost.
|
||||
// In fact it causes a bug in spec2006-483.xalancbmk
|
||||
// CmpValue is only used to compare with zero in OptimizeCompareInstr
|
||||
CmpValue = AArch64_AM::decodeLogicalImmediate(
|
||||
CmpValue = NormalizeCmpValue(AArch64_AM::decodeLogicalImmediate(
|
||||
MI.getOperand(2).getImm(),
|
||||
MI.getOpcode() == AArch64::ANDSWri ? 32 : 64) != 0;
|
||||
MI.getOpcode() == AArch64::ANDSWri ? 32 : 64));
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1462,10 +1466,9 @@ bool AArch64InstrInfo::optimizeCompareInstr(
|
||||
if (CmpInstr.getOpcode() == AArch64::PTEST_PP)
|
||||
return optimizePTestInstr(&CmpInstr, SrcReg, SrcReg2, MRI);
|
||||
|
||||
// Continue only if we have a "ri" where immediate is zero.
|
||||
// FIXME:CmpValue has already been converted to 0 or 1 in analyzeCompare
|
||||
// function.
|
||||
assert((CmpValue == 0 || CmpValue == 1) && "CmpValue must be 0 or 1!");
|
||||
// Warning: CmpValue == 2 indicates *any* value apart from 0 or 1.
|
||||
assert((CmpValue == 0 || CmpValue == 1 || CmpValue == 2) &&
|
||||
"CmpValue must be 0, 1, or 2!");
|
||||
if (SrcReg2 != 0)
|
||||
return false;
|
||||
|
||||
@ -1473,9 +1476,10 @@ bool AArch64InstrInfo::optimizeCompareInstr(
|
||||
if (!MRI->use_nodbg_empty(CmpInstr.getOperand(0).getReg()))
|
||||
return false;
|
||||
|
||||
if (!CmpValue && substituteCmpToZero(CmpInstr, SrcReg, *MRI))
|
||||
if (CmpValue == 0 && substituteCmpToZero(CmpInstr, SrcReg, *MRI))
|
||||
return true;
|
||||
return removeCmpToZeroOrOne(CmpInstr, SrcReg, CmpValue, *MRI);
|
||||
return (CmpValue == 0 || CmpValue == 1) &&
|
||||
removeCmpToZeroOrOne(CmpInstr, SrcReg, CmpValue, *MRI);
|
||||
}
|
||||
|
||||
/// Get opcode of S version of Instr.
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user