aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2021-08-21 21:25:07 +0000
committerDimitry Andric <dim@FreeBSD.org>2021-08-21 21:25:07 +0000
commit9cb5bdb8b26e2207293f0fb56701c4a0ff64a47d (patch)
tree8fe8549bfdf28ab5d376f9ae7a956787d6f8b25e
parentfa40418fea35c68de2a358bce3539cdc5cbcd21a (diff)
downloadsrc-9cb5bdb8b26e2207293f0fb56701c4a0ff64a47d.tar.gz
src-9cb5bdb8b26e2207293f0fb56701c4a0ff64a47d.zip
Vendor import of llvm-project branch release/13.x llvmorg-13.0.0-rc1-0-gd6974c010878.vendor/llvm-project/llvmorg-13.0.0-rc1-0-gd6974c010878
-rw-r--r--clang/include/clang/Basic/DiagnosticDriverKinds.td2
-rw-r--r--clang/include/clang/Basic/DiagnosticLexKinds.td7
-rw-r--r--clang/include/clang/Basic/DiagnosticSemaKinds.td2
-rw-r--r--clang/include/clang/Basic/LangOptions.def2
-rw-r--r--clang/include/clang/Driver/Options.td3
-rw-r--r--clang/include/clang/Driver/Types.h8
-rw-r--r--clang/include/clang/Frontend/PreprocessorOutputOptions.h2
-rw-r--r--clang/include/clang/Lex/HeaderSearch.h17
-rw-r--r--clang/include/clang/Lex/Preprocessor.h5
-rw-r--r--clang/include/clang/Lex/PreprocessorLexer.h20
-rw-r--r--clang/lib/Basic/OpenCLOptions.cpp7
-rw-r--r--clang/lib/Basic/TargetInfo.cpp10
-rw-r--r--clang/lib/Basic/Targets/AArch64.cpp6
-rw-r--r--clang/lib/Basic/Targets/AMDGPU.h5
-rw-r--r--clang/lib/CodeGen/CGStmt.cpp43
-rw-r--r--clang/lib/CodeGen/TargetInfo.cpp14
-rw-r--r--clang/lib/CodeGen/TargetInfo.h7
-rw-r--r--clang/lib/Driver/ToolChains/Clang.cpp15
-rw-r--r--clang/lib/Driver/Types.cpp39
-rw-r--r--clang/lib/Frontend/CompilerInvocation.cpp2
-rw-r--r--clang/lib/Frontend/PrintPreprocessedOutput.cpp349
-rw-r--r--clang/lib/Lex/Lexer.cpp4
-rw-r--r--clang/lib/Lex/PPDirectives.cpp4
-rw-r--r--clang/lib/Lex/PPLexerChange.cpp45
-rw-r--r--clang/lib/Lex/Pragma.cpp92
-rw-r--r--clang/lib/Lex/Preprocessor.cpp6
-rw-r--r--clang/lib/Parse/ParseDecl.cpp16
-rw-r--r--clang/lib/Sema/Sema.cpp3
-rw-r--r--clang/lib/Sema/SemaType.cpp47
-rw-r--r--libcxx/include/format12
-rw-r--r--libcxx/include/ranges12
-rw-r--r--lld/ELF/Config.h7
-rw-r--r--lld/ELF/Driver.cpp16
-rw-r--r--lld/ELF/Options.td3
-rw-r--r--lld/ELF/Symbols.cpp8
-rw-r--r--lld/ELF/SyntheticSections.cpp2
-rw-r--r--lld/docs/ReleaseNotes.rst2
-rw-r--r--lld/docs/ld.lld.13
-rw-r--r--llvm/include/llvm/CodeGen/TargetLowering.h5
-rw-r--r--llvm/include/llvm/CodeGen/ValueTypes.td1
-rw-r--r--llvm/include/llvm/Support/MachineValueType.h4
-rw-r--r--llvm/lib/Analysis/TargetLibraryInfo.cpp7
-rw-r--r--llvm/lib/CodeGen/GlobalISel/InlineAsmLowering.cpp9
-rw-r--r--llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp4
-rw-r--r--llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp6
-rw-r--r--llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp3
-rw-r--r--llvm/lib/CodeGen/ValueTypes.cpp2
-rw-r--r--llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp7
-rw-r--r--llvm/lib/Target/AArch64/AArch64ISelLowering.cpp55
-rw-r--r--llvm/lib/Target/AArch64/AArch64ISelLowering.h7
-rw-r--r--llvm/lib/Target/AArch64/AArch64InstrInfo.td14
-rw-r--r--llvm/lib/Target/AArch64/AArch64RegisterInfo.td4
-rw-r--r--llvm/lib/Target/AArch64/Utils/AArch64BaseInfo.h19
-rw-r--r--llvm/lib/Target/RISCV/RISCVISelLowering.cpp7
-rw-r--r--llvm/lib/Transforms/Scalar/DivRemPairs.cpp7
-rw-r--r--llvm/utils/TableGen/CodeGenTarget.cpp1
56 files changed, 615 insertions, 394 deletions
diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td
index 3b4daa59f66b..fc3704303a95 100644
--- a/clang/include/clang/Basic/DiagnosticDriverKinds.td
+++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td
@@ -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<
diff --git a/clang/include/clang/Basic/DiagnosticLexKinds.td b/clang/include/clang/Basic/DiagnosticLexKinds.td
index ce6d0d0394b4..bdf5d263fa92 100644
--- a/clang/include/clang/Basic/DiagnosticLexKinds.td
+++ b/clang/include/clang/Basic/DiagnosticLexKinds.td
@@ -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">;
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 108f1796415c..c57b8eca7deb 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -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">,
diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def
index 08b8d8851afa..74deba6ef7fb 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -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")
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 5a9fd078390e..ab1a5487d9c0 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -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">,
diff --git a/clang/include/clang/Driver/Types.h b/clang/include/clang/Driver/Types.h
index c9d63551090c..6a1f57416ae5 100644
--- a/clang/include/clang/Driver/Types.h
+++ b/clang/include/clang/Driver/Types.h
@@ -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);
diff --git a/clang/include/clang/Frontend/PreprocessorOutputOptions.h b/clang/include/clang/Frontend/PreprocessorOutputOptions.h
index 257538ee0606..72e5ad1137fb 100644
--- a/clang/include/clang/Frontend/PreprocessorOutputOptions.h
+++ b/clang/include/clang/Frontend/PreprocessorOutputOptions.h
@@ -24,7 +24,6 @@ public:
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 @@ public:
ShowIncludeDirectives = 0;
RewriteIncludes = 0;
RewriteImports = 0;
- MinimizeWhitespace = 0;
}
};
diff --git a/clang/include/clang/Lex/HeaderSearch.h b/clang/include/clang/Lex/HeaderSearch.h
index 93d6ea72270a..a35a394f719b 100644
--- a/clang/include/clang/Lex/HeaderSearch.h
+++ b/clang/include/clang/Lex/HeaderSearch.h
@@ -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 @@ public:
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,
diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h
index 7ab13640ce2c..fe2327f0a480 100644
--- a/clang/include/clang/Lex/Preprocessor.h
+++ b/clang/include/clang/Lex/Preprocessor.h
@@ -1953,7 +1953,8 @@ public:
/// 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 @@ private:
// 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);
diff --git a/clang/include/clang/Lex/PreprocessorLexer.h b/clang/include/clang/Lex/PreprocessorLexer.h
index 03b1cc2c10e2..b43197a6031c 100644
--- a/clang/include/clang/Lex/PreprocessorLexer.h
+++ b/clang/include/clang/Lex/PreprocessorLexer.h
@@ -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 @@ protected:
/// 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 @@ public:
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
diff --git a/clang/lib/Basic/OpenCLOptions.cpp b/clang/lib/Basic/OpenCLOptions.cpp
index 2e215b185f66..b7408f39bdab 100644
--- a/clang/lib/Basic/OpenCLOptions.cpp
+++ b/clang/lib/Basic/OpenCLOptions.cpp
@@ -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();
diff --git a/clang/lib/Basic/TargetInfo.cpp b/clang/lib/Basic/TargetInfo.cpp
index b647a2fb8a67..5f8e04c2bd6c 100644
--- a/clang/lib/Basic/TargetInfo.cpp
+++ b/clang/lib/Basic/TargetInfo.cpp
@@ -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");
}
}
diff --git a/clang/lib/Basic/Targets/AArch64.cpp b/clang/lib/Basic/Targets/AArch64.cpp
index 4070ac727d16..e163ebfa2348 100644
--- a/clang/lib/Basic/Targets/AArch64.cpp
+++ b/clang/lib/Basic/Targets/AArch64.cpp
@@ -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;
}
diff --git a/clang/lib/Basic/Targets/AMDGPU.h b/clang/lib/Basic/Targets/AMDGPU.h
index 244a6e044690..2e580ecf2425 100644
--- a/clang/lib/Basic/Targets/AMDGPU.h
+++ b/clang/lib/Basic/Targets/AMDGPU.h
@@ -310,9 +310,12 @@ public:
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;
}
}
diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp
index aeb319ca1581..0a3a722fa653 100644
--- a/clang/lib/CodeGen/CGStmt.cpp
+++ b/clang/lib/CodeGen/CGStmt.cpp
@@ -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);
diff --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp
index a2b68a04d351..d2cc0a699f43 100644
--- a/clang/lib/CodeGen/TargetInfo.cpp
+++ b/clang/lib/CodeGen/TargetInfo.cpp
@@ -5526,6 +5526,20 @@ public:
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 {
diff --git a/clang/lib/CodeGen/TargetInfo.h b/clang/lib/CodeGen/TargetInfo.h
index e6e474544fc4..aa8bbb60a75f 100644
--- a/clang/lib/CodeGen/TargetInfo.h
+++ b/clang/lib/CodeGen/TargetInfo.h
@@ -148,6 +148,13 @@ public:
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,
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index a4b53a640ab5..1870bd81789c 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -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)
@@ -6068,16 +6067,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))
diff --git a/clang/lib/Driver/Types.cpp b/clang/lib/Driver/Types.cpp
index 3cb2d6e8f6fd..b7ccdf23cbaa 100644
--- a/clang/lib/Driver/Types.cpp
+++ b/clang/lib/Driver/Types.cpp
@@ -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:
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index d545e9358f04..33e5f3e99c45 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -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;
diff --git a/clang/lib/Frontend/PrintPreprocessedOutput.cpp b/clang/lib/Frontend/PrintPreprocessedOutput.cpp
index b7259569595d..24ea1ccba207 100644
--- a/clang/lib/Frontend/PrintPreprocessedOutput.cpp
+++ b/clang/lib/Frontend/PrintPreprocessedOutput.cpp
@@ -95,20 +95,14 @@ private:
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 @@ public:
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 @@ public:
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 @@ public:
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 @@ public:
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;
+
+ // 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;
+
+ // 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 << ' ';
- 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());
-
- // 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 << ' ';
-
- // 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();
-
- Callbacks->HandleWhitespaceBeforeTok(Tok, /*RequireSpace=*/false,
- /*RequireSameLine=*/!IsStartOfLine);
+ if (Callbacks->hasEmittedDirectiveOnThisLine()) {
+ Callbacks->startNewLineIfNeeded();
+ Callbacks->MoveToLine(Tok.getLocation());
+ }
+
+ // 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.
diff --git a/clang/lib/Lex/Lexer.cpp b/clang/lib/Lex/Lexer.cpp
index 3034af231e0e..64944492eb99 100644
--- a/clang/lib/Lex/Lexer.cpp
+++ b/clang/lib/Lex/Lexer.cpp
@@ -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
diff --git a/clang/lib/Lex/PPDirectives.cpp b/clang/lib/Lex/PPDirectives.cpp
index 556dd8daf652..3fa8746653b0 100644
--- a/clang/lib/Lex/PPDirectives.cpp
+++ b/clang/lib/Lex/PPDirectives.cpp
@@ -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;
diff --git a/clang/lib/Lex/PPLexerChange.cpp b/clang/lib/Lex/PPLexerChange.cpp
index b979b965f46a..16170969a322 100644
--- a/clang/lib/Lex/PPLexerChange.cpp
+++ b/clang/lib/Lex/PPLexerChange.cpp
@@ -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
diff --git a/clang/lib/Lex/Pragma.cpp b/clang/lib/Lex/Pragma.cpp
index c89061ba6d02..27765af34fed 100644
--- a/clang/lib/Lex/Pragma.cpp
+++ b/clang/lib/Lex/Pragma.cpp
@@ -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"));
diff --git a/clang/lib/Lex/Preprocessor.cpp b/clang/lib/Lex/Preprocessor.cpp
index 32ea8791d29a..e376fff90432 100644
--- a/clang/lib/Lex/Preprocessor.cpp
+++ b/clang/lib/Lex/Preprocessor.cpp
@@ -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()))
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index f4f5f461e3b6..939323517b4d 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -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)
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index 5d3de06e9576..a54bd8719178 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -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));
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index b78331cdfe91..bca21b351c91 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -1525,18 +1525,20 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
break;
case DeclSpec::TST_float: Result = Context.FloatTy; break;
case DeclSpec::TST_double:
+ 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_double_requires_extension)
- << (S.getLangOpts().OpenCLVersion >= 300);
+ 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);
}
- if (DS.getTypeSpecWidth() == TypeSpecifierWidth::Long)
- Result = Context.LongDoubleTy;
- else
- Result = Context.DoubleTy;
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 << "__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 << OptName;
+ << 0 << Result
+ << (IsOpenCLC30
+ ? "cl_khr_3d_image_writes and __opencl_c_3d_image_writes"
+ : "cl_khr_3d_image_writes");
declarator.setInvalidType();
}
}
diff --git a/libcxx/include/format b/libcxx/include/format
index 0ec4b85ca0a5..cfd851aa9a3d 100644
--- a/libcxx/include/format
+++ b/libcxx/include/format
@@ -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
diff --git a/libcxx/include/ranges b/libcxx/include/ranges
index 47f66fd3f622..5feaf4c322fc 100644
--- a/libcxx/include/ranges
+++ b/libcxx/include/ranges
@@ -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
diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h
index 9144347045b9..a996a815599a 100644
--- a/lld/ELF/Config.h
+++ b/lld/ELF/Config.h
@@ -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 };
@@ -144,8 +148,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;
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index a15959158653..91e7df21a60a 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -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);
@@ -1374,7 +1377,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);
diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td
index bedcf43bbe85..f0e4c11b79eb 100644
--- a/lld/ELF/Options.td
+++ b/lld/ELF/Options.td
@@ -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">;
diff --git a/lld/ELF/Symbols.cpp b/lld/ELF/Symbols.cpp
index 1039be369d9e..496be33dd182 100644
--- a/lld/ELF/Symbols.cpp
+++ b/lld/ELF/Symbols.cpp
@@ -368,8 +368,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;
}
diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp
index 3496df1d2814..187b2ac90c21 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -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;
diff --git a/lld/docs/ReleaseNotes.rst b/lld/docs/ReleaseNotes.rst
index 40439c995f17..a52ee4348f78 100644
--- a/lld/docs/ReleaseNotes.rst
+++ b/lld/docs/ReleaseNotes.rst
@@ -30,6 +30,8 @@ ELF Improvements
(`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>`_)
Breaking changes
----------------
diff --git a/lld/docs/ld.lld.1 b/lld/docs/ld.lld.1
index ba3b0779e699..bd67e58daa4d 100644
--- a/lld/docs/ld.lld.1
+++ b/lld/docs/ld.lld.1
@@ -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
diff --git a/llvm/include/llvm/CodeGen/TargetLowering.h b/llvm/include/llvm/CodeGen/TargetLowering.h
index 692dc4d7d4cf..a4955e2a973a 100644
--- a/llvm/include/llvm/CodeGen/TargetLowering.h
+++ b/llvm/include/llvm/CodeGen/TargetLowering.h
@@ -1396,6 +1396,11 @@ public:
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),
diff --git a/llvm/include/llvm/CodeGen/ValueTypes.td b/llvm/include/llvm/CodeGen/ValueTypes.td
index 0e88e705e16b..8bacf687ac76 100644
--- a/llvm/include/llvm/CodeGen/ValueTypes.td
+++ b/llvm/include/llvm/CodeGen/ValueTypes.td
@@ -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
diff --git a/llvm/include/llvm/Support/MachineValueType.h b/llvm/include/llvm/Support/MachineValueType.h
index 31f2d5a48183..5c73cece85c3 100644
--- a/llvm/include/llvm/Support/MachineValueType.h
+++ b/llvm/include/llvm/Support/MachineValueType.h
@@ -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:
diff --git a/llvm/lib/Analysis/TargetLibraryInfo.cpp b/llvm/lib/Analysis/TargetLibraryInfo.cpp
index 4a8818f2e2a8..c3a609ee4fe1 100644
--- a/llvm/lib/Analysis/TargetLibraryInfo.cpp
+++ b/llvm/lib/Analysis/TargetLibraryInfo.cpp
@@ -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() &&
diff --git a/llvm/lib/CodeGen/GlobalISel/InlineAsmLowering.cpp b/llvm/lib/CodeGen/GlobalISel/InlineAsmLowering.cpp
index bb4d41cfd69f..4ae427484945 100644
--- a/llvm/lib/CodeGen/GlobalISel/InlineAsmLowering.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/InlineAsmLowering.cpp
@@ -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);
diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index b104e995019f..1bba7232eb14 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -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))) {
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index d56d4bcc9169..a08548393979 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -8176,7 +8176,7 @@ public:
}
}
- 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 {
diff --git a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
index 1c1dae8f953f..5e1786958b6f 100644
--- a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
@@ -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;
diff --git a/llvm/lib/CodeGen/ValueTypes.cpp b/llvm/lib/CodeGen/ValueTypes.cpp
index 9daebfd9e63d..4876b9e23717 100644
--- a/llvm/lib/CodeGen/ValueTypes.cpp
+++ b/llvm/lib/CodeGen/ValueTypes.cpp
@@ -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:
diff --git a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
index adefe3b37ee0..3ab9b250749a 100644
--- a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
+++ b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
@@ -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)) {
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index ae702eedcd66..ca6b87a5ebb0 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -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)
@@ -4611,17 +4619,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");
@@ -8179,6 +8221,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);
@@ -8266,6 +8310,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(
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.h b/llvm/lib/Target/AArch64/AArch64ISelLowering.h
index 386e1c2d8400..2b337255fc27 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.h
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.h
@@ -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 @@ public:
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.
diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
index 682cec361728..12744e4de09b 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
@@ -8092,6 +8092,20 @@ let AddedComplexity = 10 in {
// FIXME: add SVE dot-product patterns.
}
+// Custom DAG nodes and isel rules to make a 64-byte block out of eight GPRs,
+// so that it can be used as input to inline asm, and vice versa.
+def LS64_BUILD : SDNode<"AArch64ISD::LS64_BUILD", SDTypeProfile<1, 8, []>>;
+def LS64_EXTRACT : SDNode<"AArch64ISD::LS64_EXTRACT", SDTypeProfile<1, 2, []>>;
+def : Pat<(i64x8 (LS64_BUILD GPR64:$x0, GPR64:$x1, GPR64:$x2, GPR64:$x3,
+ GPR64:$x4, GPR64:$x5, GPR64:$x6, GPR64:$x7)),
+ (REG_SEQUENCE GPR64x8Class,
+ $x0, x8sub_0, $x1, x8sub_1, $x2, x8sub_2, $x3, x8sub_3,
+ $x4, x8sub_4, $x5, x8sub_5, $x6, x8sub_6, $x7, x8sub_7)>;
+foreach i = 0-7 in {
+ def : Pat<(i64 (LS64_EXTRACT (i64x8 GPR64x8:$val), (i32 i))),
+ (EXTRACT_SUBREG $val, !cast<SubRegIndex>("x8sub_"#i))>;
+}
+
let Predicates = [HasLS64] in {
def LD64B: LoadStore64B<0b101, "ld64b", (ins GPR64sp:$Rn),
(outs GPR64x8:$Rt)>;
diff --git a/llvm/lib/Target/AArch64/AArch64RegisterInfo.td b/llvm/lib/Target/AArch64/AArch64RegisterInfo.td
index 07dee3ce1fbc..67680e356683 100644
--- a/llvm/lib/Target/AArch64/AArch64RegisterInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64RegisterInfo.td
@@ -732,7 +732,9 @@ def Tuples8X : RegisterTuples<
!foreach(i, [0,1,2,3,4,5,6,7], !cast<SubRegIndex>("x8sub_"#i)),
!foreach(i, [0,1,2,3,4,5,6,7], (trunc (decimate (rotl GPR64, i), 2), 12))>;
-def GPR64x8Class : RegisterClass<"AArch64", [i64], 64, (trunc Tuples8X, 12)>;
+def GPR64x8Class : RegisterClass<"AArch64", [i64x8], 512, (trunc Tuples8X, 12)> {
+ let Size = 512;
+}
def GPR64x8AsmOp : AsmOperandClass {
let Name = "GPR64x8";
let ParserMethod = "tryParseGPR64x8";
diff --git a/llvm/lib/Target/AArch64/Utils/AArch64BaseInfo.h b/llvm/lib/Target/AArch64/Utils/AArch64BaseInfo.h
index ce6866154242..d168c2a84bbe 100644
--- a/llvm/lib/Target/AArch64/Utils/AArch64BaseInfo.h
+++ b/llvm/lib/Target/AArch64/Utils/AArch64BaseInfo.h
@@ -106,6 +106,25 @@ inline static unsigned getXRegFromWReg(unsigned Reg) {
return Reg;
}
+inline static unsigned getXRegFromXRegTuple(unsigned RegTuple) {
+ switch (RegTuple) {
+ case AArch64::X0_X1_X2_X3_X4_X5_X6_X7: return AArch64::X0;
+ case AArch64::X2_X3_X4_X5_X6_X7_X8_X9: return AArch64::X2;
+ case AArch64::X4_X5_X6_X7_X8_X9_X10_X11: return AArch64::X4;
+ case AArch64::X6_X7_X8_X9_X10_X11_X12_X13: return AArch64::X6;
+ case AArch64::X8_X9_X10_X11_X12_X13_X14_X15: return AArch64::X8;
+ case AArch64::X10_X11_X12_X13_X14_X15_X16_X17: return AArch64::X10;
+ case AArch64::X12_X13_X14_X15_X16_X17_X18_X19: return AArch64::X12;
+ case AArch64::X14_X15_X16_X17_X18_X19_X20_X21: return AArch64::X14;
+ case AArch64::X16_X17_X18_X19_X20_X21_X22_X23: return AArch64::X16;
+ case AArch64::X18_X19_X20_X21_X22_X23_X24_X25: return AArch64::X18;
+ case AArch64::X20_X21_X22_X23_X24_X25_X26_X27: return AArch64::X20;
+ case AArch64::X22_X23_X24_X25_X26_X27_X28_FP: return AArch64::X22;
+ }
+ // For anything else, return it unchanged.
+ return RegTuple;
+}
+
static inline unsigned getBRegFromDReg(unsigned Reg) {
switch (Reg) {
case AArch64::D0: return AArch64::B0;
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index d37ed584d9d2..294532011650 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -5814,6 +5814,13 @@ static SDValue performANY_EXTENDCombine(SDNode *N,
break;
}
+ // Only handle cases where the result is used by a CopyToReg that likely
+ // means the value is a liveout of the basic block. This helps prevent
+ // infinite combine loops like PR51206.
+ if (none_of(N->uses(),
+ [](SDNode *User) { return User->getOpcode() == ISD::CopyToReg; }))
+ return SDValue();
+
SmallVector<SDNode *, 4> SetCCs;
for (SDNode::use_iterator UI = Src.getNode()->use_begin(),
UE = Src.getNode()->use_end();
diff --git a/llvm/lib/Transforms/Scalar/DivRemPairs.cpp b/llvm/lib/Transforms/Scalar/DivRemPairs.cpp
index c77769368ede..66c9d9f0902a 100644
--- a/llvm/lib/Transforms/Scalar/DivRemPairs.cpp
+++ b/llvm/lib/Transforms/Scalar/DivRemPairs.cpp
@@ -272,9 +272,10 @@ static bool optimizeDivRem(Function &F, const TargetTransformInfo &TTI,
if (PredBB && IsSafeToHoist(RemInst, RemBB) &&
IsSafeToHoist(DivInst, DivBB) &&
- llvm::all_of(successors(PredBB), [&](BasicBlock *BB) {
- return BB == DivBB || BB == RemBB;
- })) {
+ all_of(successors(PredBB),
+ [&](BasicBlock *BB) { return BB == DivBB || BB == RemBB; }) &&
+ all_of(predecessors(DivBB),
+ [&](BasicBlock *BB) { return BB == RemBB || BB == PredBB; })) {
DivDominates = true;
DivInst->moveBefore(PredBB->getTerminator());
Changed = true;
diff --git a/llvm/utils/TableGen/CodeGenTarget.cpp b/llvm/utils/TableGen/CodeGenTarget.cpp
index 7311819f77ff..137f99078faf 100644
--- a/llvm/utils/TableGen/CodeGenTarget.cpp
+++ b/llvm/utils/TableGen/CodeGenTarget.cpp
@@ -77,6 +77,7 @@ StringRef llvm::getEnumName(MVT::SimpleValueType T) {
case MVT::ppcf128: return "MVT::ppcf128";
case MVT::x86mmx: return "MVT::x86mmx";
case MVT::x86amx: return "MVT::x86amx";
+ case MVT::i64x8: return "MVT::i64x8";
case MVT::Glue: return "MVT::Glue";
case MVT::isVoid: return "MVT::isVoid";
case MVT::v1i1: return "MVT::v1i1";