mirror of
https://github.com/opnsense/src.git
synced 2026-05-28 04:12:45 -04:00
Merge llvm-project release/19.x llvmorg-19.1.0-rc3-0-g437434df21d8
This updates llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and openmp to llvm-project release/19.x llvmorg-19.1.0-rc3-0-g437434df21d8. PR: 280562 MFC after: 1 month (cherry picked from commit 62987288060ff68c817b7056815aa9fb8ba8ecd7)
This commit is contained in:
parent
bbe070a078
commit
33d8457b61
117 changed files with 1236 additions and 1455 deletions
|
|
@ -670,6 +670,13 @@ public:
|
|||
/// Whether this declaration comes from another module unit.
|
||||
bool isInAnotherModuleUnit() const;
|
||||
|
||||
/// Whether this declaration comes from the same module unit being compiled.
|
||||
bool isInCurrentModuleUnit() const;
|
||||
|
||||
/// Whether the definition of the declaration should be emitted in external
|
||||
/// sources.
|
||||
bool shouldEmitInExternalSource() const;
|
||||
|
||||
/// Whether this declaration comes from explicit global module.
|
||||
bool isFromExplicitGlobalModule() const;
|
||||
|
||||
|
|
|
|||
|
|
@ -3229,7 +3229,7 @@ class UnresolvedLookupExpr final
|
|||
const DeclarationNameInfo &NameInfo, bool RequiresADL,
|
||||
const TemplateArgumentListInfo *TemplateArgs,
|
||||
UnresolvedSetIterator Begin, UnresolvedSetIterator End,
|
||||
bool KnownDependent);
|
||||
bool KnownDependent, bool KnownInstantiationDependent);
|
||||
|
||||
UnresolvedLookupExpr(EmptyShell Empty, unsigned NumResults,
|
||||
bool HasTemplateKWAndArgsInfo);
|
||||
|
|
@ -3248,7 +3248,7 @@ public:
|
|||
NestedNameSpecifierLoc QualifierLoc,
|
||||
const DeclarationNameInfo &NameInfo, bool RequiresADL,
|
||||
UnresolvedSetIterator Begin, UnresolvedSetIterator End,
|
||||
bool KnownDependent);
|
||||
bool KnownDependent, bool KnownInstantiationDependent);
|
||||
|
||||
// After canonicalization, there may be dependent template arguments in
|
||||
// CanonicalConverted But none of Args is dependent. When any of
|
||||
|
|
@ -3258,7 +3258,8 @@ public:
|
|||
NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc,
|
||||
const DeclarationNameInfo &NameInfo, bool RequiresADL,
|
||||
const TemplateArgumentListInfo *Args, UnresolvedSetIterator Begin,
|
||||
UnresolvedSetIterator End, bool KnownDependent);
|
||||
UnresolvedSetIterator End, bool KnownDependent,
|
||||
bool KnownInstantiationDependent);
|
||||
|
||||
static UnresolvedLookupExpr *CreateEmpty(const ASTContext &Context,
|
||||
unsigned NumResults,
|
||||
|
|
|
|||
|
|
@ -1260,9 +1260,6 @@ def warn_pragma_intrinsic_builtin : Warning<
|
|||
def warn_pragma_unused_expected_var : Warning<
|
||||
"expected '#pragma unused' argument to be a variable name">,
|
||||
InGroup<IgnoredPragmas>;
|
||||
// - #pragma mc_func
|
||||
def err_pragma_mc_func_not_supported :
|
||||
Error<"#pragma mc_func is not supported">;
|
||||
// - #pragma init_seg
|
||||
def warn_pragma_init_seg_unsupported_target : Warning<
|
||||
"'#pragma init_seg' is only supported when targeting a "
|
||||
|
|
|
|||
|
|
@ -159,6 +159,12 @@ public:
|
|||
};
|
||||
|
||||
struct PointerAuthOptions {
|
||||
/// Should return addresses be authenticated?
|
||||
bool ReturnAddresses = false;
|
||||
|
||||
/// Do authentication failures cause a trap?
|
||||
bool AuthTraps = false;
|
||||
|
||||
/// Do indirect goto label addresses need to be authenticated?
|
||||
bool IndirectGotos = false;
|
||||
|
||||
|
|
|
|||
|
|
@ -2116,7 +2116,7 @@ def SVFCLAMP_BF : SInst<"svclamp[_{d}]", "dddd", "b", MergeNone, "aarch64_sve_
|
|||
multiclass MinMaxIntr<string i, string zm, string mul, string t> {
|
||||
def SVS # NAME : SInst<"sv" # i # "[" # zm # "_{d}_" # mul # "]", t, "csil", MergeNone, "aarch64_sve_s" # i # zm # "_" # mul, [IsStreaming], []>;
|
||||
def SVU # NAME : SInst<"sv" # i # "[" # zm # "_{d}_" # mul # "]", t, "UcUsUiUl", MergeNone, "aarch64_sve_u" # i # zm # "_" # mul, [IsStreaming], []>;
|
||||
def SVF # NAME : SInst<"sv" # i # "[" # zm # "_{d}_" # mul # "]", t, "bhfd", MergeNone, "aarch64_sve_f" # i # zm # "_" # mul, [IsStreaming], []>;
|
||||
def SVF # NAME : SInst<"sv" # i # "[" # zm # "_{d}_" # mul # "]", t, "hfd", MergeNone, "aarch64_sve_f" # i # zm # "_" # mul, [IsStreaming], []>;
|
||||
}
|
||||
|
||||
let SVETargetGuard = InvalidMode, SMETargetGuard = "sme2" in {
|
||||
|
|
@ -2134,11 +2134,11 @@ let SVETargetGuard = InvalidMode, SMETargetGuard = "sme2" in {
|
|||
}
|
||||
|
||||
multiclass SInstMinMaxByVector<string name> {
|
||||
def NAME # _SINGLE_X2 : SInst<"sv" # name # "nm[_single_{d}_x2]", "22d", "bhfd", MergeNone, "aarch64_sve_f" # name # "nm_single_x2", [IsStreaming], []>;
|
||||
def NAME # _SINGLE_X4 : SInst<"sv" # name # "nm[_single_{d}_x4]", "44d", "bhfd", MergeNone, "aarch64_sve_f" # name # "nm_single_x4", [IsStreaming], []>;
|
||||
def NAME # _SINGLE_X2 : SInst<"sv" # name # "nm[_single_{d}_x2]", "22d", "hfd", MergeNone, "aarch64_sve_f" # name # "nm_single_x2", [IsStreaming], []>;
|
||||
def NAME # _SINGLE_X4 : SInst<"sv" # name # "nm[_single_{d}_x4]", "44d", "hfd", MergeNone, "aarch64_sve_f" # name # "nm_single_x4", [IsStreaming], []>;
|
||||
|
||||
def NAME # _X2 : SInst<"sv" # name # "nm[_{d}_x2]", "222", "bhfd", MergeNone, "aarch64_sve_f" # name # "nm_x2", [IsStreaming], []>;
|
||||
def NAME # _X4 : SInst<"sv" # name # "nm[_{d}_x4]", "444", "bhfd", MergeNone, "aarch64_sve_f" # name # "nm_x4", [IsStreaming], []>;
|
||||
def NAME # _X2 : SInst<"sv" # name # "nm[_{d}_x2]", "222", "hfd", MergeNone, "aarch64_sve_f" # name # "nm_x2", [IsStreaming], []>;
|
||||
def NAME # _X4 : SInst<"sv" # name # "nm[_{d}_x4]", "444", "hfd", MergeNone, "aarch64_sve_f" # name # "nm_x4", [IsStreaming], []>;
|
||||
}
|
||||
|
||||
let SVETargetGuard = InvalidMode, SMETargetGuard = "sme2" in {
|
||||
|
|
@ -2172,9 +2172,25 @@ let SVETargetGuard = InvalidMode, SMETargetGuard = "sme2" in {
|
|||
def SVFCLAMP_X4 : SInst<"svclamp[_single_{d}_x4]", "44dd", "hfd", MergeNone, "aarch64_sve_fclamp_single_x4", [IsStreaming], []>;
|
||||
}
|
||||
|
||||
multiclass BfSingleMultiVector<string name> {
|
||||
def NAME # _SINGLE_X2 : SInst<"sv" # name # "[_single_{d}_x2]", "22d", "b", MergeNone, "aarch64_sve_f" # name # "_single_x2", [IsStreaming], []>;
|
||||
def NAME # _SINGLE_X4 : SInst<"sv" # name # "[_single_{d}_x4]", "44d", "b", MergeNone, "aarch64_sve_f" # name # "_single_x4", [IsStreaming], []>;
|
||||
|
||||
def NAME # _X2 : SInst<"sv" # name # "[_{d}_x2]", "222", "b", MergeNone, "aarch64_sve_f" # name # "_x2", [IsStreaming], []>;
|
||||
def NAME # _X4 : SInst<"sv" # name # "[_{d}_x4]", "444", "b", MergeNone, "aarch64_sve_f" # name # "_x4", [IsStreaming], []>;
|
||||
}
|
||||
|
||||
let SVETargetGuard = InvalidMode, SMETargetGuard = "sme2,b16b16"in {
|
||||
def SVBFCLAMP_X2 : SInst<"svclamp[_single_{d}_x2]", "22dd", "b", MergeNone, "aarch64_sve_bfclamp_single_x2", [IsStreaming], []>;
|
||||
def SVBFCLAMP_X4 : SInst<"svclamp[_single_{d}_x4]", "44dd", "b", MergeNone, "aarch64_sve_bfclamp_single_x4", [IsStreaming], []>;
|
||||
|
||||
// bfmin, bfmax (single, multi)
|
||||
defm SVBFMIN : BfSingleMultiVector<"min">;
|
||||
defm SVBFMAX : BfSingleMultiVector<"max">;
|
||||
|
||||
// bfminnm, bfmaxnm (single, multi)
|
||||
defm SVBFMINNM : BfSingleMultiVector<"minnm">;
|
||||
defm SVBFMAXNM : BfSingleMultiVector<"maxnm">;
|
||||
}
|
||||
|
||||
let SVETargetGuard = InvalidMode, SMETargetGuard = "sme2" in {
|
||||
|
|
|
|||
|
|
@ -932,8 +932,9 @@ def O_flag : Flag<["-"], "O">, Visibility<[ClangOption, CC1Option, FC1Option]>,
|
|||
Alias<O>, AliasArgs<["1"]>;
|
||||
def Ofast : Joined<["-"], "Ofast">, Group<O_Group>,
|
||||
Visibility<[ClangOption, CC1Option, FlangOption]>,
|
||||
HelpText<"Deprecated; use '-O3 -ffast-math' for the same behavior,"
|
||||
" or '-O3' to enable only conforming optimizations">;
|
||||
HelpTextForVariants<[ClangOption, CC1Option],
|
||||
"Deprecated; use '-O3 -ffast-math' for the same behavior,"
|
||||
" or '-O3' to enable only conforming optimizations">;
|
||||
def P : Flag<["-"], "P">,
|
||||
Visibility<[ClangOption, CC1Option, FlangOption, FC1Option]>,
|
||||
Group<Preprocessor_Group>,
|
||||
|
|
@ -3106,7 +3107,7 @@ def fmodules_user_build_path : Separate<["-"], "fmodules-user-build-path">, Grou
|
|||
HelpText<"Specify the module user build path">,
|
||||
MarshallingInfoString<HeaderSearchOpts<"ModuleUserBuildPath">>;
|
||||
def fprebuilt_module_path : Joined<["-"], "fprebuilt-module-path=">, Group<i_Group>,
|
||||
Flags<[]>, Visibility<[ClangOption, CC1Option]>,
|
||||
Flags<[]>, Visibility<[ClangOption, CLOption, CC1Option]>,
|
||||
MetaVarName<"<directory>">,
|
||||
HelpText<"Specify the prebuilt module path">;
|
||||
defm prebuilt_implicit_modules : BoolFOption<"prebuilt-implicit-modules",
|
||||
|
|
@ -3115,11 +3116,11 @@ defm prebuilt_implicit_modules : BoolFOption<"prebuilt-implicit-modules",
|
|||
NegFlag<SetFalse>, BothFlags<[], [ClangOption, CC1Option]>>;
|
||||
|
||||
def fmodule_output_EQ : Joined<["-"], "fmodule-output=">,
|
||||
Flags<[NoXarchOption]>, Visibility<[ClangOption, CC1Option]>,
|
||||
Flags<[NoXarchOption]>, Visibility<[ClangOption, CLOption, CC1Option]>,
|
||||
MarshallingInfoString<FrontendOpts<"ModuleOutputPath">>,
|
||||
HelpText<"Save intermediate module file results when compiling a standard C++ module unit.">;
|
||||
def fmodule_output : Flag<["-"], "fmodule-output">, Flags<[NoXarchOption]>,
|
||||
Visibility<[ClangOption, CC1Option]>,
|
||||
Visibility<[ClangOption, CLOption, CC1Option]>,
|
||||
HelpText<"Save intermediate module file results when compiling a standard C++ module unit.">;
|
||||
|
||||
defm skip_odr_check_in_gmf : BoolOption<"f", "skip-odr-check-in-gmf",
|
||||
|
|
@ -3299,8 +3300,10 @@ def fretain_comments_from_system_headers : Flag<["-"], "fretain-comments-from-sy
|
|||
Visibility<[ClangOption, CC1Option]>,
|
||||
MarshallingInfoFlag<LangOpts<"RetainCommentsFromSystemHeaders">>;
|
||||
def fmodule_header : Flag <["-"], "fmodule-header">, Group<f_Group>,
|
||||
Visibility<[ClangOption, CLOption]>,
|
||||
HelpText<"Build a C++20 Header Unit from a header">;
|
||||
def fmodule_header_EQ : Joined<["-"], "fmodule-header=">, Group<f_Group>,
|
||||
Visibility<[ClangOption, CLOption]>,
|
||||
MetaVarName<"<kind>">,
|
||||
HelpText<"Build a C++20 Header Unit from a header that should be found in the user (fmodule-header=user) or system (fmodule-header=system) search path.">;
|
||||
|
||||
|
|
@ -5945,6 +5948,7 @@ def _output : Separate<["--"], "output">, Alias<o>;
|
|||
def _param : Separate<["--"], "param">, Group<CompileOnly_Group>;
|
||||
def _param_EQ : Joined<["--"], "param=">, Alias<_param>;
|
||||
def _precompile : Flag<["--"], "precompile">, Flags<[NoXarchOption]>,
|
||||
Visibility<[ClangOption, CLOption]>,
|
||||
Group<Action_Group>, HelpText<"Only precompile the input">;
|
||||
def _prefix_EQ : Joined<["--"], "prefix=">, Alias<B>;
|
||||
def _prefix : Separate<["--"], "prefix">, Alias<B>;
|
||||
|
|
@ -8086,13 +8090,6 @@ def source_date_epoch : Separate<["-"], "source-date-epoch">,
|
|||
|
||||
} // let Visibility = [CC1Option]
|
||||
|
||||
defm err_pragma_mc_func_aix : BoolFOption<"err-pragma-mc-func-aix",
|
||||
PreprocessorOpts<"ErrorOnPragmaMcfuncOnAIX">, DefaultFalse,
|
||||
PosFlag<SetTrue, [], [ClangOption, CC1Option],
|
||||
"Treat uses of #pragma mc_func as errors">,
|
||||
NegFlag<SetFalse,[], [ClangOption, CC1Option],
|
||||
"Ignore uses of #pragma mc_func">>;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// CUDA Options
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
|||
|
|
@ -211,10 +211,6 @@ public:
|
|||
/// If set, the UNIX timestamp specified by SOURCE_DATE_EPOCH.
|
||||
std::optional<uint64_t> SourceDateEpoch;
|
||||
|
||||
/// If set, the preprocessor reports an error when processing #pragma mc_func
|
||||
/// on AIX.
|
||||
bool ErrorOnPragmaMcfuncOnAIX = false;
|
||||
|
||||
public:
|
||||
PreprocessorOptions() : PrecompiledPreambleBytes(0, false) {}
|
||||
|
||||
|
|
@ -252,7 +248,6 @@ public:
|
|||
PrecompiledPreambleBytes.first = 0;
|
||||
PrecompiledPreambleBytes.second = false;
|
||||
RetainExcludedConditionalBlocks = false;
|
||||
ErrorOnPragmaMcfuncOnAIX = false;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -221,7 +221,6 @@ class Parser : public CodeCompletionHandler {
|
|||
std::unique_ptr<PragmaHandler> MaxTokensHerePragmaHandler;
|
||||
std::unique_ptr<PragmaHandler> MaxTokensTotalPragmaHandler;
|
||||
std::unique_ptr<PragmaHandler> RISCVPragmaHandler;
|
||||
std::unique_ptr<PragmaHandler> MCFuncPragmaHandler;
|
||||
|
||||
std::unique_ptr<CommentHandler> CommentSemaHandler;
|
||||
|
||||
|
|
|
|||
|
|
@ -721,6 +721,9 @@ enum ASTRecordTypes {
|
|||
|
||||
/// Record code for \#pragma clang unsafe_buffer_usage begin/end
|
||||
PP_UNSAFE_BUFFER_USAGE = 69,
|
||||
|
||||
/// Record code for vtables to emit.
|
||||
VTABLES_TO_EMIT = 70,
|
||||
};
|
||||
|
||||
/// Record types used within a source manager block.
|
||||
|
|
|
|||
|
|
@ -790,6 +790,11 @@ private:
|
|||
/// the consumer eagerly.
|
||||
SmallVector<GlobalDeclID, 16> EagerlyDeserializedDecls;
|
||||
|
||||
/// The IDs of all vtables to emit. The referenced declarations are passed
|
||||
/// to the consumers' HandleVTable eagerly after passing
|
||||
/// EagerlyDeserializedDecls.
|
||||
SmallVector<GlobalDeclID, 16> VTablesToEmit;
|
||||
|
||||
/// The IDs of all tentative definitions stored in the chain.
|
||||
///
|
||||
/// Sema keeps track of all tentative definitions in a TU because it has to
|
||||
|
|
@ -1500,6 +1505,7 @@ private:
|
|||
bool isConsumerInterestedIn(Decl *D);
|
||||
void PassInterestingDeclsToConsumer();
|
||||
void PassInterestingDeclToConsumer(Decl *D);
|
||||
void PassVTableToConsumer(CXXRecordDecl *RD);
|
||||
|
||||
void finishPendingActions();
|
||||
void diagnoseOdrViolations();
|
||||
|
|
|
|||
|
|
@ -500,6 +500,10 @@ private:
|
|||
std::vector<SourceRange> NonAffectingRanges;
|
||||
std::vector<SourceLocation::UIntTy> NonAffectingOffsetAdjustments;
|
||||
|
||||
/// A list of classes which need to emit the VTable in the corresponding
|
||||
/// object file.
|
||||
llvm::SmallVector<CXXRecordDecl *> PendingEmittingVTables;
|
||||
|
||||
/// Computes input files that didn't affect compilation of the current module,
|
||||
/// and initializes data structures necessary for leaving those files out
|
||||
/// during \c SourceManager serialization.
|
||||
|
|
@ -857,6 +861,8 @@ public:
|
|||
return PredefinedDecls.count(D);
|
||||
}
|
||||
|
||||
void handleVTable(CXXRecordDecl *RD);
|
||||
|
||||
private:
|
||||
// ASTDeserializationListener implementation
|
||||
void ReaderInitialized(ASTReader *Reader) override;
|
||||
|
|
@ -951,6 +957,7 @@ public:
|
|||
|
||||
void InitializeSema(Sema &S) override { SemaPtr = &S; }
|
||||
void HandleTranslationUnit(ASTContext &Ctx) override;
|
||||
void HandleVTable(CXXRecordDecl *RD) override { Writer.handleVTable(RD); }
|
||||
ASTMutationListener *GetASTMutationListener() override;
|
||||
ASTDeserializationListener *GetASTDeserializationListener() override;
|
||||
bool hasEmittedPCH() const { return Buffer->IsComplete; }
|
||||
|
|
|
|||
|
|
@ -12405,8 +12405,7 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) {
|
|||
!isMSStaticDataMemberInlineDefinition(VD))
|
||||
return false;
|
||||
|
||||
// Variables in other module units shouldn't be forced to be emitted.
|
||||
if (VD->isInAnotherModuleUnit())
|
||||
if (VD->shouldEmitInExternalSource())
|
||||
return false;
|
||||
|
||||
// Variables that can be needed in other TUs are required.
|
||||
|
|
|
|||
|
|
@ -8578,13 +8578,15 @@ ASTNodeImporter::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E) {
|
|||
return UnresolvedLookupExpr::Create(
|
||||
Importer.getToContext(), *ToNamingClassOrErr, *ToQualifierLocOrErr,
|
||||
*ToTemplateKeywordLocOrErr, ToNameInfo, E->requiresADL(), &ToTAInfo,
|
||||
ToDecls.begin(), ToDecls.end(), KnownDependent);
|
||||
ToDecls.begin(), ToDecls.end(), KnownDependent,
|
||||
/*KnownInstantiationDependent=*/E->isInstantiationDependent());
|
||||
}
|
||||
|
||||
return UnresolvedLookupExpr::Create(
|
||||
Importer.getToContext(), *ToNamingClassOrErr, *ToQualifierLocOrErr,
|
||||
ToNameInfo, E->requiresADL(), ToDecls.begin(), ToDecls.end(),
|
||||
/*KnownDependent=*/E->isTypeDependent());
|
||||
/*KnownDependent=*/E->isTypeDependent(),
|
||||
/*KnownInstantiationDependent=*/E->isInstantiationDependent());
|
||||
}
|
||||
|
||||
ExpectedStmt
|
||||
|
|
|
|||
|
|
@ -1125,22 +1125,38 @@ bool Decl::isInAnotherModuleUnit() const {
|
|||
if (!M)
|
||||
return false;
|
||||
|
||||
// FIXME or NOTE: maybe we need to be clear about the semantics
|
||||
// of clang header modules. e.g., if this lives in a clang header
|
||||
// module included by the current unit, should we return false
|
||||
// here?
|
||||
//
|
||||
// This is clear for header units as the specification says the
|
||||
// header units live in a synthesised translation unit. So we
|
||||
// can return false here.
|
||||
M = M->getTopLevelModule();
|
||||
// FIXME: It is problematic if the header module lives in another module
|
||||
// unit. Consider to fix this by techniques like
|
||||
// ExternalASTSource::hasExternalDefinitions.
|
||||
if (M->isHeaderLikeModule())
|
||||
if (!M->isNamedModule())
|
||||
return false;
|
||||
|
||||
// A global module without parent implies that we're parsing the global
|
||||
// module. So it can't be in another module unit.
|
||||
if (M->isGlobalModule())
|
||||
return false;
|
||||
|
||||
assert(M->isNamedModule() && "New module kind?");
|
||||
return M != getASTContext().getCurrentNamedModule();
|
||||
}
|
||||
|
||||
bool Decl::isInCurrentModuleUnit() const {
|
||||
auto *M = getOwningModule();
|
||||
|
||||
if (!M || !M->isNamedModule())
|
||||
return false;
|
||||
|
||||
return M == getASTContext().getCurrentNamedModule();
|
||||
}
|
||||
|
||||
bool Decl::shouldEmitInExternalSource() const {
|
||||
ExternalASTSource *Source = getASTContext().getExternalSource();
|
||||
if (!Source)
|
||||
return false;
|
||||
|
||||
return Source->hasExternalDefinitions(this) == ExternalASTSource::EK_Always;
|
||||
}
|
||||
|
||||
bool Decl::isFromExplicitGlobalModule() const {
|
||||
return getOwningModule() && getOwningModule()->isExplicitGlobalModule();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -402,10 +402,11 @@ UnresolvedLookupExpr::UnresolvedLookupExpr(
|
|||
NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc,
|
||||
const DeclarationNameInfo &NameInfo, bool RequiresADL,
|
||||
const TemplateArgumentListInfo *TemplateArgs, UnresolvedSetIterator Begin,
|
||||
UnresolvedSetIterator End, bool KnownDependent)
|
||||
UnresolvedSetIterator End, bool KnownDependent,
|
||||
bool KnownInstantiationDependent)
|
||||
: OverloadExpr(UnresolvedLookupExprClass, Context, QualifierLoc,
|
||||
TemplateKWLoc, NameInfo, TemplateArgs, Begin, End,
|
||||
KnownDependent, false, false),
|
||||
KnownDependent, KnownInstantiationDependent, false),
|
||||
NamingClass(NamingClass) {
|
||||
UnresolvedLookupExprBits.RequiresADL = RequiresADL;
|
||||
}
|
||||
|
|
@ -420,7 +421,7 @@ UnresolvedLookupExpr *UnresolvedLookupExpr::Create(
|
|||
const ASTContext &Context, CXXRecordDecl *NamingClass,
|
||||
NestedNameSpecifierLoc QualifierLoc, const DeclarationNameInfo &NameInfo,
|
||||
bool RequiresADL, UnresolvedSetIterator Begin, UnresolvedSetIterator End,
|
||||
bool KnownDependent) {
|
||||
bool KnownDependent, bool KnownInstantiationDependent) {
|
||||
unsigned NumResults = End - Begin;
|
||||
unsigned Size = totalSizeToAlloc<DeclAccessPair, ASTTemplateKWAndArgsInfo,
|
||||
TemplateArgumentLoc>(NumResults, 0, 0);
|
||||
|
|
@ -428,7 +429,8 @@ UnresolvedLookupExpr *UnresolvedLookupExpr::Create(
|
|||
return new (Mem) UnresolvedLookupExpr(
|
||||
Context, NamingClass, QualifierLoc,
|
||||
/*TemplateKWLoc=*/SourceLocation(), NameInfo, RequiresADL,
|
||||
/*TemplateArgs=*/nullptr, Begin, End, KnownDependent);
|
||||
/*TemplateArgs=*/nullptr, Begin, End, KnownDependent,
|
||||
KnownInstantiationDependent);
|
||||
}
|
||||
|
||||
UnresolvedLookupExpr *UnresolvedLookupExpr::Create(
|
||||
|
|
@ -436,7 +438,8 @@ UnresolvedLookupExpr *UnresolvedLookupExpr::Create(
|
|||
NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc,
|
||||
const DeclarationNameInfo &NameInfo, bool RequiresADL,
|
||||
const TemplateArgumentListInfo *Args, UnresolvedSetIterator Begin,
|
||||
UnresolvedSetIterator End, bool KnownDependent) {
|
||||
UnresolvedSetIterator End, bool KnownDependent,
|
||||
bool KnownInstantiationDependent) {
|
||||
unsigned NumResults = End - Begin;
|
||||
bool HasTemplateKWAndArgsInfo = Args || TemplateKWLoc.isValid();
|
||||
unsigned NumTemplateArgs = Args ? Args->size() : 0;
|
||||
|
|
@ -444,9 +447,9 @@ UnresolvedLookupExpr *UnresolvedLookupExpr::Create(
|
|||
TemplateArgumentLoc>(
|
||||
NumResults, HasTemplateKWAndArgsInfo, NumTemplateArgs);
|
||||
void *Mem = Context.Allocate(Size, alignof(UnresolvedLookupExpr));
|
||||
return new (Mem) UnresolvedLookupExpr(Context, NamingClass, QualifierLoc,
|
||||
TemplateKWLoc, NameInfo, RequiresADL,
|
||||
Args, Begin, End, KnownDependent);
|
||||
return new (Mem) UnresolvedLookupExpr(
|
||||
Context, NamingClass, QualifierLoc, TemplateKWLoc, NameInfo, RequiresADL,
|
||||
Args, Begin, End, KnownDependent, KnownInstantiationDependent);
|
||||
}
|
||||
|
||||
UnresolvedLookupExpr *UnresolvedLookupExpr::CreateEmpty(
|
||||
|
|
|
|||
|
|
@ -2032,7 +2032,7 @@ static void getTrivialDefaultFunctionAttributes(
|
|||
}
|
||||
|
||||
TargetInfo::BranchProtectionInfo BPI(LangOpts);
|
||||
TargetCodeGenInfo::setBranchProtectionFnAttributes(BPI, FuncAttrs);
|
||||
TargetCodeGenInfo::initBranchProtectionFnAttributes(BPI, FuncAttrs);
|
||||
}
|
||||
|
||||
/// Merges `target-features` from \TargetOpts and \F, and sets the result in
|
||||
|
|
|
|||
|
|
@ -1078,29 +1078,41 @@ llvm::GlobalVariable::LinkageTypes
|
|||
CodeGenModule::getVTableLinkage(const CXXRecordDecl *RD) {
|
||||
if (!RD->isExternallyVisible())
|
||||
return llvm::GlobalVariable::InternalLinkage;
|
||||
|
||||
// We're at the end of the translation unit, so the current key
|
||||
// function is fully correct.
|
||||
const CXXMethodDecl *keyFunction = Context.getCurrentKeyFunction(RD);
|
||||
if (keyFunction && !RD->hasAttr<DLLImportAttr>()) {
|
||||
|
||||
// In windows, the linkage of vtable is not related to modules.
|
||||
bool IsInNamedModule = !getTarget().getCXXABI().isMicrosoft() &&
|
||||
RD->isInNamedModule();
|
||||
// If the CXXRecordDecl is not in a module unit, we need to get
|
||||
// its key function. We're at the end of the translation unit, so the current
|
||||
// key function is fully correct.
|
||||
const CXXMethodDecl *keyFunction =
|
||||
IsInNamedModule ? nullptr : Context.getCurrentKeyFunction(RD);
|
||||
if (IsInNamedModule || (keyFunction && !RD->hasAttr<DLLImportAttr>())) {
|
||||
// If this class has a key function, use that to determine the
|
||||
// linkage of the vtable.
|
||||
const FunctionDecl *def = nullptr;
|
||||
if (keyFunction->hasBody(def))
|
||||
if (keyFunction && keyFunction->hasBody(def))
|
||||
keyFunction = cast<CXXMethodDecl>(def);
|
||||
|
||||
switch (keyFunction->getTemplateSpecializationKind()) {
|
||||
case TSK_Undeclared:
|
||||
case TSK_ExplicitSpecialization:
|
||||
bool IsExternalDefinition =
|
||||
IsInNamedModule ? RD->shouldEmitInExternalSource() : !def;
|
||||
|
||||
TemplateSpecializationKind Kind =
|
||||
IsInNamedModule ? RD->getTemplateSpecializationKind()
|
||||
: keyFunction->getTemplateSpecializationKind();
|
||||
|
||||
switch (Kind) {
|
||||
case TSK_Undeclared:
|
||||
case TSK_ExplicitSpecialization:
|
||||
assert(
|
||||
(def || CodeGenOpts.OptimizationLevel > 0 ||
|
||||
(IsInNamedModule || def || CodeGenOpts.OptimizationLevel > 0 ||
|
||||
CodeGenOpts.getDebugInfo() != llvm::codegenoptions::NoDebugInfo) &&
|
||||
"Shouldn't query vtable linkage without key function, "
|
||||
"optimizations, or debug info");
|
||||
if (!def && CodeGenOpts.OptimizationLevel > 0)
|
||||
"Shouldn't query vtable linkage without the class in module units, "
|
||||
"key function, optimizations, or debug info");
|
||||
if (IsExternalDefinition && CodeGenOpts.OptimizationLevel > 0)
|
||||
return llvm::GlobalVariable::AvailableExternallyLinkage;
|
||||
|
||||
if (keyFunction->isInlined())
|
||||
if (keyFunction && keyFunction->isInlined())
|
||||
return !Context.getLangOpts().AppleKext
|
||||
? llvm::GlobalVariable::LinkOnceODRLinkage
|
||||
: llvm::Function::InternalLinkage;
|
||||
|
|
@ -1119,7 +1131,7 @@ CodeGenModule::getVTableLinkage(const CXXRecordDecl *RD) {
|
|||
|
||||
case TSK_ExplicitInstantiationDeclaration:
|
||||
llvm_unreachable("Should not have been asked to emit this");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -fapple-kext mode does not support weak linkage, so we must use
|
||||
|
|
@ -1213,22 +1225,20 @@ bool CodeGenVTables::isVTableExternal(const CXXRecordDecl *RD) {
|
|||
TSK == TSK_ExplicitInstantiationDefinition)
|
||||
return false;
|
||||
|
||||
// Otherwise, if the class is attached to a module, the tables are uniquely
|
||||
// emitted in the object for the module unit in which it is defined.
|
||||
if (RD->isInNamedModule())
|
||||
return RD->shouldEmitInExternalSource();
|
||||
|
||||
// Otherwise, if the class doesn't have a key function (possibly
|
||||
// anymore), the vtable must be defined here.
|
||||
const CXXMethodDecl *keyFunction = CGM.getContext().getCurrentKeyFunction(RD);
|
||||
if (!keyFunction)
|
||||
return false;
|
||||
|
||||
const FunctionDecl *Def;
|
||||
// Otherwise, if we don't have a definition of the key function, the
|
||||
// vtable must be defined somewhere else.
|
||||
if (!keyFunction->hasBody(Def))
|
||||
return true;
|
||||
|
||||
assert(Def && "The body of the key function is not assigned to Def?");
|
||||
// If the non-inline key function comes from another module unit, the vtable
|
||||
// must be defined there.
|
||||
return Def->isInAnotherModuleUnit() && !Def->isInlineSpecified();
|
||||
return !keyFunction->hasBody();
|
||||
}
|
||||
|
||||
/// Given that we're currently at the end of the translation unit, and
|
||||
|
|
|
|||
|
|
@ -880,8 +880,12 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
|
|||
|
||||
// Add pointer authentication attributes.
|
||||
const CodeGenOptions &CodeGenOpts = CGM.getCodeGenOpts();
|
||||
if (CodeGenOpts.PointerAuth.ReturnAddresses)
|
||||
Fn->addFnAttr("ptrauth-returns");
|
||||
if (CodeGenOpts.PointerAuth.FunctionPointers)
|
||||
Fn->addFnAttr("ptrauth-calls");
|
||||
if (CodeGenOpts.PointerAuth.AuthTraps)
|
||||
Fn->addFnAttr("ptrauth-auth-traps");
|
||||
if (CodeGenOpts.PointerAuth.IndirectGotos)
|
||||
Fn->addFnAttr("ptrauth-indirect-gotos");
|
||||
|
||||
|
|
|
|||
|
|
@ -2315,6 +2315,9 @@ bool ItaniumCXXABI::canSpeculativelyEmitVTable(const CXXRecordDecl *RD) const {
|
|||
if (!canSpeculativelyEmitVTableAsBaseClass(RD))
|
||||
return false;
|
||||
|
||||
if (RD->shouldEmitInExternalSource())
|
||||
return false;
|
||||
|
||||
// For a complete-object vtable (or more specifically, for the VTT), we need
|
||||
// to be able to speculatively emit the vtables of all dynamic virtual bases.
|
||||
for (const auto &B : RD->vbases()) {
|
||||
|
|
|
|||
|
|
@ -209,13 +209,37 @@ llvm::Value *TargetCodeGenInfo::createEnqueuedBlockKernel(
|
|||
|
||||
void TargetCodeGenInfo::setBranchProtectionFnAttributes(
|
||||
const TargetInfo::BranchProtectionInfo &BPI, llvm::Function &F) {
|
||||
llvm::AttrBuilder FuncAttrs(F.getContext());
|
||||
setBranchProtectionFnAttributes(BPI, FuncAttrs);
|
||||
F.addFnAttrs(FuncAttrs);
|
||||
// Called on already created and initialized function where attributes already
|
||||
// set from command line attributes but some might need to be removed as the
|
||||
// actual BPI is different.
|
||||
if (BPI.SignReturnAddr != LangOptions::SignReturnAddressScopeKind::None) {
|
||||
F.addFnAttr("sign-return-address", BPI.getSignReturnAddrStr());
|
||||
F.addFnAttr("sign-return-address-key", BPI.getSignKeyStr());
|
||||
} else {
|
||||
if (F.hasFnAttribute("sign-return-address"))
|
||||
F.removeFnAttr("sign-return-address");
|
||||
if (F.hasFnAttribute("sign-return-address-key"))
|
||||
F.removeFnAttr("sign-return-address-key");
|
||||
}
|
||||
|
||||
auto AddRemoveAttributeAsSet = [&](bool Set, const StringRef &ModAttr) {
|
||||
if (Set)
|
||||
F.addFnAttr(ModAttr);
|
||||
else if (F.hasFnAttribute(ModAttr))
|
||||
F.removeFnAttr(ModAttr);
|
||||
};
|
||||
|
||||
AddRemoveAttributeAsSet(BPI.BranchTargetEnforcement,
|
||||
"branch-target-enforcement");
|
||||
AddRemoveAttributeAsSet(BPI.BranchProtectionPAuthLR,
|
||||
"branch-protection-pauth-lr");
|
||||
AddRemoveAttributeAsSet(BPI.GuardedControlStack, "guarded-control-stack");
|
||||
}
|
||||
|
||||
void TargetCodeGenInfo::setBranchProtectionFnAttributes(
|
||||
void TargetCodeGenInfo::initBranchProtectionFnAttributes(
|
||||
const TargetInfo::BranchProtectionInfo &BPI, llvm::AttrBuilder &FuncAttrs) {
|
||||
// Only used for initializing attributes in the AttrBuilder, which will not
|
||||
// contain any of these attributes so no need to remove anything.
|
||||
if (BPI.SignReturnAddr != LangOptions::SignReturnAddressScopeKind::None) {
|
||||
FuncAttrs.addAttribute("sign-return-address", BPI.getSignReturnAddrStr());
|
||||
FuncAttrs.addAttribute("sign-return-address-key", BPI.getSignKeyStr());
|
||||
|
|
|
|||
|
|
@ -414,13 +414,16 @@ public:
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
// Set the Branch Protection Attributes of the Function accordingly to the
|
||||
// BPI. Remove attributes that contradict with current BPI.
|
||||
static void
|
||||
setBranchProtectionFnAttributes(const TargetInfo::BranchProtectionInfo &BPI,
|
||||
llvm::Function &F);
|
||||
|
||||
// Add the Branch Protection Attributes of the FuncAttrs.
|
||||
static void
|
||||
setBranchProtectionFnAttributes(const TargetInfo::BranchProtectionInfo &BPI,
|
||||
llvm::AttrBuilder &FuncAttrs);
|
||||
initBranchProtectionFnAttributes(const TargetInfo::BranchProtectionInfo &BPI,
|
||||
llvm::AttrBuilder &FuncAttrs);
|
||||
|
||||
protected:
|
||||
static std::string qualifyWindowsLibrary(StringRef Lib);
|
||||
|
|
|
|||
|
|
@ -840,12 +840,13 @@ static bool isStreamingCompatible(const FunctionDecl *F) {
|
|||
static void diagnoseIfNeedsFPReg(DiagnosticsEngine &Diags,
|
||||
const StringRef ABIName,
|
||||
const AArch64ABIInfo &ABIInfo,
|
||||
const QualType &Ty, const NamedDecl *D) {
|
||||
const QualType &Ty, const NamedDecl *D,
|
||||
SourceLocation loc) {
|
||||
const Type *HABase = nullptr;
|
||||
uint64_t HAMembers = 0;
|
||||
if (Ty->isFloatingType() || Ty->isVectorType() ||
|
||||
ABIInfo.isHomogeneousAggregate(Ty, HABase, HAMembers)) {
|
||||
Diags.Report(D->getLocation(), diag::err_target_unsupported_type_for_abi)
|
||||
Diags.Report(loc, diag::err_target_unsupported_type_for_abi)
|
||||
<< D->getDeclName() << Ty << ABIName;
|
||||
}
|
||||
}
|
||||
|
|
@ -860,10 +861,11 @@ void AArch64TargetCodeGenInfo::checkFunctionABI(
|
|||
|
||||
if (!TI.hasFeature("fp") && !ABIInfo.isSoftFloat()) {
|
||||
diagnoseIfNeedsFPReg(CGM.getDiags(), TI.getABI(), ABIInfo,
|
||||
FuncDecl->getReturnType(), FuncDecl);
|
||||
FuncDecl->getReturnType(), FuncDecl,
|
||||
FuncDecl->getLocation());
|
||||
for (ParmVarDecl *PVD : FuncDecl->parameters()) {
|
||||
diagnoseIfNeedsFPReg(CGM.getDiags(), TI.getABI(), ABIInfo, PVD->getType(),
|
||||
PVD);
|
||||
PVD, FuncDecl->getLocation());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -908,11 +910,11 @@ void AArch64TargetCodeGenInfo::checkFunctionCallABISoftFloat(
|
|||
return;
|
||||
|
||||
diagnoseIfNeedsFPReg(CGM.getDiags(), TI.getABI(), ABIInfo, ReturnType,
|
||||
Caller);
|
||||
Callee ? Callee : Caller, CallLoc);
|
||||
|
||||
for (const CallArg &Arg : Args)
|
||||
diagnoseIfNeedsFPReg(CGM.getDiags(), TI.getABI(), ABIInfo, Arg.getType(),
|
||||
Caller);
|
||||
Callee ? Callee : Caller, CallLoc);
|
||||
}
|
||||
|
||||
void AArch64TargetCodeGenInfo::checkFunctionCallABI(CodeGenModule &CGM,
|
||||
|
|
|
|||
|
|
@ -557,12 +557,6 @@ void AIX::addClangTargetOptions(
|
|||
if (!Args.getLastArgNoClaim(options::OPT_fsized_deallocation,
|
||||
options::OPT_fno_sized_deallocation))
|
||||
CC1Args.push_back("-fno-sized-deallocation");
|
||||
|
||||
if (Args.hasFlag(options::OPT_ferr_pragma_mc_func_aix,
|
||||
options::OPT_fno_err_pragma_mc_func_aix, false))
|
||||
CC1Args.push_back("-ferr-pragma-mc-func-aix");
|
||||
else
|
||||
CC1Args.push_back("-fno-err-pragma-mc-func-aix");
|
||||
}
|
||||
|
||||
void AIX::addProfileRTLibs(const llvm::opt::ArgList &Args,
|
||||
|
|
|
|||
|
|
@ -609,6 +609,10 @@ void NVPTX::Linker::ConstructJob(Compilation &C, const JobAction &JA,
|
|||
CmdArgs.push_back(Args.MakeArgString(
|
||||
"--pxtas-path=" + Args.getLastArgValue(options::OPT_ptxas_path_EQ)));
|
||||
|
||||
if (Args.hasArg(options::OPT_cuda_path_EQ))
|
||||
CmdArgs.push_back(Args.MakeArgString(
|
||||
"--cuda-path=" + Args.getLastArgValue(options::OPT_cuda_path_EQ)));
|
||||
|
||||
// Add paths specified in LIBRARY_PATH environment variable as -L options.
|
||||
addDirectoryList(Args, CmdArgs, "-L", "LIBRARY_PATH");
|
||||
|
||||
|
|
|
|||
|
|
@ -2923,22 +2923,45 @@ bool Darwin::isAlignedAllocationUnavailable() const {
|
|||
return TargetVersion < alignedAllocMinVersion(OS);
|
||||
}
|
||||
|
||||
static bool sdkSupportsBuiltinModules(const Darwin::DarwinPlatformKind &TargetPlatform, const std::optional<DarwinSDKInfo> &SDKInfo) {
|
||||
static bool sdkSupportsBuiltinModules(
|
||||
const Darwin::DarwinPlatformKind &TargetPlatform,
|
||||
const Darwin::DarwinEnvironmentKind &TargetEnvironment,
|
||||
const std::optional<DarwinSDKInfo> &SDKInfo) {
|
||||
if (TargetEnvironment == Darwin::NativeEnvironment ||
|
||||
TargetEnvironment == Darwin::Simulator ||
|
||||
TargetEnvironment == Darwin::MacCatalyst) {
|
||||
// Standard xnu/Mach/Darwin based environments
|
||||
// depend on the SDK version.
|
||||
} else {
|
||||
// All other environments support builtin modules from the start.
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!SDKInfo)
|
||||
// If there is no SDK info, assume this is building against a
|
||||
// pre-SDK version of macOS (i.e. before Mac OS X 10.4). Those
|
||||
// don't support modules anyway, but the headers definitely
|
||||
// don't support builtin modules either. It might also be some
|
||||
// kind of degenerate build environment, err on the side of
|
||||
// the old behavior which is to not use builtin modules.
|
||||
return false;
|
||||
|
||||
VersionTuple SDKVersion = SDKInfo->getVersion();
|
||||
switch (TargetPlatform) {
|
||||
// Existing SDKs added support for builtin modules in the fall
|
||||
// 2024 major releases.
|
||||
case Darwin::MacOS:
|
||||
return SDKVersion >= VersionTuple(99U);
|
||||
return SDKVersion >= VersionTuple(15U);
|
||||
case Darwin::IPhoneOS:
|
||||
return SDKVersion >= VersionTuple(99U);
|
||||
return SDKVersion >= VersionTuple(18U);
|
||||
case Darwin::TvOS:
|
||||
return SDKVersion >= VersionTuple(99U);
|
||||
return SDKVersion >= VersionTuple(18U);
|
||||
case Darwin::WatchOS:
|
||||
return SDKVersion >= VersionTuple(99U);
|
||||
return SDKVersion >= VersionTuple(11U);
|
||||
case Darwin::XROS:
|
||||
return SDKVersion >= VersionTuple(99U);
|
||||
return SDKVersion >= VersionTuple(2U);
|
||||
|
||||
// New SDKs support builtin modules from the start.
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
|
|
@ -3030,7 +3053,7 @@ void Darwin::addClangTargetOptions(
|
|||
// i.e. when the builtin stdint.h is in the Darwin module too, the cycle
|
||||
// goes away. Note that -fbuiltin-headers-in-system-modules does nothing
|
||||
// to fix the same problem with C++ headers, and is generally fragile.
|
||||
if (!sdkSupportsBuiltinModules(TargetPlatform, SDKInfo))
|
||||
if (!sdkSupportsBuiltinModules(TargetPlatform, TargetEnvironment, SDKInfo))
|
||||
CC1Args.push_back("-fbuiltin-headers-in-system-modules");
|
||||
|
||||
if (!DriverArgs.hasArgNoClaim(options::OPT_fdefine_target_os_macros,
|
||||
|
|
|
|||
|
|
@ -2463,7 +2463,8 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes(
|
|||
// lists should shrink over time. Please don't add more elements to *Triples.
|
||||
static const char *const AArch64LibDirs[] = {"/lib64", "/lib"};
|
||||
static const char *const AArch64Triples[] = {
|
||||
"aarch64-none-linux-gnu", "aarch64-redhat-linux", "aarch64-suse-linux"};
|
||||
"aarch64-none-linux-gnu", "aarch64-linux-gnu", "aarch64-redhat-linux",
|
||||
"aarch64-suse-linux"};
|
||||
static const char *const AArch64beLibDirs[] = {"/lib"};
|
||||
static const char *const AArch64beTriples[] = {"aarch64_be-none-linux-gnu"};
|
||||
|
||||
|
|
|
|||
|
|
@ -242,7 +242,9 @@ bool types::isCXX(ID Id) {
|
|||
case TY_CXXHUHeader:
|
||||
case TY_PP_CXXHeaderUnit:
|
||||
case TY_ObjCXXHeader: case TY_PP_ObjCXXHeader:
|
||||
case TY_CXXModule: case TY_PP_CXXModule:
|
||||
case TY_CXXModule:
|
||||
case TY_PP_CXXModule:
|
||||
case TY_ModuleFile:
|
||||
case TY_PP_CLCXX:
|
||||
case TY_CUDA: case TY_PP_CUDA: case TY_CUDA_DEVICE:
|
||||
case TY_HIP:
|
||||
|
|
|
|||
|
|
@ -2872,9 +2872,18 @@ private:
|
|||
return false;
|
||||
|
||||
// Search for unexpected tokens.
|
||||
for (auto *Prev = BeforeRParen; Prev != LParen; Prev = Prev->Previous)
|
||||
for (auto *Prev = BeforeRParen; Prev != LParen; Prev = Prev->Previous) {
|
||||
if (Prev->is(tok::r_paren)) {
|
||||
Prev = Prev->MatchingParen;
|
||||
if (!Prev)
|
||||
return false;
|
||||
if (Prev->is(TT_FunctionTypeLParen))
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
if (!Prev->isOneOf(tok::kw_const, tok::identifier, tok::coloncolon))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -507,6 +507,9 @@ void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) {
|
|||
if (!Line->InMacroBody && !Style.isTableGen()) {
|
||||
// Skip PPDirective lines and comments.
|
||||
while (NextTok->is(tok::hash)) {
|
||||
NextTok = Tokens->getNextToken();
|
||||
if (NextTok->is(tok::pp_not_keyword))
|
||||
break;
|
||||
do {
|
||||
NextTok = Tokens->getNextToken();
|
||||
} while (NextTok->NewlinesBefore == 0 && NextTok->isNot(tok::eof));
|
||||
|
|
|
|||
|
|
@ -1504,6 +1504,8 @@ void CompilerInvocation::setDefaultPointerAuthOptions(
|
|||
Opts.CXXMemberFunctionPointers =
|
||||
PointerAuthSchema(Key::ASIA, false, Discrimination::Type);
|
||||
}
|
||||
Opts.ReturnAddresses = LangOpts.PointerAuthReturns;
|
||||
Opts.AuthTraps = LangOpts.PointerAuthAuthTraps;
|
||||
Opts.IndirectGotos = LangOpts.PointerAuthIndirectGotos;
|
||||
}
|
||||
|
||||
|
|
@ -1511,7 +1513,8 @@ static void parsePointerAuthOptions(PointerAuthOptions &Opts,
|
|||
const LangOptions &LangOpts,
|
||||
const llvm::Triple &Triple,
|
||||
DiagnosticsEngine &Diags) {
|
||||
if (!LangOpts.PointerAuthCalls && !LangOpts.PointerAuthIndirectGotos)
|
||||
if (!LangOpts.PointerAuthCalls && !LangOpts.PointerAuthReturns &&
|
||||
!LangOpts.PointerAuthAuthTraps && !LangOpts.PointerAuthIndirectGotos)
|
||||
return;
|
||||
|
||||
CompilerInvocation::setDefaultPointerAuthOptions(Opts, LangOpts, Triple);
|
||||
|
|
|
|||
|
|
@ -763,6 +763,7 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts,
|
|||
Builder.defineMacro("__cpp_placeholder_variables", "202306L");
|
||||
|
||||
// C++26 features supported in earlier language modes.
|
||||
Builder.defineMacro("__cpp_pack_indexing", "202311L");
|
||||
Builder.defineMacro("__cpp_deleted_function", "202403L");
|
||||
|
||||
if (LangOpts.Char8)
|
||||
|
|
|
|||
|
|
@ -28,6 +28,12 @@ typedef enum {
|
|||
/* A process-specific key which can be used to sign data pointers. */
|
||||
ptrauth_key_process_dependent_data = ptrauth_key_asdb,
|
||||
|
||||
/* The key used to sign return addresses on the stack.
|
||||
The extra data is based on the storage address of the return address.
|
||||
On AArch64, that is always the storage address of the return address + 8
|
||||
(or, in other words, the value of the stack pointer on function entry) */
|
||||
ptrauth_key_return_address = ptrauth_key_process_dependent_code,
|
||||
|
||||
/* The key used to sign C function pointers.
|
||||
The extra data is always 0. */
|
||||
ptrauth_key_function_pointer = ptrauth_key_process_independent_code,
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@
|
|||
#include "clang/Basic/PragmaKinds.h"
|
||||
#include "clang/Basic/TargetInfo.h"
|
||||
#include "clang/Lex/Preprocessor.h"
|
||||
#include "clang/Lex/PreprocessorOptions.h"
|
||||
#include "clang/Lex/Token.h"
|
||||
#include "clang/Parse/LoopHint.h"
|
||||
#include "clang/Parse/ParseDiagnostic.h"
|
||||
|
|
@ -412,19 +411,6 @@ private:
|
|||
Sema &Actions;
|
||||
};
|
||||
|
||||
struct PragmaMCFuncHandler : public PragmaHandler {
|
||||
PragmaMCFuncHandler(bool ReportError)
|
||||
: PragmaHandler("mc_func"), ReportError(ReportError) {}
|
||||
void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer,
|
||||
Token &Tok) override {
|
||||
if (ReportError)
|
||||
PP.Diag(Tok, diag::err_pragma_mc_func_not_supported);
|
||||
}
|
||||
|
||||
private:
|
||||
bool ReportError = false;
|
||||
};
|
||||
|
||||
void markAsReinjectedForRelexing(llvm::MutableArrayRef<clang::Token> Toks) {
|
||||
for (auto &T : Toks)
|
||||
T.setFlag(clang::Token::IsReinjected);
|
||||
|
|
@ -582,12 +568,6 @@ void Parser::initializePragmaHandlers() {
|
|||
RISCVPragmaHandler = std::make_unique<PragmaRISCVHandler>(Actions);
|
||||
PP.AddPragmaHandler("clang", RISCVPragmaHandler.get());
|
||||
}
|
||||
|
||||
if (getTargetInfo().getTriple().isOSAIX()) {
|
||||
MCFuncPragmaHandler = std::make_unique<PragmaMCFuncHandler>(
|
||||
PP.getPreprocessorOpts().ErrorOnPragmaMcfuncOnAIX);
|
||||
PP.AddPragmaHandler(MCFuncPragmaHandler.get());
|
||||
}
|
||||
}
|
||||
|
||||
void Parser::resetPragmaHandlers() {
|
||||
|
|
@ -722,11 +702,6 @@ void Parser::resetPragmaHandlers() {
|
|||
PP.RemovePragmaHandler("clang", RISCVPragmaHandler.get());
|
||||
RISCVPragmaHandler.reset();
|
||||
}
|
||||
|
||||
if (getTargetInfo().getTriple().isOSAIX()) {
|
||||
PP.RemovePragmaHandler(MCFuncPragmaHandler.get());
|
||||
MCFuncPragmaHandler.reset();
|
||||
}
|
||||
}
|
||||
|
||||
/// Handle the annotation token produced for #pragma unused(...)
|
||||
|
|
|
|||
|
|
@ -531,6 +531,10 @@ static ExprResult calculateConstraintSatisfaction(
|
|||
|
||||
std::optional<unsigned>
|
||||
EvaluateFoldExpandedConstraintSize(const CXXFoldExpr *FE) const {
|
||||
|
||||
// We should ignore errors in the presence of packs of different size.
|
||||
Sema::SFINAETrap Trap(S);
|
||||
|
||||
Expr *Pattern = FE->getPattern();
|
||||
|
||||
SmallVector<UnexpandedParameterPack, 2> Unexpanded;
|
||||
|
|
|
|||
|
|
@ -820,7 +820,8 @@ ExprResult Sema::BuildOperatorCoawaitLookupExpr(Scope *S, SourceLocation Loc) {
|
|||
Expr *CoawaitOp = UnresolvedLookupExpr::Create(
|
||||
Context, /*NamingClass*/ nullptr, NestedNameSpecifierLoc(),
|
||||
DeclarationNameInfo(OpName, Loc), /*RequiresADL*/ true, Functions.begin(),
|
||||
Functions.end(), /*KnownDependent=*/false);
|
||||
Functions.end(), /*KnownDependent=*/false,
|
||||
/*KnownInstantiationDependent=*/false);
|
||||
assert(CoawaitOp);
|
||||
return CoawaitOp;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1219,7 +1219,7 @@ Corrected:
|
|||
return NameClassification::OverloadSet(UnresolvedLookupExpr::Create(
|
||||
Context, Result.getNamingClass(), SS.getWithLocInContext(Context),
|
||||
Result.getLookupNameInfo(), ADL, Result.begin(), Result.end(),
|
||||
/*KnownDependent=*/false));
|
||||
/*KnownDependent=*/false, /*KnownInstantiationDependent=*/false));
|
||||
}
|
||||
|
||||
ExprResult
|
||||
|
|
@ -18073,6 +18073,15 @@ void Sema::ActOnTagFinishDefinition(Scope *S, Decl *TagD,
|
|||
if (NumInitMethods > 1 || !Def->hasInitMethod())
|
||||
Diag(RD->getLocation(), diag::err_sycl_special_type_num_init_method);
|
||||
}
|
||||
|
||||
// If we're defining a dynamic class in a module interface unit, we always
|
||||
// need to produce the vtable for it, even if the vtable is not used in the
|
||||
// current TU.
|
||||
//
|
||||
// The case where the current class is not dynamic is handled in
|
||||
// MarkVTableUsed.
|
||||
if (getCurrentModule() && getCurrentModule()->isInterfaceOrPartition())
|
||||
MarkVTableUsed(RD->getLocation(), RD, /*DefinitionRequired=*/true);
|
||||
}
|
||||
|
||||
// Exit this scope of this tag's definition.
|
||||
|
|
|
|||
|
|
@ -1289,7 +1289,7 @@ static bool checkTupleLikeDecomposition(Sema &S,
|
|||
S.Context, nullptr, NestedNameSpecifierLoc(), SourceLocation(),
|
||||
DeclarationNameInfo(GetDN, Loc), /*RequiresADL=*/true, &Args,
|
||||
UnresolvedSetIterator(), UnresolvedSetIterator(),
|
||||
/*KnownDependent=*/false);
|
||||
/*KnownDependent=*/false, /*KnownInstantiationDependent=*/false);
|
||||
|
||||
Expr *Arg = E.get();
|
||||
E = S.BuildCallExpr(nullptr, Get, Loc, Arg, Loc);
|
||||
|
|
@ -7042,11 +7042,43 @@ void Sema::CheckCompletedCXXClass(Scope *S, CXXRecordDecl *Record) {
|
|||
}
|
||||
}
|
||||
|
||||
bool EffectivelyConstexprDestructor = true;
|
||||
// Avoid triggering vtable instantiation due to a dtor that is not
|
||||
// "effectively constexpr" for better compatibility.
|
||||
// See https://github.com/llvm/llvm-project/issues/102293 for more info.
|
||||
if (isa<CXXDestructorDecl>(M)) {
|
||||
auto Check = [](QualType T, auto &&Check) -> bool {
|
||||
const CXXRecordDecl *RD =
|
||||
T->getBaseElementTypeUnsafe()->getAsCXXRecordDecl();
|
||||
if (!RD || !RD->isCompleteDefinition())
|
||||
return true;
|
||||
|
||||
if (!RD->hasConstexprDestructor())
|
||||
return false;
|
||||
|
||||
QualType CanUnqualT = T.getCanonicalType().getUnqualifiedType();
|
||||
for (const CXXBaseSpecifier &B : RD->bases())
|
||||
if (B.getType().getCanonicalType().getUnqualifiedType() !=
|
||||
CanUnqualT &&
|
||||
!Check(B.getType(), Check))
|
||||
return false;
|
||||
for (const FieldDecl *FD : RD->fields())
|
||||
if (FD->getType().getCanonicalType().getUnqualifiedType() !=
|
||||
CanUnqualT &&
|
||||
!Check(FD->getType(), Check))
|
||||
return false;
|
||||
return true;
|
||||
};
|
||||
EffectivelyConstexprDestructor =
|
||||
Check(QualType(Record->getTypeForDecl(), 0), Check);
|
||||
}
|
||||
|
||||
// Define defaulted constexpr virtual functions that override a base class
|
||||
// function right away.
|
||||
// FIXME: We can defer doing this until the vtable is marked as used.
|
||||
if (CSM != CXXSpecialMemberKind::Invalid && !M->isDeleted() &&
|
||||
M->isDefaulted() && M->isConstexpr() && M->size_overridden_methods())
|
||||
M->isDefaulted() && M->isConstexpr() && M->size_overridden_methods() &&
|
||||
EffectivelyConstexprDestructor)
|
||||
DefineDefaultedFunction(*this, M, M->getLocation());
|
||||
|
||||
if (!Incomplete)
|
||||
|
|
@ -18485,11 +18517,15 @@ bool Sema::DefineUsedVTables() {
|
|||
|
||||
bool DefineVTable = true;
|
||||
|
||||
// If this class has a key function, but that key function is
|
||||
// defined in another translation unit, we don't need to emit the
|
||||
// vtable even though we're using it.
|
||||
const CXXMethodDecl *KeyFunction = Context.getCurrentKeyFunction(Class);
|
||||
if (KeyFunction && !KeyFunction->hasBody()) {
|
||||
// V-tables for non-template classes with an owning module are always
|
||||
// uniquely emitted in that module.
|
||||
if (Class->isInCurrentModuleUnit()) {
|
||||
DefineVTable = true;
|
||||
} else if (KeyFunction && !KeyFunction->hasBody()) {
|
||||
// If this class has a key function, but that key function is
|
||||
// defined in another translation unit, we don't need to emit the
|
||||
// vtable even though we're using it.
|
||||
// The key function is in another translation unit.
|
||||
DefineVTable = false;
|
||||
TemplateSpecializationKind TSK =
|
||||
|
|
@ -18534,7 +18570,7 @@ bool Sema::DefineUsedVTables() {
|
|||
DefinedAnything = true;
|
||||
MarkVirtualMembersReferenced(Loc, Class);
|
||||
CXXRecordDecl *Canonical = Class->getCanonicalDecl();
|
||||
if (VTablesUsed[Canonical])
|
||||
if (VTablesUsed[Canonical] && !Class->shouldEmitInExternalSource())
|
||||
Consumer.HandleVTable(Class);
|
||||
|
||||
// Warn if we're emitting a weak vtable. The vtable will be weak if there is
|
||||
|
|
|
|||
|
|
@ -3188,7 +3188,7 @@ ExprResult Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
|
|||
UnresolvedLookupExpr *ULE = UnresolvedLookupExpr::Create(
|
||||
Context, R.getNamingClass(), SS.getWithLocInContext(Context),
|
||||
R.getLookupNameInfo(), NeedsADL, R.begin(), R.end(),
|
||||
/*KnownDependent=*/false);
|
||||
/*KnownDependent=*/false, /*KnownInstantiationDependent=*/false);
|
||||
|
||||
return ULE;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -331,7 +331,8 @@ ExprResult Sema::BuildPossibleImplicitMemberExpr(
|
|||
return UnresolvedLookupExpr::Create(
|
||||
Context, R.getNamingClass(), SS.getWithLocInContext(Context),
|
||||
TemplateKWLoc, R.getLookupNameInfo(), /*RequiresADL=*/false,
|
||||
TemplateArgs, R.begin(), R.end(), /*KnownDependent=*/true);
|
||||
TemplateArgs, R.begin(), R.end(), /*KnownDependent=*/true,
|
||||
/*KnownInstantiationDependent=*/true);
|
||||
|
||||
case IMA_Error_StaticOrExplicitContext:
|
||||
case IMA_Error_Unrelated:
|
||||
|
|
|
|||
|
|
@ -515,8 +515,8 @@ class InitListChecker {
|
|||
uint64_t ElsCount = 1;
|
||||
// Otherwise try to fill whole array with embed data.
|
||||
if (Entity.getKind() == InitializedEntity::EK_ArrayElement) {
|
||||
ValueDecl *ArrDecl = Entity.getParent()->getDecl();
|
||||
auto *AType = SemaRef.Context.getAsArrayType(ArrDecl->getType());
|
||||
auto *AType =
|
||||
SemaRef.Context.getAsArrayType(Entity.getParent()->getType());
|
||||
assert(AType && "expected array type when initializing array");
|
||||
ElsCount = Embed->getDataElementCount();
|
||||
if (const auto *CAType = dyn_cast<ConstantArrayType>(AType))
|
||||
|
|
|
|||
|
|
@ -17968,7 +17968,8 @@ buildDeclareReductionRef(Sema &SemaRef, SourceLocation Loc, SourceRange Range,
|
|||
return UnresolvedLookupExpr::Create(
|
||||
SemaRef.Context, /*NamingClass=*/nullptr,
|
||||
ReductionIdScopeSpec.getWithLocInContext(SemaRef.Context), ReductionId,
|
||||
/*ADL=*/true, ResSet.begin(), ResSet.end(), /*KnownDependent=*/false);
|
||||
/*ADL=*/true, ResSet.begin(), ResSet.end(), /*KnownDependent=*/false,
|
||||
/*KnownInstantiationDependent=*/false);
|
||||
}
|
||||
// Lookup inside the classes.
|
||||
// C++ [over.match.oper]p3:
|
||||
|
|
@ -20834,7 +20835,8 @@ static ExprResult buildUserDefinedMapperRef(Sema &SemaRef, Scope *S,
|
|||
return UnresolvedLookupExpr::Create(
|
||||
SemaRef.Context, /*NamingClass=*/nullptr,
|
||||
MapperIdScopeSpec.getWithLocInContext(SemaRef.Context), MapperId,
|
||||
/*ADL=*/false, URS.begin(), URS.end(), /*KnownDependent=*/false);
|
||||
/*ADL=*/false, URS.begin(), URS.end(), /*KnownDependent=*/false,
|
||||
/*KnownInstantiationDependent=*/false);
|
||||
}
|
||||
SourceLocation Loc = MapperId.getLoc();
|
||||
// [OpenMP 5.0], 2.19.7.3 declare mapper Directive, Restrictions
|
||||
|
|
|
|||
|
|
@ -14083,9 +14083,9 @@ ExprResult Sema::CreateUnresolvedLookupExpr(CXXRecordDecl *NamingClass,
|
|||
DeclarationNameInfo DNI,
|
||||
const UnresolvedSetImpl &Fns,
|
||||
bool PerformADL) {
|
||||
return UnresolvedLookupExpr::Create(Context, NamingClass, NNSLoc, DNI,
|
||||
PerformADL, Fns.begin(), Fns.end(),
|
||||
/*KnownDependent=*/false);
|
||||
return UnresolvedLookupExpr::Create(
|
||||
Context, NamingClass, NNSLoc, DNI, PerformADL, Fns.begin(), Fns.end(),
|
||||
/*KnownDependent=*/false, /*KnownInstantiationDependent=*/false);
|
||||
}
|
||||
|
||||
ExprResult Sema::BuildCXXMemberCallExpr(Expr *E, NamedDecl *FoundDecl,
|
||||
|
|
|
|||
|
|
@ -4436,7 +4436,8 @@ ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS,
|
|||
UnresolvedLookupExpr *ULE = UnresolvedLookupExpr::Create(
|
||||
Context, R.getNamingClass(), SS.getWithLocInContext(Context),
|
||||
TemplateKWLoc, R.getLookupNameInfo(), RequiresADL, TemplateArgs,
|
||||
R.begin(), R.end(), KnownDependent);
|
||||
R.begin(), R.end(), KnownDependent,
|
||||
/*KnownInstantiationDependent=*/false);
|
||||
|
||||
// Model the templates with UnresolvedTemplateTy. The expression should then
|
||||
// either be transformed in an instantiation or be diagnosed in
|
||||
|
|
|
|||
|
|
@ -10541,7 +10541,7 @@ TreeTransform<Derived>::TransformOMPReductionClause(OMPReductionClause *C) {
|
|||
SemaRef.Context, /*NamingClass=*/nullptr,
|
||||
ReductionIdScopeSpec.getWithLocInContext(SemaRef.Context), NameInfo,
|
||||
/*ADL=*/true, Decls.begin(), Decls.end(),
|
||||
/*KnownDependent=*/false));
|
||||
/*KnownDependent=*/false, /*KnownInstantiationDependent=*/false));
|
||||
} else
|
||||
UnresolvedReductions.push_back(nullptr);
|
||||
}
|
||||
|
|
@ -10588,7 +10588,7 @@ OMPClause *TreeTransform<Derived>::TransformOMPTaskReductionClause(
|
|||
SemaRef.Context, /*NamingClass=*/nullptr,
|
||||
ReductionIdScopeSpec.getWithLocInContext(SemaRef.Context), NameInfo,
|
||||
/*ADL=*/true, Decls.begin(), Decls.end(),
|
||||
/*KnownDependent=*/false));
|
||||
/*KnownDependent=*/false, /*KnownInstantiationDependent=*/false));
|
||||
} else
|
||||
UnresolvedReductions.push_back(nullptr);
|
||||
}
|
||||
|
|
@ -10634,7 +10634,7 @@ TreeTransform<Derived>::TransformOMPInReductionClause(OMPInReductionClause *C) {
|
|||
SemaRef.Context, /*NamingClass=*/nullptr,
|
||||
ReductionIdScopeSpec.getWithLocInContext(SemaRef.Context), NameInfo,
|
||||
/*ADL=*/true, Decls.begin(), Decls.end(),
|
||||
/*KnownDependent=*/false));
|
||||
/*KnownDependent=*/false, /*KnownInstantiationDependent=*/false));
|
||||
} else
|
||||
UnresolvedReductions.push_back(nullptr);
|
||||
}
|
||||
|
|
@ -10816,7 +10816,7 @@ bool transformOMPMappableExprListClause(
|
|||
TT.getSema().Context, /*NamingClass=*/nullptr,
|
||||
MapperIdScopeSpec.getWithLocInContext(TT.getSema().Context),
|
||||
MapperIdInfo, /*ADL=*/true, Decls.begin(), Decls.end(),
|
||||
/*KnownDependent=*/false));
|
||||
/*KnownDependent=*/false, /*KnownInstantiationDependent=*/false));
|
||||
} else {
|
||||
UnresolvedMappers.push_back(nullptr);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3921,6 +3921,13 @@ llvm::Error ASTReader::ReadASTBlock(ModuleFile &F,
|
|||
}
|
||||
break;
|
||||
|
||||
case VTABLES_TO_EMIT:
|
||||
if (F.Kind == MK_MainFile ||
|
||||
getContext().getLangOpts().BuildingPCHWithObjectFile)
|
||||
for (unsigned I = 0, N = Record.size(); I != N;)
|
||||
VTablesToEmit.push_back(ReadDeclID(F, Record, I));
|
||||
break;
|
||||
|
||||
case IMPORTED_MODULES:
|
||||
if (!F.isModule()) {
|
||||
// If we aren't loading a module (which has its own exports), make
|
||||
|
|
@ -8110,6 +8117,10 @@ void ASTReader::PassInterestingDeclToConsumer(Decl *D) {
|
|||
Consumer->HandleInterestingDecl(DeclGroupRef(D));
|
||||
}
|
||||
|
||||
void ASTReader::PassVTableToConsumer(CXXRecordDecl *RD) {
|
||||
Consumer->HandleVTable(RD);
|
||||
}
|
||||
|
||||
void ASTReader::StartTranslationUnit(ASTConsumer *Consumer) {
|
||||
this->Consumer = Consumer;
|
||||
|
||||
|
|
|
|||
|
|
@ -3684,6 +3684,54 @@ static void inheritDefaultTemplateArguments(ASTContext &Context,
|
|||
}
|
||||
}
|
||||
|
||||
// [basic.link]/p10:
|
||||
// If two declarations of an entity are attached to different modules,
|
||||
// the program is ill-formed;
|
||||
static void checkMultipleDefinitionInNamedModules(ASTReader &Reader, Decl *D,
|
||||
Decl *Previous) {
|
||||
Module *M = Previous->getOwningModule();
|
||||
|
||||
// We only care about the case in named modules.
|
||||
if (!M || !M->isNamedModule())
|
||||
return;
|
||||
|
||||
// If it is previous implcitly introduced, it is not meaningful to
|
||||
// diagnose it.
|
||||
if (Previous->isImplicit())
|
||||
return;
|
||||
|
||||
// FIXME: Get rid of the enumeration of decl types once we have an appropriate
|
||||
// abstract for decls of an entity. e.g., the namespace decl and using decl
|
||||
// doesn't introduce an entity.
|
||||
if (!isa<VarDecl, FunctionDecl, TagDecl, RedeclarableTemplateDecl>(Previous))
|
||||
return;
|
||||
|
||||
// Skip implicit instantiations since it may give false positive diagnostic
|
||||
// messages.
|
||||
// FIXME: Maybe this shows the implicit instantiations may have incorrect
|
||||
// module owner ships. But given we've finished the compilation of a module,
|
||||
// how can we add new entities to that module?
|
||||
if (auto *VTSD = dyn_cast<VarTemplateSpecializationDecl>(Previous);
|
||||
VTSD && !VTSD->isExplicitSpecialization())
|
||||
return;
|
||||
if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(Previous);
|
||||
CTSD && !CTSD->isExplicitSpecialization())
|
||||
return;
|
||||
if (auto *Func = dyn_cast<FunctionDecl>(Previous))
|
||||
if (auto *FTSI = Func->getTemplateSpecializationInfo();
|
||||
FTSI && !FTSI->isExplicitSpecialization())
|
||||
return;
|
||||
|
||||
// It is fine if they are in the same module.
|
||||
if (Reader.getContext().isInSameModule(M, D->getOwningModule()))
|
||||
return;
|
||||
|
||||
Reader.Diag(Previous->getLocation(),
|
||||
diag::err_multiple_decl_in_different_modules)
|
||||
<< cast<NamedDecl>(Previous) << M->Name;
|
||||
Reader.Diag(D->getLocation(), diag::note_also_found);
|
||||
}
|
||||
|
||||
void ASTDeclReader::attachPreviousDecl(ASTReader &Reader, Decl *D,
|
||||
Decl *Previous, Decl *Canon) {
|
||||
assert(D && Previous);
|
||||
|
|
@ -3697,22 +3745,7 @@ void ASTDeclReader::attachPreviousDecl(ASTReader &Reader, Decl *D,
|
|||
#include "clang/AST/DeclNodes.inc"
|
||||
}
|
||||
|
||||
// [basic.link]/p10:
|
||||
// If two declarations of an entity are attached to different modules,
|
||||
// the program is ill-formed;
|
||||
//
|
||||
// FIXME: Get rid of the enumeration of decl types once we have an appropriate
|
||||
// abstract for decls of an entity. e.g., the namespace decl and using decl
|
||||
// doesn't introduce an entity.
|
||||
if (Module *M = Previous->getOwningModule();
|
||||
M && M->isNamedModule() &&
|
||||
isa<VarDecl, FunctionDecl, TagDecl, RedeclarableTemplateDecl>(Previous) &&
|
||||
!Reader.getContext().isInSameModule(M, D->getOwningModule())) {
|
||||
Reader.Diag(Previous->getLocation(),
|
||||
diag::err_multiple_decl_in_different_modules)
|
||||
<< cast<NamedDecl>(Previous) << M->Name;
|
||||
Reader.Diag(D->getLocation(), diag::note_also_found);
|
||||
}
|
||||
checkMultipleDefinitionInNamedModules(Reader, D, Previous);
|
||||
|
||||
// If the declaration was visible in one module, a redeclaration of it in
|
||||
// another module remains visible even if it wouldn't be visible by itself.
|
||||
|
|
@ -4209,6 +4242,13 @@ void ASTReader::PassInterestingDeclsToConsumer() {
|
|||
|
||||
// If we add any new potential interesting decl in the last call, consume it.
|
||||
ConsumingPotentialInterestingDecls();
|
||||
|
||||
for (GlobalDeclID ID : VTablesToEmit) {
|
||||
auto *RD = cast<CXXRecordDecl>(GetDecl(ID));
|
||||
assert(!RD->shouldEmitInExternalSource());
|
||||
PassVTableToConsumer(RD);
|
||||
}
|
||||
VTablesToEmit.clear();
|
||||
}
|
||||
|
||||
void ASTReader::loadDeclUpdateRecords(PendingUpdateRecord &Record) {
|
||||
|
|
|
|||
|
|
@ -927,6 +927,7 @@ void ASTWriter::WriteBlockInfoBlock() {
|
|||
RECORD(DECLS_TO_CHECK_FOR_DEFERRED_DIAGS);
|
||||
RECORD(PP_ASSUME_NONNULL_LOC);
|
||||
RECORD(PP_UNSAFE_BUFFER_USAGE);
|
||||
RECORD(VTABLES_TO_EMIT);
|
||||
|
||||
// SourceManager Block.
|
||||
BLOCK(SOURCE_MANAGER_BLOCK);
|
||||
|
|
@ -3961,6 +3962,10 @@ void ASTWriter::WriteIdentifierTable(Preprocessor &PP,
|
|||
Stream.EmitRecord(INTERESTING_IDENTIFIERS, InterestingIdents);
|
||||
}
|
||||
|
||||
void ASTWriter::handleVTable(CXXRecordDecl *RD) {
|
||||
PendingEmittingVTables.push_back(RD);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// DeclContext's Name Lookup Table Serialization
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
@ -5163,6 +5168,13 @@ void ASTWriter::PrepareWritingSpecialDecls(Sema &SemaRef) {
|
|||
// Write all of the DeclsToCheckForDeferredDiags.
|
||||
for (auto *D : SemaRef.DeclsToCheckForDeferredDiags)
|
||||
GetDeclRef(D);
|
||||
|
||||
// Write all classes that need to emit the vtable definitions if required.
|
||||
if (isWritingStdCXXNamedModules())
|
||||
for (CXXRecordDecl *RD : PendingEmittingVTables)
|
||||
GetDeclRef(RD);
|
||||
else
|
||||
PendingEmittingVTables.clear();
|
||||
}
|
||||
|
||||
void ASTWriter::WriteSpecialDeclRecords(Sema &SemaRef) {
|
||||
|
|
@ -5317,6 +5329,17 @@ void ASTWriter::WriteSpecialDeclRecords(Sema &SemaRef) {
|
|||
}
|
||||
if (!DeleteExprsToAnalyze.empty())
|
||||
Stream.EmitRecord(DELETE_EXPRS_TO_ANALYZE, DeleteExprsToAnalyze);
|
||||
|
||||
RecordData VTablesToEmit;
|
||||
for (CXXRecordDecl *RD : PendingEmittingVTables) {
|
||||
if (!wasDeclEmitted(RD))
|
||||
continue;
|
||||
|
||||
AddDeclRef(RD, VTablesToEmit);
|
||||
}
|
||||
|
||||
if (!VTablesToEmit.empty())
|
||||
Stream.EmitRecord(VTABLES_TO_EMIT, VTablesToEmit);
|
||||
}
|
||||
|
||||
ASTFileSignature ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot,
|
||||
|
|
@ -6559,10 +6582,12 @@ void ASTRecordWriter::AddCXXDefinitionData(const CXXRecordDecl *D) {
|
|||
// computed.
|
||||
Record->push_back(D->getODRHash());
|
||||
|
||||
bool ModulesDebugInfo =
|
||||
Writer->Context->getLangOpts().ModulesDebugInfo && !D->isDependentType();
|
||||
Record->push_back(ModulesDebugInfo);
|
||||
if (ModulesDebugInfo)
|
||||
bool ModulesCodegen =
|
||||
!D->isDependentType() &&
|
||||
(Writer->Context->getLangOpts().ModulesDebugInfo ||
|
||||
D->isInNamedModule());
|
||||
Record->push_back(ModulesCodegen);
|
||||
if (ModulesCodegen)
|
||||
Writer->AddDeclRef(D, Writer->ModularCodegenDecls);
|
||||
|
||||
// IsLambda bit is already saved.
|
||||
|
|
|
|||
|
|
@ -1529,8 +1529,14 @@ void ASTDeclWriter::VisitCXXRecordDecl(CXXRecordDecl *D) {
|
|||
if (D->isThisDeclarationADefinition())
|
||||
Record.AddCXXDefinitionData(D);
|
||||
|
||||
if (D->isCompleteDefinition() && D->isInNamedModule())
|
||||
Writer.AddDeclRef(D, Writer.ModularCodegenDecls);
|
||||
|
||||
// Store (what we currently believe to be) the key function to avoid
|
||||
// deserializing every method so we can compute it.
|
||||
//
|
||||
// FIXME: Avoid adding the key function if the class is defined in
|
||||
// module purview since in that case the key function is meaningless.
|
||||
if (D->isCompleteDefinition())
|
||||
Record.AddDeclRef(Context.getCurrentKeyFunction(D));
|
||||
|
||||
|
|
|
|||
|
|
@ -210,6 +210,10 @@ static cl::opt<bool> FailOnIncompleteFormat(
|
|||
cl::desc("If set, fail with exit code 1 on incomplete format."),
|
||||
cl::init(false), cl::cat(ClangFormatCategory));
|
||||
|
||||
static cl::opt<bool> ListIgnored("list-ignored",
|
||||
cl::desc("List ignored files."),
|
||||
cl::cat(ClangFormatCategory), cl::Hidden);
|
||||
|
||||
namespace clang {
|
||||
namespace format {
|
||||
|
||||
|
|
@ -715,7 +719,13 @@ int main(int argc, const char **argv) {
|
|||
unsigned FileNo = 1;
|
||||
bool Error = false;
|
||||
for (const auto &FileName : FileNames) {
|
||||
if (isIgnored(FileName))
|
||||
const bool Ignored = isIgnored(FileName);
|
||||
if (ListIgnored) {
|
||||
if (Ignored)
|
||||
outs() << FileName << '\n';
|
||||
continue;
|
||||
}
|
||||
if (Ignored)
|
||||
continue;
|
||||
if (Verbose) {
|
||||
errs() << "Formatting [" << FileNo++ << "/" << FileNames.size() << "] "
|
||||
|
|
|
|||
|
|
@ -252,7 +252,15 @@ DEFINE_COMPILERRT_FUNCTION_ALIAS(__arm_sc_memmove, __arm_sc_memcpy)
|
|||
#define zva_val x5
|
||||
|
||||
DEFINE_COMPILERRT_OUTLINE_FUNCTION_UNMANGLED(__arm_sc_memset)
|
||||
dup v0.16B, valw
|
||||
#ifdef __ARM_FEATURE_SVE
|
||||
mov z0.b, valw
|
||||
#else
|
||||
bfi valw, valw, #8, #8
|
||||
bfi valw, valw, #16, #16
|
||||
bfi val, val, #32, #32
|
||||
fmov d0, val
|
||||
fmov v0.d[1], val
|
||||
#endif
|
||||
add dstend2, dstin, count
|
||||
|
||||
cmp count, 96
|
||||
|
|
|
|||
|
|
@ -33,11 +33,15 @@
|
|||
// For mips64, syscall(__NR_stat) fills the buffer in the 'struct kernel_stat'
|
||||
// format. Struct kernel_stat is defined as 'struct stat' in asm/stat.h. To
|
||||
// access stat from asm/stat.h, without conflicting with definition in
|
||||
// sys/stat.h, we use this trick.
|
||||
# if SANITIZER_MIPS64
|
||||
// sys/stat.h, we use this trick. sparc64 is similar, using
|
||||
// syscall(__NR_stat64) and struct kernel_stat64.
|
||||
# if SANITIZER_MIPS64 || SANITIZER_SPARC64
|
||||
# include <asm/unistd.h>
|
||||
# include <sys/types.h>
|
||||
# define stat kernel_stat
|
||||
# if SANITIZER_SPARC64
|
||||
# define stat64 kernel_stat64
|
||||
# endif
|
||||
# if SANITIZER_GO
|
||||
# undef st_atime
|
||||
# undef st_mtime
|
||||
|
|
@ -48,6 +52,7 @@
|
|||
# endif
|
||||
# include <asm/stat.h>
|
||||
# undef stat
|
||||
# undef stat64
|
||||
# endif
|
||||
|
||||
# include <dlfcn.h>
|
||||
|
|
@ -285,8 +290,7 @@ uptr internal_ftruncate(fd_t fd, uptr size) {
|
|||
return res;
|
||||
}
|
||||
|
||||
# if (!SANITIZER_LINUX_USES_64BIT_SYSCALLS || SANITIZER_SPARC) && \
|
||||
SANITIZER_LINUX
|
||||
# if !SANITIZER_LINUX_USES_64BIT_SYSCALLS && SANITIZER_LINUX
|
||||
static void stat64_to_stat(struct stat64 *in, struct stat *out) {
|
||||
internal_memset(out, 0, sizeof(*out));
|
||||
out->st_dev = in->st_dev;
|
||||
|
|
@ -327,7 +331,12 @@ static void statx_to_stat(struct statx *in, struct stat *out) {
|
|||
}
|
||||
# endif
|
||||
|
||||
# if SANITIZER_MIPS64
|
||||
# if SANITIZER_MIPS64 || SANITIZER_SPARC64
|
||||
# if SANITIZER_MIPS64
|
||||
typedef struct kernel_stat kstat_t;
|
||||
# else
|
||||
typedef struct kernel_stat64 kstat_t;
|
||||
# endif
|
||||
// Undefine compatibility macros from <sys/stat.h>
|
||||
// so that they would not clash with the kernel_stat
|
||||
// st_[a|m|c]time fields
|
||||
|
|
@ -345,7 +354,7 @@ static void statx_to_stat(struct statx *in, struct stat *out) {
|
|||
# undef st_mtime_nsec
|
||||
# undef st_ctime_nsec
|
||||
# endif
|
||||
static void kernel_stat_to_stat(struct kernel_stat *in, struct stat *out) {
|
||||
static void kernel_stat_to_stat(kstat_t *in, struct stat *out) {
|
||||
internal_memset(out, 0, sizeof(*out));
|
||||
out->st_dev = in->st_dev;
|
||||
out->st_ino = in->st_ino;
|
||||
|
|
@ -391,6 +400,12 @@ uptr internal_stat(const char *path, void *buf) {
|
|||
!SANITIZER_SPARC
|
||||
return internal_syscall(SYSCALL(newfstatat), AT_FDCWD, (uptr)path, (uptr)buf,
|
||||
0);
|
||||
# elif SANITIZER_SPARC64
|
||||
kstat_t buf64;
|
||||
int res = internal_syscall(SYSCALL(fstatat64), AT_FDCWD, (uptr)path,
|
||||
(uptr)&buf64, 0);
|
||||
kernel_stat_to_stat(&buf64, (struct stat *)buf);
|
||||
return res;
|
||||
# else
|
||||
struct stat64 buf64;
|
||||
int res = internal_syscall(SYSCALL(fstatat64), AT_FDCWD, (uptr)path,
|
||||
|
|
@ -423,6 +438,12 @@ uptr internal_lstat(const char *path, void *buf) {
|
|||
!SANITIZER_SPARC
|
||||
return internal_syscall(SYSCALL(newfstatat), AT_FDCWD, (uptr)path, (uptr)buf,
|
||||
AT_SYMLINK_NOFOLLOW);
|
||||
# elif SANITIZER_SPARC64
|
||||
kstat_t buf64;
|
||||
int res = internal_syscall(SYSCALL(fstatat64), AT_FDCWD, (uptr)path,
|
||||
(uptr)&buf64, AT_SYMLINK_NOFOLLOW);
|
||||
kernel_stat_to_stat(&buf64, (struct stat *)buf);
|
||||
return res;
|
||||
# else
|
||||
struct stat64 buf64;
|
||||
int res = internal_syscall(SYSCALL(fstatat64), AT_FDCWD, (uptr)path,
|
||||
|
|
@ -442,10 +463,16 @@ uptr internal_fstat(fd_t fd, void *buf) {
|
|||
# if SANITIZER_FREEBSD || SANITIZER_LINUX_USES_64BIT_SYSCALLS
|
||||
# if SANITIZER_MIPS64
|
||||
// For mips64, fstat syscall fills buffer in the format of kernel_stat
|
||||
struct kernel_stat kbuf;
|
||||
kstat_t kbuf;
|
||||
int res = internal_syscall(SYSCALL(fstat), fd, &kbuf);
|
||||
kernel_stat_to_stat(&kbuf, (struct stat *)buf);
|
||||
return res;
|
||||
# elif SANITIZER_LINUX && SANITIZER_SPARC64
|
||||
// For sparc64, fstat64 syscall fills buffer in the format of kernel_stat64
|
||||
kstat_t kbuf;
|
||||
int res = internal_syscall(SYSCALL(fstat64), fd, &kbuf);
|
||||
kernel_stat_to_stat(&kbuf, (struct stat *)buf);
|
||||
return res;
|
||||
# elif SANITIZER_LINUX && defined(__loongarch__)
|
||||
struct statx bufx;
|
||||
int res = internal_syscall(SYSCALL(statx), fd, "", AT_EMPTY_PATH,
|
||||
|
|
@ -826,10 +853,16 @@ uptr internal_sigaltstack(const void *ss, void *oss) {
|
|||
return internal_syscall(SYSCALL(sigaltstack), (uptr)ss, (uptr)oss);
|
||||
}
|
||||
|
||||
extern "C" pid_t __fork(void);
|
||||
|
||||
int internal_fork() {
|
||||
# if SANITIZER_LINUX
|
||||
# if SANITIZER_S390
|
||||
return internal_syscall(SYSCALL(clone), 0, SIGCHLD);
|
||||
# elif SANITIZER_SPARC
|
||||
// The clone syscall interface on SPARC differs massively from the rest,
|
||||
// so fall back to __fork.
|
||||
return __fork();
|
||||
# else
|
||||
return internal_syscall(SYSCALL(clone), SIGCHLD, 0);
|
||||
# endif
|
||||
|
|
|
|||
|
|
@ -20,24 +20,37 @@
|
|||
|
||||
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||
|
||||
// Writing two full functions for rotl and rotr makes it easier for the compiler
|
||||
// to optimize the code. On x86 this function becomes the ROL instruction and
|
||||
// the rotr function becomes the ROR instruction.
|
||||
template <class _Tp>
|
||||
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp __rotr(_Tp __t, int __cnt) _NOEXCEPT {
|
||||
static_assert(__libcpp_is_unsigned_integer<_Tp>::value, "__rotr requires an unsigned integer type");
|
||||
const unsigned int __dig = numeric_limits<_Tp>::digits;
|
||||
if ((__cnt % __dig) == 0)
|
||||
return __t;
|
||||
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp __rotl(_Tp __x, int __s) _NOEXCEPT {
|
||||
static_assert(__libcpp_is_unsigned_integer<_Tp>::value, "__rotl requires an unsigned integer type");
|
||||
const int __N = numeric_limits<_Tp>::digits;
|
||||
int __r = __s % __N;
|
||||
|
||||
if (__cnt < 0) {
|
||||
__cnt *= -1;
|
||||
return (__t << (__cnt % __dig)) | (__t >> (__dig - (__cnt % __dig))); // rotr with negative __cnt is similar to rotl
|
||||
}
|
||||
if (__r == 0)
|
||||
return __x;
|
||||
|
||||
return (__t >> (__cnt % __dig)) | (__t << (__dig - (__cnt % __dig)));
|
||||
if (__r > 0)
|
||||
return (__x << __r) | (__x >> (__N - __r));
|
||||
|
||||
return (__x >> -__r) | (__x << (__N + __r));
|
||||
}
|
||||
|
||||
template <class _Tp>
|
||||
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp __rotl(_Tp __t, int __cnt) _NOEXCEPT {
|
||||
return std::__rotr(__t, -__cnt);
|
||||
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp __rotr(_Tp __x, int __s) _NOEXCEPT {
|
||||
static_assert(__libcpp_is_unsigned_integer<_Tp>::value, "__rotr requires an unsigned integer type");
|
||||
const int __N = numeric_limits<_Tp>::digits;
|
||||
int __r = __s % __N;
|
||||
|
||||
if (__r == 0)
|
||||
return __x;
|
||||
|
||||
if (__r > 0)
|
||||
return (__x >> __r) | (__x << (__N - __r));
|
||||
|
||||
return (__x << -__r) | (__x >> (__N + __r));
|
||||
}
|
||||
|
||||
#if _LIBCPP_STD_VER >= 20
|
||||
|
|
|
|||
|
|
@ -9,19 +9,17 @@
|
|||
#ifndef _LIBCPP___MATH_HYPOT_H
|
||||
#define _LIBCPP___MATH_HYPOT_H
|
||||
|
||||
#include <__algorithm/max.h>
|
||||
#include <__config>
|
||||
#include <__math/abs.h>
|
||||
#include <__math/exponential_functions.h>
|
||||
#include <__math/roots.h>
|
||||
#include <__type_traits/enable_if.h>
|
||||
#include <__type_traits/is_arithmetic.h>
|
||||
#include <__type_traits/is_same.h>
|
||||
#include <__type_traits/promote.h>
|
||||
|
||||
#if _LIBCPP_STD_VER >= 17
|
||||
# include <__algorithm/max.h>
|
||||
# include <__math/abs.h>
|
||||
# include <__math/roots.h>
|
||||
# include <__utility/pair.h>
|
||||
# include <limits>
|
||||
#endif
|
||||
#include <__utility/pair.h>
|
||||
#include <limits>
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||
# pragma GCC system_header
|
||||
|
|
@ -53,58 +51,32 @@ inline _LIBCPP_HIDE_FROM_ABI typename __promote<_A1, _A2>::type hypot(_A1 __x, _
|
|||
}
|
||||
|
||||
#if _LIBCPP_STD_VER >= 17
|
||||
// Factors needed to determine if over-/underflow might happen for `std::hypot(x,y,z)`.
|
||||
// returns [overflow_threshold, overflow_scale]
|
||||
template <class _Real>
|
||||
_LIBCPP_HIDE_FROM_ABI std::pair<_Real, _Real> __hypot_factors() {
|
||||
static_assert(std::numeric_limits<_Real>::is_iec559);
|
||||
|
||||
if constexpr (std::is_same_v<_Real, float>) {
|
||||
static_assert(-125 == std::numeric_limits<_Real>::min_exponent);
|
||||
static_assert(+128 == std::numeric_limits<_Real>::max_exponent);
|
||||
return {0x1.0p+62f, 0x1.0p-70f};
|
||||
} else if constexpr (std::is_same_v<_Real, double>) {
|
||||
static_assert(-1021 == std::numeric_limits<_Real>::min_exponent);
|
||||
static_assert(+1024 == std::numeric_limits<_Real>::max_exponent);
|
||||
return {0x1.0p+510, 0x1.0p-600};
|
||||
} else { // long double
|
||||
static_assert(std::is_same_v<_Real, long double>);
|
||||
|
||||
// preprocessor guard necessary, otherwise literals (e.g. `0x1.0p+8'190l`) throw warnings even when shielded by `if
|
||||
// constexpr`
|
||||
# if __DBL_MAX_EXP__ == __LDBL_MAX_EXP__
|
||||
static_assert(sizeof(_Real) == sizeof(double));
|
||||
return static_cast<std::pair<_Real, _Real>>(__math::__hypot_factors<double>());
|
||||
# else
|
||||
static_assert(sizeof(_Real) > sizeof(double));
|
||||
static_assert(-16381 == std::numeric_limits<_Real>::min_exponent);
|
||||
static_assert(+16384 == std::numeric_limits<_Real>::max_exponent);
|
||||
return {0x1.0p+8190l, 0x1.0p-9000l};
|
||||
# endif
|
||||
}
|
||||
}
|
||||
|
||||
// Computes the three-dimensional hypotenuse: `std::hypot(x,y,z)`.
|
||||
// The naive implementation might over-/underflow which is why this implementation is more involved:
|
||||
// If the square of an argument might run into issues, we scale the arguments appropriately.
|
||||
// See https://github.com/llvm/llvm-project/issues/92782 for a detailed discussion and summary.
|
||||
template <class _Real>
|
||||
_LIBCPP_HIDE_FROM_ABI _Real __hypot(_Real __x, _Real __y, _Real __z) {
|
||||
// Factors needed to determine if over-/underflow might happen
|
||||
constexpr int __exp = std::numeric_limits<_Real>::max_exponent / 2;
|
||||
const _Real __overflow_threshold = __math::ldexp(_Real(1), __exp);
|
||||
const _Real __overflow_scale = __math::ldexp(_Real(1), -(__exp + 20));
|
||||
|
||||
// Scale arguments depending on their size
|
||||
const _Real __max_abs = std::max(__math::fabs(__x), std::max(__math::fabs(__y), __math::fabs(__z)));
|
||||
const auto [__overflow_threshold, __overflow_scale] = __math::__hypot_factors<_Real>();
|
||||
_Real __scale;
|
||||
if (__max_abs > __overflow_threshold) { // x*x + y*y + z*z might overflow
|
||||
__scale = __overflow_scale;
|
||||
__x *= __scale;
|
||||
__y *= __scale;
|
||||
__z *= __scale;
|
||||
} else if (__max_abs < 1 / __overflow_threshold) { // x*x + y*y + z*z might underflow
|
||||
__scale = 1 / __overflow_scale;
|
||||
__x *= __scale;
|
||||
__y *= __scale;
|
||||
__z *= __scale;
|
||||
} else
|
||||
} else {
|
||||
__scale = 1;
|
||||
}
|
||||
__x *= __scale;
|
||||
__y *= __scale;
|
||||
__z *= __scale;
|
||||
|
||||
// Compute hypot of scaled arguments and undo scaling
|
||||
return __math::sqrt(__x * __x + __y * __y + __z * __z) / __scale;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -63,17 +63,17 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
using _SP = __pointer_of_or_t<_Smart, _Pointer>;
|
||||
using _SmartPtr = __pointer_of_or_t<_Smart, _Pointer>;
|
||||
if constexpr (is_pointer_v<_Smart>) {
|
||||
std::apply([&](auto&&... __args) { __s_ = _Smart(static_cast<_SP>(__p_), std::forward<_Args>(__args)...); },
|
||||
std::apply([&](auto&&... __args) { __s_ = _Smart(static_cast<_SmartPtr>(__p_), std::forward<_Args>(__args)...); },
|
||||
std::move(__a_));
|
||||
} else if constexpr (__resettable_smart_pointer_with_args<_Smart, _Pointer, _Args...>) {
|
||||
std::apply([&](auto&&... __args) { __s_.reset(static_cast<_SP>(__p_), std::forward<_Args>(__args)...); },
|
||||
std::apply([&](auto&&... __args) { __s_.reset(static_cast<_SmartPtr>(__p_), std::forward<_Args>(__args)...); },
|
||||
std::move(__a_));
|
||||
} else {
|
||||
static_assert(is_constructible_v<_Smart, _SP, _Args...>,
|
||||
static_assert(is_constructible_v<_Smart, _SmartPtr, _Args...>,
|
||||
"The smart pointer must be constructible from arguments of types _Smart, _Pointer, _Args...");
|
||||
std::apply([&](auto&&... __args) { __s_ = _Smart(static_cast<_SP>(__p_), std::forward<_Args>(__args)...); },
|
||||
std::apply([&](auto&&... __args) { __s_ = _Smart(static_cast<_SmartPtr>(__p_), std::forward<_Args>(__args)...); },
|
||||
std::move(__a_));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,14 +58,14 @@ public:
|
|||
return;
|
||||
}
|
||||
|
||||
using _SP = __pointer_of_or_t<_Smart, _Pointer>;
|
||||
using _SmartPtr = __pointer_of_or_t<_Smart, _Pointer>;
|
||||
if constexpr (__resettable_smart_pointer_with_args<_Smart, _Pointer, _Args...>) {
|
||||
std::apply([&](auto&&... __args) { __s_.reset(static_cast<_SP>(__p_), std::forward<_Args>(__args)...); },
|
||||
std::apply([&](auto&&... __args) { __s_.reset(static_cast<_SmartPtr>(__p_), std::forward<_Args>(__args)...); },
|
||||
std::move(__a_));
|
||||
} else {
|
||||
static_assert(is_constructible_v<_Smart, _SP, _Args...>,
|
||||
static_assert(is_constructible_v<_Smart, _SmartPtr, _Args...>,
|
||||
"The smart pointer must be constructible from arguments of types _Smart, _Pointer, _Args...");
|
||||
std::apply([&](auto&&... __args) { __s_ = _Smart(static_cast<_SP>(__p_), std::forward<_Args>(__args)...); },
|
||||
std::apply([&](auto&&... __args) { __s_ = _Smart(static_cast<_SmartPtr>(__p_), std::forward<_Args>(__args)...); },
|
||||
std::move(__a_));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -421,7 +421,8 @@ public:
|
|||
|
||||
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR complex(float __re = 0.0f, float __im = 0.0f) : __re_(__re), __im_(__im) {}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR complex(__from_builtin_tag, _Complex float __v)
|
||||
template <class _Tag, __enable_if_t<_IsSame<_Tag, __from_builtin_tag>::value, int> = 0>
|
||||
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR explicit complex(_Tag, _Complex float __v)
|
||||
: __re_(__real__ __v), __im_(__imag__ __v) {}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI explicit _LIBCPP_CONSTEXPR complex(const complex<double>& __c);
|
||||
|
|
@ -517,7 +518,8 @@ public:
|
|||
|
||||
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR complex(double __re = 0.0, double __im = 0.0) : __re_(__re), __im_(__im) {}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR complex(__from_builtin_tag, _Complex double __v)
|
||||
template <class _Tag, __enable_if_t<_IsSame<_Tag, __from_builtin_tag>::value, int> = 0>
|
||||
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR explicit complex(_Tag, _Complex double __v)
|
||||
: __re_(__real__ __v), __im_(__imag__ __v) {}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR complex(const complex<float>& __c);
|
||||
|
|
@ -617,7 +619,8 @@ public:
|
|||
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR complex(long double __re = 0.0L, long double __im = 0.0L)
|
||||
: __re_(__re), __im_(__im) {}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR complex(__from_builtin_tag, _Complex long double __v)
|
||||
template <class _Tag, __enable_if_t<_IsSame<_Tag, __from_builtin_tag>::value, int> = 0>
|
||||
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR explicit complex(_Tag, _Complex long double __v)
|
||||
: __re_(__real__ __v), __im_(__imag__ __v) {}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR complex(const complex<float>& __c);
|
||||
|
|
|
|||
|
|
@ -301,7 +301,7 @@ struct __optional_destruct_base<_Tp, false> {
|
|||
|
||||
# if _LIBCPP_STD_VER >= 23
|
||||
template <class _Fp, class... _Args>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr __optional_destruct_base(
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr explicit __optional_destruct_base(
|
||||
__optional_construct_from_invoke_tag, _Fp&& __f, _Args&&... __args)
|
||||
: __val_(std::invoke(std::forward<_Fp>(__f), std::forward<_Args>(__args)...)), __engaged_(true) {}
|
||||
# endif
|
||||
|
|
@ -707,8 +707,11 @@ public:
|
|||
}
|
||||
|
||||
# if _LIBCPP_STD_VER >= 23
|
||||
template <class _Fp, class... _Args>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr explicit optional(__optional_construct_from_invoke_tag, _Fp&& __f, _Args&&... __args)
|
||||
template <class _Tag,
|
||||
class _Fp,
|
||||
class... _Args,
|
||||
__enable_if_t<_IsSame<_Tag, __optional_construct_from_invoke_tag>::value, int> = 0>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr explicit optional(_Tag, _Fp&& __f, _Args&&... __args)
|
||||
: __base(__optional_construct_from_invoke_tag{}, std::forward<_Fp>(__f), std::forward<_Args>(__args)...) {}
|
||||
# endif
|
||||
|
||||
|
|
|
|||
|
|
@ -206,10 +206,10 @@ struct __is_std_span<span<_Tp, _Sz>> : true_type {};
|
|||
|
||||
template <class _Range, class _ElementType>
|
||||
concept __span_compatible_range =
|
||||
!__is_std_span<remove_cvref_t<_Range>>::value && //
|
||||
ranges::contiguous_range<_Range> && //
|
||||
ranges::sized_range<_Range> && //
|
||||
(ranges::borrowed_range<_Range> || is_const_v<_ElementType>) && //
|
||||
!__is_std_span<remove_cvref_t<_Range>>::value && //
|
||||
!__is_std_array<remove_cvref_t<_Range>>::value && //
|
||||
!is_array_v<remove_cvref_t<_Range>> && //
|
||||
is_convertible_v<remove_reference_t<ranges::range_reference_t<_Range>> (*)[], _ElementType (*)[]>;
|
||||
|
|
|
|||
|
|
@ -1815,6 +1815,13 @@ inline const char *Registers_ppc64::getRegisterName(int regNum) {
|
|||
/// process.
|
||||
class _LIBUNWIND_HIDDEN Registers_arm64;
|
||||
extern "C" void __libunwind_Registers_arm64_jumpto(Registers_arm64 *);
|
||||
|
||||
#if defined(_LIBUNWIND_USE_GCS)
|
||||
extern "C" void *__libunwind_cet_get_jump_target() {
|
||||
return reinterpret_cast<void *>(&__libunwind_Registers_arm64_jumpto);
|
||||
}
|
||||
#endif
|
||||
|
||||
class _LIBUNWIND_HIDDEN Registers_arm64 {
|
||||
public:
|
||||
Registers_arm64();
|
||||
|
|
|
|||
|
|
@ -471,7 +471,7 @@ public:
|
|||
}
|
||||
#endif
|
||||
|
||||
#if defined(_LIBUNWIND_USE_CET)
|
||||
#if defined(_LIBUNWIND_USE_CET) || defined(_LIBUNWIND_USE_GCS)
|
||||
virtual void *get_registers() {
|
||||
_LIBUNWIND_ABORT("get_registers not implemented");
|
||||
}
|
||||
|
|
@ -954,7 +954,7 @@ public:
|
|||
virtual uintptr_t getDataRelBase();
|
||||
#endif
|
||||
|
||||
#if defined(_LIBUNWIND_USE_CET)
|
||||
#if defined(_LIBUNWIND_USE_CET) || defined(_LIBUNWIND_USE_GCS)
|
||||
virtual void *get_registers() { return &_registers; }
|
||||
#endif
|
||||
|
||||
|
|
@ -3005,7 +3005,7 @@ bool UnwindCursor<A, R>::isReadableAddr(const pint_t addr) const {
|
|||
}
|
||||
#endif
|
||||
|
||||
#if defined(_LIBUNWIND_USE_CET)
|
||||
#if defined(_LIBUNWIND_USE_CET) || defined(_LIBUNWIND_USE_GCS)
|
||||
extern "C" void *__libunwind_cet_get_registers(unw_cursor_t *cursor) {
|
||||
AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
|
||||
return co->get_registers();
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@
|
|||
// _LIBUNWIND_POP_CET_SSP is used to adjust CET shadow stack pointer and we
|
||||
// directly jump to __libunwind_Registers_x86/x86_64_jumpto instead of using
|
||||
// a regular function call to avoid pushing to CET shadow stack again.
|
||||
#if !defined(_LIBUNWIND_USE_CET)
|
||||
#if !defined(_LIBUNWIND_USE_CET) && !defined(_LIBUNWIND_USE_GCS)
|
||||
#define __unw_phase2_resume(cursor, fn) \
|
||||
do { \
|
||||
(void)fn; \
|
||||
|
|
@ -72,6 +72,19 @@
|
|||
__asm__ volatile("jmpq *%%rdx\n\t" :: "D"(cetRegContext), \
|
||||
"d"(cetJumpAddress)); \
|
||||
} while (0)
|
||||
#elif defined(_LIBUNWIND_TARGET_AARCH64)
|
||||
#define __cet_ss_step_size 8
|
||||
#define __unw_phase2_resume(cursor, fn) \
|
||||
do { \
|
||||
_LIBUNWIND_POP_CET_SSP((fn)); \
|
||||
void *cetRegContext = __libunwind_cet_get_registers((cursor)); \
|
||||
void *cetJumpAddress = __libunwind_cet_get_jump_target(); \
|
||||
__asm__ volatile("mov x0, %0\n\t" \
|
||||
"br %1\n\t" \
|
||||
: \
|
||||
: "r"(cetRegContext), "r"(cetJumpAddress) \
|
||||
: "x0"); \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
static _Unwind_Reason_Code
|
||||
|
|
@ -170,6 +183,10 @@ unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except
|
|||
}
|
||||
extern int __unw_step_stage2(unw_cursor_t *);
|
||||
|
||||
#if defined(_LIBUNWIND_USE_GCS)
|
||||
// Enable the GCS target feature to permit gcspop instructions to be used.
|
||||
__attribute__((target("gcs")))
|
||||
#endif
|
||||
static _Unwind_Reason_Code
|
||||
unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *exception_object) {
|
||||
__unw_init_local(cursor, uc);
|
||||
|
|
@ -180,8 +197,12 @@ unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except
|
|||
// uc is initialized by __unw_getcontext in the parent frame. The first stack
|
||||
// frame walked is unwind_phase2.
|
||||
unsigned framesWalked = 1;
|
||||
#ifdef _LIBUNWIND_USE_CET
|
||||
#if defined(_LIBUNWIND_USE_CET)
|
||||
unsigned long shadowStackTop = _get_ssp();
|
||||
#elif defined(_LIBUNWIND_USE_GCS)
|
||||
unsigned long shadowStackTop = 0;
|
||||
if (__chkfeat(_CHKFEAT_GCS))
|
||||
shadowStackTop = (unsigned long)__gcspr();
|
||||
#endif
|
||||
// Walk each frame until we reach where search phase said to stop.
|
||||
while (true) {
|
||||
|
|
@ -238,7 +259,7 @@ unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except
|
|||
// against return address stored in CET shadow stack, if the 2 addresses don't
|
||||
// match, it means return address in normal stack has been corrupted, we return
|
||||
// _URC_FATAL_PHASE2_ERROR.
|
||||
#ifdef _LIBUNWIND_USE_CET
|
||||
#if defined(_LIBUNWIND_USE_CET) || defined(_LIBUNWIND_USE_GCS)
|
||||
if (shadowStackTop != 0) {
|
||||
unw_word_t retInNormalStack;
|
||||
__unw_get_reg(cursor, UNW_REG_IP, &retInNormalStack);
|
||||
|
|
@ -306,6 +327,10 @@ unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except
|
|||
return _URC_FATAL_PHASE2_ERROR;
|
||||
}
|
||||
|
||||
#if defined(_LIBUNWIND_USE_GCS)
|
||||
// Enable the GCS target feature to permit gcspop instructions to be used.
|
||||
__attribute__((target("gcs")))
|
||||
#endif
|
||||
static _Unwind_Reason_Code
|
||||
unwind_phase2_forced(unw_context_t *uc, unw_cursor_t *cursor,
|
||||
_Unwind_Exception *exception_object,
|
||||
|
|
|
|||
|
|
@ -629,6 +629,10 @@ Lnovec:
|
|||
|
||||
#elif defined(__aarch64__)
|
||||
|
||||
#if defined(__ARM_FEATURE_GCS_DEFAULT)
|
||||
.arch_extension gcs
|
||||
#endif
|
||||
|
||||
//
|
||||
// extern "C" void __libunwind_Registers_arm64_jumpto(Registers_arm64 *);
|
||||
//
|
||||
|
|
@ -680,6 +684,16 @@ DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_arm64_jumpto)
|
|||
ldr x16, [x0, #0x0F8]
|
||||
ldp x0, x1, [x0, #0x000] // restore x0,x1
|
||||
mov sp,x16 // restore sp
|
||||
#if defined(__ARM_FEATURE_GCS_DEFAULT)
|
||||
// If GCS is enabled we need to push the address we're returning to onto the
|
||||
// GCS stack. We can't just return using br, as there won't be a BTI landing
|
||||
// pad instruction at the destination.
|
||||
mov x16, #1
|
||||
chkfeat x16
|
||||
cbnz x16, Lnogcs
|
||||
gcspushm x30
|
||||
Lnogcs:
|
||||
#endif
|
||||
ret x30 // jump to pc
|
||||
|
||||
#elif defined(__arm__) && !defined(__APPLE__)
|
||||
|
|
|
|||
|
|
@ -82,7 +82,22 @@
|
|||
#define PPC64_OPD2
|
||||
#endif
|
||||
|
||||
#if defined(__aarch64__) && defined(__ARM_FEATURE_BTI_DEFAULT)
|
||||
#if defined(__aarch64__)
|
||||
#if defined(__ARM_FEATURE_GCS_DEFAULT) && defined(__ARM_FEATURE_BTI_DEFAULT)
|
||||
// Set BTI, PAC, and GCS gnu property bits
|
||||
#define GNU_PROPERTY 7
|
||||
// We indirectly branch to __libunwind_Registers_arm64_jumpto from
|
||||
// __unw_phase2_resume, so we need to use bti jc.
|
||||
#define AARCH64_BTI bti jc
|
||||
#elif defined(__ARM_FEATURE_GCS_DEFAULT)
|
||||
// Set GCS gnu property bit
|
||||
#define GNU_PROPERTY 4
|
||||
#elif defined(__ARM_FEATURE_BTI_DEFAULT)
|
||||
// Set BTI and PAC gnu property bits
|
||||
#define GNU_PROPERTY 3
|
||||
#define AARCH64_BTI bti c
|
||||
#endif
|
||||
#ifdef GNU_PROPERTY
|
||||
.pushsection ".note.gnu.property", "a" SEPARATOR \
|
||||
.balign 8 SEPARATOR \
|
||||
.long 4 SEPARATOR \
|
||||
|
|
@ -91,12 +106,12 @@
|
|||
.asciz "GNU" SEPARATOR \
|
||||
.long 0xc0000000 SEPARATOR /* GNU_PROPERTY_AARCH64_FEATURE_1_AND */ \
|
||||
.long 4 SEPARATOR \
|
||||
.long 3 SEPARATOR /* GNU_PROPERTY_AARCH64_FEATURE_1_BTI AND */ \
|
||||
/* GNU_PROPERTY_AARCH64_FEATURE_1_PAC */ \
|
||||
.long GNU_PROPERTY SEPARATOR \
|
||||
.long 0 SEPARATOR \
|
||||
.popsection SEPARATOR
|
||||
#define AARCH64_BTI bti c
|
||||
#else
|
||||
#endif
|
||||
#endif
|
||||
#if !defined(AARCH64_BTI)
|
||||
#define AARCH64_BTI
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,28 @@
|
|||
} while (0)
|
||||
#endif
|
||||
|
||||
// On AArch64 we use _LIBUNWIND_USE_GCS to indicate that GCS is supported. We
|
||||
// need to guard any use of GCS instructions with __chkfeat though, as GCS may
|
||||
// not be enabled.
|
||||
#if defined(_LIBUNWIND_TARGET_AARCH64) && defined(__ARM_FEATURE_GCS_DEFAULT)
|
||||
#include <arm_acle.h>
|
||||
|
||||
// We can only use GCS if arm_acle.h defines the GCS intrinsics.
|
||||
#ifdef _CHKFEAT_GCS
|
||||
#define _LIBUNWIND_USE_GCS 1
|
||||
#endif
|
||||
|
||||
#define _LIBUNWIND_POP_CET_SSP(x) \
|
||||
do { \
|
||||
if (__chkfeat(_CHKFEAT_GCS)) { \
|
||||
unsigned tmp = (x); \
|
||||
while (tmp--) \
|
||||
__gcspopm(); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#endif
|
||||
|
||||
extern void *__libunwind_cet_get_registers(unw_cursor_t *);
|
||||
extern void *__libunwind_cet_get_jump_target(void);
|
||||
|
||||
|
|
|
|||
|
|
@ -228,10 +228,16 @@ static void writePltHeaderLong(uint8_t *buf) {
|
|||
write32(buf + 16, gotPlt - l1 - 8);
|
||||
}
|
||||
|
||||
// True if we should use Thumb PLTs, which currently require Thumb2, and are
|
||||
// only used if the target does not have the ARM ISA.
|
||||
static bool useThumbPLTs() {
|
||||
return config->armHasThumb2ISA && !config->armHasArmISA;
|
||||
}
|
||||
|
||||
// The default PLT header requires the .got.plt to be within 128 Mb of the
|
||||
// .plt in the positive direction.
|
||||
void ARM::writePltHeader(uint8_t *buf) const {
|
||||
if (config->armThumbPLTs) {
|
||||
if (useThumbPLTs()) {
|
||||
// The instruction sequence for thumb:
|
||||
//
|
||||
// 0: b500 push {lr}
|
||||
|
|
@ -289,7 +295,7 @@ void ARM::writePltHeader(uint8_t *buf) const {
|
|||
}
|
||||
|
||||
void ARM::addPltHeaderSymbols(InputSection &isec) const {
|
||||
if (config->armThumbPLTs) {
|
||||
if (useThumbPLTs()) {
|
||||
addSyntheticLocal("$t", STT_NOTYPE, 0, 0, isec);
|
||||
addSyntheticLocal("$d", STT_NOTYPE, 12, 0, isec);
|
||||
} else {
|
||||
|
|
@ -315,7 +321,7 @@ static void writePltLong(uint8_t *buf, uint64_t gotPltEntryAddr,
|
|||
void ARM::writePlt(uint8_t *buf, const Symbol &sym,
|
||||
uint64_t pltEntryAddr) const {
|
||||
|
||||
if (!config->armThumbPLTs) {
|
||||
if (!useThumbPLTs()) {
|
||||
uint64_t offset = sym.getGotPltVA() - pltEntryAddr - 8;
|
||||
|
||||
// The PLT entry is similar to the example given in Appendix A of ELF for
|
||||
|
|
@ -367,7 +373,7 @@ void ARM::writePlt(uint8_t *buf, const Symbol &sym,
|
|||
}
|
||||
|
||||
void ARM::addPltSymbols(InputSection &isec, uint64_t off) const {
|
||||
if (config->armThumbPLTs) {
|
||||
if (useThumbPLTs()) {
|
||||
addSyntheticLocal("$t", STT_NOTYPE, off, 0, isec);
|
||||
} else {
|
||||
addSyntheticLocal("$a", STT_NOTYPE, off, 0, isec);
|
||||
|
|
@ -393,7 +399,7 @@ bool ARM::needsThunk(RelExpr expr, RelType type, const InputFile *file,
|
|||
case R_ARM_JUMP24:
|
||||
// Source is ARM, all PLT entries are ARM so no interworking required.
|
||||
// Otherwise we need to interwork if STT_FUNC Symbol has bit 0 set (Thumb).
|
||||
assert(!config->armThumbPLTs &&
|
||||
assert(!useThumbPLTs() &&
|
||||
"If the source is ARM, we should not need Thumb PLTs");
|
||||
if (s.isFunc() && expr == R_PC && (s.getVA() & 1))
|
||||
return true;
|
||||
|
|
@ -407,7 +413,8 @@ bool ARM::needsThunk(RelExpr expr, RelType type, const InputFile *file,
|
|||
case R_ARM_THM_JUMP24:
|
||||
// Source is Thumb, when all PLT entries are ARM interworking is required.
|
||||
// Otherwise we need to interwork if STT_FUNC Symbol has bit 0 clear (ARM).
|
||||
if ((expr == R_PLT_PC && !config->armThumbPLTs) || (s.isFunc() && (s.getVA() & 1) == 0))
|
||||
if ((expr == R_PLT_PC && !useThumbPLTs()) ||
|
||||
(s.isFunc() && (s.getVA() & 1) == 0))
|
||||
return true;
|
||||
[[fallthrough]];
|
||||
case R_ARM_THM_CALL: {
|
||||
|
|
@ -675,7 +682,7 @@ void ARM::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
|
|||
// PLT entries are always ARM state so we know we need to interwork.
|
||||
assert(rel.sym); // R_ARM_THM_CALL is always reached via relocate().
|
||||
bool bit0Thumb = val & 1;
|
||||
bool useThumb = bit0Thumb || config->armThumbPLTs;
|
||||
bool useThumb = bit0Thumb || useThumbPLTs();
|
||||
bool isBlx = (read16(loc + 2) & 0x1000) == 0;
|
||||
// lld 10.0 and before always used bit0Thumb when deciding to write a BLX
|
||||
// even when type not STT_FUNC.
|
||||
|
|
|
|||
|
|
@ -217,7 +217,8 @@ struct Config {
|
|||
bool allowMultipleDefinition;
|
||||
bool fatLTOObjects;
|
||||
bool androidPackDynRelocs = false;
|
||||
bool armThumbPLTs = false;
|
||||
bool armHasArmISA = false;
|
||||
bool armHasThumb2ISA = false;
|
||||
bool armHasBlx = false;
|
||||
bool armHasMovtMovw = false;
|
||||
bool armJ1J2BranchEncoding = false;
|
||||
|
|
|
|||
|
|
@ -991,6 +991,15 @@ processCallGraphRelocations(SmallVector<uint32_t, 32> &symbolIndices,
|
|||
for (size_t i = 0, e = objSections.size(); i < e; ++i) {
|
||||
const Elf_Shdr_Impl<ELFT> &sec = objSections[i];
|
||||
if (sec.sh_info == inputObj->cgProfileSectionIndex) {
|
||||
if (sec.sh_type == SHT_CREL) {
|
||||
auto crels =
|
||||
CHECK(obj.crels(sec), "could not retrieve cg profile rela section");
|
||||
for (const auto &rel : crels.first)
|
||||
symbolIndices.push_back(rel.getSymbol(false));
|
||||
for (const auto &rel : crels.second)
|
||||
symbolIndices.push_back(rel.getSymbol(false));
|
||||
break;
|
||||
}
|
||||
if (sec.sh_type == SHT_RELA) {
|
||||
ArrayRef<typename ELFT::Rela> relas =
|
||||
CHECK(obj.relas(sec), "could not retrieve cg profile rela section");
|
||||
|
|
|
|||
|
|
@ -203,10 +203,8 @@ static void updateSupportedARMFeatures(const ARMAttributeParser &attributes) {
|
|||
attributes.getAttributeValue(ARMBuildAttrs::ARM_ISA_use);
|
||||
std::optional<unsigned> thumb =
|
||||
attributes.getAttributeValue(ARMBuildAttrs::THUMB_ISA_use);
|
||||
bool noArmISA = !armISA || *armISA == ARMBuildAttrs::Not_Allowed;
|
||||
bool hasThumb2 = thumb && *thumb >= ARMBuildAttrs::AllowThumb32;
|
||||
if (noArmISA && hasThumb2)
|
||||
config->armThumbPLTs = true;
|
||||
config->armHasArmISA |= armISA && *armISA >= ARMBuildAttrs::Allowed;
|
||||
config->armHasThumb2ISA |= thumb && *thumb >= ARMBuildAttrs::AllowThumb32;
|
||||
}
|
||||
|
||||
InputFile::InputFile(Kind k, MemoryBufferRef m)
|
||||
|
|
|
|||
|
|
@ -459,7 +459,8 @@ private:
|
|||
// InputSectionBase.
|
||||
class RelocationScanner {
|
||||
public:
|
||||
template <class ELFT> void scanSection(InputSectionBase &s);
|
||||
template <class ELFT>
|
||||
void scanSection(InputSectionBase &s, bool isEH = false);
|
||||
|
||||
private:
|
||||
InputSectionBase *sec;
|
||||
|
|
@ -1617,10 +1618,11 @@ void RelocationScanner::scan(Relocs<RelTy> rels) {
|
|||
});
|
||||
}
|
||||
|
||||
template <class ELFT> void RelocationScanner::scanSection(InputSectionBase &s) {
|
||||
template <class ELFT>
|
||||
void RelocationScanner::scanSection(InputSectionBase &s, bool isEH) {
|
||||
sec = &s;
|
||||
getter = OffsetGetter(s);
|
||||
const RelsOrRelas<ELFT> rels = s.template relsOrRelas<ELFT>();
|
||||
const RelsOrRelas<ELFT> rels = s.template relsOrRelas<ELFT>(!isEH);
|
||||
if (rels.areRelocsCrel())
|
||||
scan<ELFT>(rels.crels);
|
||||
else if (rels.areRelocsRel())
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ class LLDB_API SBSaveCoreOptions {
|
|||
public:
|
||||
SBSaveCoreOptions();
|
||||
SBSaveCoreOptions(const lldb::SBSaveCoreOptions &rhs);
|
||||
~SBSaveCoreOptions() = default;
|
||||
~SBSaveCoreOptions();
|
||||
|
||||
const SBSaveCoreOptions &operator=(const lldb::SBSaveCoreOptions &rhs);
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@
|
|||
#include "lldb/lldb-forward.h"
|
||||
#include "lldb/lldb-public.h"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace lldb_private {
|
||||
|
||||
/// \class AddressableBits AddressableBits.h "lldb/Core/AddressableBits.h"
|
||||
|
|
|
|||
|
|
@ -29,6 +29,8 @@ SBSaveCoreOptions::SBSaveCoreOptions(const SBSaveCoreOptions &rhs) {
|
|||
m_opaque_up = clone(rhs.m_opaque_up);
|
||||
}
|
||||
|
||||
SBSaveCoreOptions::~SBSaveCoreOptions() = default;
|
||||
|
||||
const SBSaveCoreOptions &
|
||||
SBSaveCoreOptions::operator=(const SBSaveCoreOptions &rhs) {
|
||||
LLDB_INSTRUMENT_VA(this, rhs);
|
||||
|
|
|
|||
|
|
@ -269,8 +269,15 @@ static void PrepareContextToReceiveMembers(TypeSystemClang &ast,
|
|||
}
|
||||
|
||||
// We don't have a type definition and/or the import failed, but we need to
|
||||
// add members to it. Start the definition to make that possible.
|
||||
tag_decl_ctx->startDefinition();
|
||||
// add members to it. Start the definition to make that possible. If the type
|
||||
// has no external storage we also have to complete the definition. Otherwise,
|
||||
// that will happen when we are asked to complete the type
|
||||
// (CompleteTypeFromDWARF).
|
||||
ast.StartTagDeclarationDefinition(type);
|
||||
if (!tag_decl_ctx->hasExternalLexicalStorage()) {
|
||||
ast.SetDeclIsForcefullyCompleted(tag_decl_ctx);
|
||||
ast.CompleteTagDeclarationDefinition(type);
|
||||
}
|
||||
}
|
||||
|
||||
ParsedDWARFTypeAttributes::ParsedDWARFTypeAttributes(const DWARFDIE &die) {
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <functional>
|
||||
|
|
|
|||
|
|
@ -199,9 +199,8 @@ public:
|
|||
/// Check whether the dependencies between the accesses are safe.
|
||||
///
|
||||
/// Only checks sets with elements in \p CheckDeps.
|
||||
bool areDepsSafe(DepCandidates &AccessSets, MemAccessInfoList &CheckDeps,
|
||||
const DenseMap<Value *, SmallVector<const Value *, 16>>
|
||||
&UnderlyingObjects);
|
||||
bool areDepsSafe(const DepCandidates &AccessSets,
|
||||
const MemAccessInfoList &CheckDeps);
|
||||
|
||||
/// No memory dependence was encountered that would inhibit
|
||||
/// vectorization.
|
||||
|
|
@ -351,11 +350,8 @@ private:
|
|||
/// element access it records this distance in \p MinDepDistBytes (if this
|
||||
/// distance is smaller than any other distance encountered so far).
|
||||
/// Otherwise, this function returns true signaling a possible dependence.
|
||||
Dependence::DepType
|
||||
isDependent(const MemAccessInfo &A, unsigned AIdx, const MemAccessInfo &B,
|
||||
unsigned BIdx,
|
||||
const DenseMap<Value *, SmallVector<const Value *, 16>>
|
||||
&UnderlyingObjects);
|
||||
Dependence::DepType isDependent(const MemAccessInfo &A, unsigned AIdx,
|
||||
const MemAccessInfo &B, unsigned BIdx);
|
||||
|
||||
/// Check whether the data dependence could prevent store-load
|
||||
/// forwarding.
|
||||
|
|
@ -392,11 +388,9 @@ private:
|
|||
/// determined, or a struct containing (Distance, Stride, TypeSize, AIsWrite,
|
||||
/// BIsWrite).
|
||||
std::variant<Dependence::DepType, DepDistanceStrideAndSizeInfo>
|
||||
getDependenceDistanceStrideAndSize(
|
||||
const MemAccessInfo &A, Instruction *AInst, const MemAccessInfo &B,
|
||||
Instruction *BInst,
|
||||
const DenseMap<Value *, SmallVector<const Value *, 16>>
|
||||
&UnderlyingObjects);
|
||||
getDependenceDistanceStrideAndSize(const MemAccessInfo &A, Instruction *AInst,
|
||||
const MemAccessInfo &B,
|
||||
Instruction *BInst);
|
||||
};
|
||||
|
||||
class RuntimePointerChecking;
|
||||
|
|
@ -797,7 +791,8 @@ replaceSymbolicStrideSCEV(PredicatedScalarEvolution &PSE,
|
|||
Value *Ptr);
|
||||
|
||||
/// If the pointer has a constant stride return it in units of the access type
|
||||
/// size. Otherwise return std::nullopt.
|
||||
/// size. If the pointer is loop-invariant, return 0. Otherwise return
|
||||
/// std::nullopt.
|
||||
///
|
||||
/// Ensure that it does not wrap in the address space, assuming the predicate
|
||||
/// associated with \p PSE is true.
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
#include "llvm/ADT/BitVector.h"
|
||||
#include "llvm/CodeGen/MachineBasicBlock.h"
|
||||
#include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h"
|
||||
#include "llvm/Support/TypeSize.h"
|
||||
#include <vector>
|
||||
|
||||
|
|
@ -473,6 +474,11 @@ public:
|
|||
/// Return the frame base information to be encoded in the DWARF subprogram
|
||||
/// debug info.
|
||||
virtual DwarfFrameBase getDwarfFrameBase(const MachineFunction &MF) const;
|
||||
|
||||
/// This method is called at the end of prolog/epilog code insertion, so
|
||||
/// targets can emit remarks based on the final frame layout.
|
||||
virtual void emitRemarks(const MachineFunction &MF,
|
||||
MachineOptimizationRemarkEmitter *ORE) const {};
|
||||
};
|
||||
|
||||
} // End llvm namespace
|
||||
|
|
|
|||
|
|
@ -1,204 +0,0 @@
|
|||
//===- CodeGenData.h --------------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains support for codegen data that has stable summary which
|
||||
// can be used to optimize the code in the subsequent codegen.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGENDATA_CODEGENDATA_H
|
||||
#define LLVM_CODEGENDATA_CODEGENDATA_H
|
||||
|
||||
#include "llvm/ADT/BitmaskEnum.h"
|
||||
#include "llvm/Bitcode/BitcodeReader.h"
|
||||
#include "llvm/CodeGenData/OutlinedHashTree.h"
|
||||
#include "llvm/CodeGenData/OutlinedHashTreeRecord.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/Object/ObjectFile.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/TargetParser/Triple.h"
|
||||
#include <mutex>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
enum CGDataSectKind {
|
||||
#define CG_DATA_SECT_ENTRY(Kind, SectNameCommon, SectNameCoff, Prefix) Kind,
|
||||
#include "llvm/CodeGenData/CodeGenData.inc"
|
||||
};
|
||||
|
||||
std::string getCodeGenDataSectionName(CGDataSectKind CGSK,
|
||||
Triple::ObjectFormatType OF,
|
||||
bool AddSegmentInfo = true);
|
||||
|
||||
enum class CGDataKind {
|
||||
Unknown = 0x0,
|
||||
// A function outlining info.
|
||||
FunctionOutlinedHashTree = 0x1,
|
||||
LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/FunctionOutlinedHashTree)
|
||||
};
|
||||
|
||||
const std::error_category &cgdata_category();
|
||||
|
||||
enum class cgdata_error {
|
||||
success = 0,
|
||||
eof,
|
||||
bad_magic,
|
||||
bad_header,
|
||||
empty_cgdata,
|
||||
malformed,
|
||||
unsupported_version,
|
||||
};
|
||||
|
||||
inline std::error_code make_error_code(cgdata_error E) {
|
||||
return std::error_code(static_cast<int>(E), cgdata_category());
|
||||
}
|
||||
|
||||
class CGDataError : public ErrorInfo<CGDataError> {
|
||||
public:
|
||||
CGDataError(cgdata_error Err, const Twine &ErrStr = Twine())
|
||||
: Err(Err), Msg(ErrStr.str()) {
|
||||
assert(Err != cgdata_error::success && "Not an error");
|
||||
}
|
||||
|
||||
std::string message() const override;
|
||||
|
||||
void log(raw_ostream &OS) const override { OS << message(); }
|
||||
|
||||
std::error_code convertToErrorCode() const override {
|
||||
return make_error_code(Err);
|
||||
}
|
||||
|
||||
cgdata_error get() const { return Err; }
|
||||
const std::string &getMessage() const { return Msg; }
|
||||
|
||||
/// Consume an Error and return the raw enum value contained within it, and
|
||||
/// the optional error message. The Error must either be a success value, or
|
||||
/// contain a single CGDataError.
|
||||
static std::pair<cgdata_error, std::string> take(Error E) {
|
||||
auto Err = cgdata_error::success;
|
||||
std::string Msg;
|
||||
handleAllErrors(std::move(E), [&Err, &Msg](const CGDataError &IPE) {
|
||||
assert(Err == cgdata_error::success && "Multiple errors encountered");
|
||||
Err = IPE.get();
|
||||
Msg = IPE.getMessage();
|
||||
});
|
||||
return {Err, Msg};
|
||||
}
|
||||
|
||||
static char ID;
|
||||
|
||||
private:
|
||||
cgdata_error Err;
|
||||
std::string Msg;
|
||||
};
|
||||
|
||||
enum CGDataMode {
|
||||
None,
|
||||
Read,
|
||||
Write,
|
||||
};
|
||||
|
||||
class CodeGenData {
|
||||
/// Global outlined hash tree that has oulined hash sequences across modules.
|
||||
std::unique_ptr<OutlinedHashTree> PublishedHashTree;
|
||||
|
||||
/// This flag is set when -fcodegen-data-generate is passed.
|
||||
/// Or, it can be mutated with -fcodegen-data-thinlto-two-rounds.
|
||||
bool EmitCGData;
|
||||
|
||||
/// This is a singleton instance which is thread-safe. Unlike profile data
|
||||
/// which is largely function-based, codegen data describes the whole module.
|
||||
/// Therefore, this can be initialized once, and can be used across modules
|
||||
/// instead of constructing the same one for each codegen backend.
|
||||
static std::unique_ptr<CodeGenData> Instance;
|
||||
static std::once_flag OnceFlag;
|
||||
|
||||
CodeGenData() = default;
|
||||
|
||||
public:
|
||||
~CodeGenData() = default;
|
||||
|
||||
static CodeGenData &getInstance();
|
||||
|
||||
/// Returns true if we have a valid outlined hash tree.
|
||||
bool hasOutlinedHashTree() {
|
||||
return PublishedHashTree && !PublishedHashTree->empty();
|
||||
}
|
||||
|
||||
/// Returns the outlined hash tree. This can be globally used in a read-only
|
||||
/// manner.
|
||||
const OutlinedHashTree *getOutlinedHashTree() {
|
||||
return PublishedHashTree.get();
|
||||
}
|
||||
|
||||
/// Returns true if we should write codegen data.
|
||||
bool emitCGData() { return EmitCGData; }
|
||||
|
||||
/// Publish the (globally) merged or read outlined hash tree.
|
||||
void publishOutlinedHashTree(std::unique_ptr<OutlinedHashTree> HashTree) {
|
||||
PublishedHashTree = std::move(HashTree);
|
||||
// Ensure we disable emitCGData as we do not want to read and write both.
|
||||
EmitCGData = false;
|
||||
}
|
||||
};
|
||||
|
||||
namespace cgdata {
|
||||
|
||||
inline bool hasOutlinedHashTree() {
|
||||
return CodeGenData::getInstance().hasOutlinedHashTree();
|
||||
}
|
||||
|
||||
inline const OutlinedHashTree *getOutlinedHashTree() {
|
||||
return CodeGenData::getInstance().getOutlinedHashTree();
|
||||
}
|
||||
|
||||
inline bool emitCGData() { return CodeGenData::getInstance().emitCGData(); }
|
||||
|
||||
inline void
|
||||
publishOutlinedHashTree(std::unique_ptr<OutlinedHashTree> HashTree) {
|
||||
CodeGenData::getInstance().publishOutlinedHashTree(std::move(HashTree));
|
||||
}
|
||||
|
||||
void warn(Error E, StringRef Whence = "");
|
||||
void warn(Twine Message, std::string Whence = "", std::string Hint = "");
|
||||
|
||||
} // end namespace cgdata
|
||||
|
||||
namespace IndexedCGData {
|
||||
|
||||
// A signature for data validation, representing "\xffcgdata\x81" in
|
||||
// little-endian order
|
||||
const uint64_t Magic = 0x81617461646763ff;
|
||||
|
||||
enum CGDataVersion {
|
||||
// Version 1 is the first version. This version supports the outlined
|
||||
// hash tree.
|
||||
Version1 = 1,
|
||||
CurrentVersion = CG_DATA_INDEX_VERSION
|
||||
};
|
||||
const uint64_t Version = CGDataVersion::CurrentVersion;
|
||||
|
||||
struct Header {
|
||||
uint64_t Magic;
|
||||
uint32_t Version;
|
||||
uint32_t DataKind;
|
||||
uint64_t OutlinedHashTreeOffset;
|
||||
|
||||
// New fields should only be added at the end to ensure that the size
|
||||
// computation is correct. The methods below need to be updated to ensure that
|
||||
// the new field is read correctly.
|
||||
|
||||
// Reads a header struct from the buffer.
|
||||
static Expected<Header> readFromBuffer(const unsigned char *Curr);
|
||||
};
|
||||
|
||||
} // end namespace IndexedCGData
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_CODEGEN_PREPARE_H
|
||||
|
|
@ -1,46 +0,0 @@
|
|||
/*===-- CodeGenData.inc ----------------------------------------*- C++ -*-=== *\
|
||||
|*
|
||||
|* Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
|* See https://llvm.org/LICENSE.txt for license information.
|
||||
|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|*
|
||||
\*===----------------------------------------------------------------------===*/
|
||||
/*
|
||||
* This is the main file that defines all the data structure, signature,
|
||||
* constant literals that are shared across compiler, host tools (reader/writer)
|
||||
* to support codegen data.
|
||||
*
|
||||
\*===----------------------------------------------------------------------===*/
|
||||
|
||||
/* Helper macros. */
|
||||
#define CG_DATA_SIMPLE_QUOTE(x) #x
|
||||
#define CG_DATA_QUOTE(x) CG_DATA_SIMPLE_QUOTE(x)
|
||||
|
||||
#ifdef CG_DATA_SECT_ENTRY
|
||||
#define CG_DATA_DEFINED
|
||||
CG_DATA_SECT_ENTRY(CG_outline, CG_DATA_QUOTE(CG_DATA_OUTLINE_COMMON),
|
||||
CG_DATA_OUTLINE_COFF, "__DATA,")
|
||||
|
||||
#undef CG_DATA_SECT_ENTRY
|
||||
#endif
|
||||
|
||||
/* section name strings common to all targets other
|
||||
than WIN32 */
|
||||
#define CG_DATA_OUTLINE_COMMON __llvm_outline
|
||||
/* Since cg data sections are not allocated, we don't need to
|
||||
* access them at runtime.
|
||||
*/
|
||||
#define CG_DATA_OUTLINE_COFF ".loutline"
|
||||
|
||||
#ifdef _WIN32
|
||||
/* Runtime section names and name strings. */
|
||||
#define CG_DATA_SECT_NAME CG_DATA_OUTLINE_COFF
|
||||
|
||||
#else
|
||||
/* Runtime section names and name strings. */
|
||||
#define CG_DATA_SECT_NAME CG_DATA_QUOTE(CG_DATA_OUTLINE_COMMON)
|
||||
|
||||
#endif
|
||||
|
||||
/* Indexed codegen data format version (start from 1). */
|
||||
#define CG_DATA_INDEX_VERSION 1
|
||||
|
|
@ -1,154 +0,0 @@
|
|||
//===- CodeGenDataReader.h --------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains support for reading codegen data.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGENDATA_CODEGENDATAREADER_H
|
||||
#define LLVM_CODEGENDATA_CODEGENDATAREADER_H
|
||||
|
||||
#include "llvm/CodeGenData/CodeGenData.h"
|
||||
#include "llvm/CodeGenData/OutlinedHashTreeRecord.h"
|
||||
#include "llvm/Support/LineIterator.h"
|
||||
#include "llvm/Support/VirtualFileSystem.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class CodeGenDataReader {
|
||||
cgdata_error LastError = cgdata_error::success;
|
||||
std::string LastErrorMsg;
|
||||
|
||||
public:
|
||||
CodeGenDataReader() = default;
|
||||
virtual ~CodeGenDataReader() = default;
|
||||
|
||||
/// Read the header. Required before reading first record.
|
||||
virtual Error read() = 0;
|
||||
/// Return the codegen data version.
|
||||
virtual uint32_t getVersion() const = 0;
|
||||
/// Return the codegen data kind.
|
||||
virtual CGDataKind getDataKind() const = 0;
|
||||
/// Return true if the data has an outlined hash tree.
|
||||
virtual bool hasOutlinedHashTree() const = 0;
|
||||
/// Return the outlined hash tree that is released from the reader.
|
||||
std::unique_ptr<OutlinedHashTree> releaseOutlinedHashTree() {
|
||||
return std::move(HashTreeRecord.HashTree);
|
||||
}
|
||||
|
||||
/// Factory method to create an appropriately typed reader for the given
|
||||
/// codegen data file path and file system.
|
||||
static Expected<std::unique_ptr<CodeGenDataReader>>
|
||||
create(const Twine &Path, vfs::FileSystem &FS);
|
||||
|
||||
/// Factory method to create an appropriately typed reader for the given
|
||||
/// memory buffer.
|
||||
static Expected<std::unique_ptr<CodeGenDataReader>>
|
||||
create(std::unique_ptr<MemoryBuffer> Buffer);
|
||||
|
||||
/// Extract the cgdata embedded in sections from the given object file and
|
||||
/// merge them into the GlobalOutlineRecord. This is a static helper that
|
||||
/// is used by `llvm-cgdata merge` or ThinLTO's two-codegen rounds.
|
||||
static Error mergeFromObjectFile(const object::ObjectFile *Obj,
|
||||
OutlinedHashTreeRecord &GlobalOutlineRecord);
|
||||
|
||||
protected:
|
||||
/// The outlined hash tree that has been read. When it's released by
|
||||
/// releaseOutlinedHashTree(), it's no longer valid.
|
||||
OutlinedHashTreeRecord HashTreeRecord;
|
||||
|
||||
/// Set the current error and return same.
|
||||
Error error(cgdata_error Err, const std::string &ErrMsg = "") {
|
||||
LastError = Err;
|
||||
LastErrorMsg = ErrMsg;
|
||||
if (Err == cgdata_error::success)
|
||||
return Error::success();
|
||||
return make_error<CGDataError>(Err, ErrMsg);
|
||||
}
|
||||
|
||||
Error error(Error &&E) {
|
||||
handleAllErrors(std::move(E), [&](const CGDataError &IPE) {
|
||||
LastError = IPE.get();
|
||||
LastErrorMsg = IPE.getMessage();
|
||||
});
|
||||
return make_error<CGDataError>(LastError, LastErrorMsg);
|
||||
}
|
||||
|
||||
/// Clear the current error and return a successful one.
|
||||
Error success() { return error(cgdata_error::success); }
|
||||
};
|
||||
|
||||
class IndexedCodeGenDataReader : public CodeGenDataReader {
|
||||
/// The codegen data file contents.
|
||||
std::unique_ptr<MemoryBuffer> DataBuffer;
|
||||
/// The header
|
||||
IndexedCGData::Header Header;
|
||||
|
||||
public:
|
||||
IndexedCodeGenDataReader(std::unique_ptr<MemoryBuffer> DataBuffer)
|
||||
: DataBuffer(std::move(DataBuffer)) {}
|
||||
IndexedCodeGenDataReader(const IndexedCodeGenDataReader &) = delete;
|
||||
IndexedCodeGenDataReader &
|
||||
operator=(const IndexedCodeGenDataReader &) = delete;
|
||||
|
||||
/// Return true if the given buffer is in binary codegen data format.
|
||||
static bool hasFormat(const MemoryBuffer &Buffer);
|
||||
/// Read the contents including the header.
|
||||
Error read() override;
|
||||
/// Return the codegen data version.
|
||||
uint32_t getVersion() const override { return Header.Version; }
|
||||
/// Return the codegen data kind.
|
||||
CGDataKind getDataKind() const override {
|
||||
return static_cast<CGDataKind>(Header.DataKind);
|
||||
}
|
||||
/// Return true if the header indicates the data has an outlined hash tree.
|
||||
/// This does not mean that the data is still available.
|
||||
bool hasOutlinedHashTree() const override {
|
||||
return Header.DataKind &
|
||||
static_cast<uint32_t>(CGDataKind::FunctionOutlinedHashTree);
|
||||
}
|
||||
};
|
||||
|
||||
/// This format is a simple text format that's suitable for test data.
|
||||
/// The header is a custom format starting with `:` per line to indicate which
|
||||
/// codegen data is recorded. `#` is used to indicate a comment.
|
||||
/// The subsequent data is a YAML format per each codegen data in order.
|
||||
/// Currently, it only has a function outlined hash tree.
|
||||
class TextCodeGenDataReader : public CodeGenDataReader {
|
||||
/// The codegen data file contents.
|
||||
std::unique_ptr<MemoryBuffer> DataBuffer;
|
||||
/// Iterator over the profile data.
|
||||
line_iterator Line;
|
||||
/// Describe the kind of the codegen data.
|
||||
CGDataKind DataKind = CGDataKind::Unknown;
|
||||
|
||||
public:
|
||||
TextCodeGenDataReader(std::unique_ptr<MemoryBuffer> DataBuffer_)
|
||||
: DataBuffer(std::move(DataBuffer_)), Line(*DataBuffer, true, '#') {}
|
||||
TextCodeGenDataReader(const TextCodeGenDataReader &) = delete;
|
||||
TextCodeGenDataReader &operator=(const TextCodeGenDataReader &) = delete;
|
||||
|
||||
/// Return true if the given buffer is in text codegen data format.
|
||||
static bool hasFormat(const MemoryBuffer &Buffer);
|
||||
/// Read the contents including the header.
|
||||
Error read() override;
|
||||
/// Text format does not have version, so return 0.
|
||||
uint32_t getVersion() const override { return 0; }
|
||||
/// Return the codegen data kind.
|
||||
CGDataKind getDataKind() const override { return DataKind; }
|
||||
/// Return true if the header indicates the data has an outlined hash tree.
|
||||
/// This does not mean that the data is still available.
|
||||
bool hasOutlinedHashTree() const override {
|
||||
return static_cast<uint32_t>(DataKind) &
|
||||
static_cast<uint32_t>(CGDataKind::FunctionOutlinedHashTree);
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_CODEGENDATA_CODEGENDATAREADER_H
|
||||
|
|
@ -1,68 +0,0 @@
|
|||
//===- CodeGenDataWriter.h --------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains support for writing codegen data.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGENDATA_CODEGENDATAWRITER_H
|
||||
#define LLVM_CODEGENDATA_CODEGENDATAWRITER_H
|
||||
|
||||
#include "llvm/CodeGenData/CodeGenData.h"
|
||||
#include "llvm/CodeGenData/OutlinedHashTreeRecord.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class CGDataOStream;
|
||||
|
||||
class CodeGenDataWriter {
|
||||
/// The outlined hash tree to be written.
|
||||
OutlinedHashTreeRecord HashTreeRecord;
|
||||
|
||||
/// A bit mask describing the kind of the codegen data.
|
||||
CGDataKind DataKind = CGDataKind::Unknown;
|
||||
|
||||
public:
|
||||
CodeGenDataWriter() = default;
|
||||
~CodeGenDataWriter() = default;
|
||||
|
||||
/// Add the outlined hash tree record. The input Record is released.
|
||||
void addRecord(OutlinedHashTreeRecord &Record);
|
||||
|
||||
/// Write the codegen data to \c OS
|
||||
Error write(raw_fd_ostream &OS);
|
||||
|
||||
/// Write the codegen data in text format to \c OS
|
||||
Error writeText(raw_fd_ostream &OS);
|
||||
|
||||
/// Return the attributes of the current CGData.
|
||||
CGDataKind getCGDataKind() const { return DataKind; }
|
||||
|
||||
/// Return true if the header indicates the data has an outlined hash tree.
|
||||
bool hasOutlinedHashTree() const {
|
||||
return static_cast<uint32_t>(DataKind) &
|
||||
static_cast<uint32_t>(CGDataKind::FunctionOutlinedHashTree);
|
||||
}
|
||||
|
||||
private:
|
||||
/// The offset of the outlined hash tree in the file.
|
||||
uint64_t OutlinedHashTreeOffset;
|
||||
|
||||
/// Write the codegen data header to \c COS
|
||||
Error writeHeader(CGDataOStream &COS);
|
||||
|
||||
/// Write the codegen data header in text to \c OS
|
||||
Error writeHeaderText(raw_fd_ostream &OS);
|
||||
|
||||
Error writeImpl(CGDataOStream &COS);
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_CODEGENDATA_CODEGENDATAWRITER_H
|
||||
|
|
@ -846,8 +846,10 @@ struct AAMDNodes {
|
|||
AAMDNodes concat(const AAMDNodes &Other) const;
|
||||
|
||||
/// Create a new AAMDNode for accessing \p AccessSize bytes of this AAMDNode.
|
||||
/// If his AAMDNode has !tbaa.struct and \p AccessSize matches the size of the
|
||||
/// field at offset 0, get the TBAA tag describing the accessed field.
|
||||
/// If this AAMDNode has !tbaa.struct and \p AccessSize matches the size of
|
||||
/// the field at offset 0, get the TBAA tag describing the accessed field.
|
||||
/// If such an AAMDNode already embeds !tbaa, the existing one is retrieved.
|
||||
/// Finally, !tbaa.struct is zeroed out.
|
||||
AAMDNodes adjustForAccess(unsigned AccessSize);
|
||||
AAMDNodes adjustForAccess(size_t Offset, Type *AccessTy,
|
||||
const DataLayout &DL);
|
||||
|
|
|
|||
|
|
@ -728,11 +728,6 @@ public:
|
|||
|
||||
MemAccessInfoList &getDependenciesToCheck() { return CheckDeps; }
|
||||
|
||||
const DenseMap<Value *, SmallVector<const Value *, 16>> &
|
||||
getUnderlyingObjects() {
|
||||
return UnderlyingObjects;
|
||||
}
|
||||
|
||||
private:
|
||||
typedef MapVector<MemAccessInfo, SmallSetVector<Type *, 1>> PtrAccessMap;
|
||||
|
||||
|
|
@ -1459,22 +1454,23 @@ static bool isNoWrapAddRec(Value *Ptr, const SCEVAddRecExpr *AR,
|
|||
}
|
||||
|
||||
/// Check whether the access through \p Ptr has a constant stride.
|
||||
std::optional<int64_t> llvm::getPtrStride(PredicatedScalarEvolution &PSE,
|
||||
Type *AccessTy, Value *Ptr,
|
||||
const Loop *Lp,
|
||||
const DenseMap<Value *, const SCEV *> &StridesMap,
|
||||
bool Assume, bool ShouldCheckWrap) {
|
||||
std::optional<int64_t>
|
||||
llvm::getPtrStride(PredicatedScalarEvolution &PSE, Type *AccessTy, Value *Ptr,
|
||||
const Loop *Lp,
|
||||
const DenseMap<Value *, const SCEV *> &StridesMap,
|
||||
bool Assume, bool ShouldCheckWrap) {
|
||||
const SCEV *PtrScev = replaceSymbolicStrideSCEV(PSE, StridesMap, Ptr);
|
||||
if (PSE.getSE()->isLoopInvariant(PtrScev, Lp))
|
||||
return {0};
|
||||
|
||||
Type *Ty = Ptr->getType();
|
||||
assert(Ty->isPointerTy() && "Unexpected non-ptr");
|
||||
|
||||
if (isa<ScalableVectorType>(AccessTy)) {
|
||||
LLVM_DEBUG(dbgs() << "LAA: Bad stride - Scalable object: " << *AccessTy
|
||||
<< "\n");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const SCEV *PtrScev = replaceSymbolicStrideSCEV(PSE, StridesMap, Ptr);
|
||||
|
||||
const SCEVAddRecExpr *AR = dyn_cast<SCEVAddRecExpr>(PtrScev);
|
||||
if (Assume && !AR)
|
||||
AR = PSE.getAsAddRec(Ptr);
|
||||
|
|
@ -1899,24 +1895,12 @@ static bool areStridedAccessesIndependent(uint64_t Distance, uint64_t Stride,
|
|||
return ScaledDist % Stride;
|
||||
}
|
||||
|
||||
/// Returns true if any of the underlying objects has a loop varying address,
|
||||
/// i.e. may change in \p L.
|
||||
static bool
|
||||
isLoopVariantIndirectAddress(ArrayRef<const Value *> UnderlyingObjects,
|
||||
ScalarEvolution &SE, const Loop *L) {
|
||||
return any_of(UnderlyingObjects, [&SE, L](const Value *UO) {
|
||||
return !SE.isLoopInvariant(SE.getSCEV(const_cast<Value *>(UO)), L);
|
||||
});
|
||||
}
|
||||
|
||||
std::variant<MemoryDepChecker::Dependence::DepType,
|
||||
MemoryDepChecker::DepDistanceStrideAndSizeInfo>
|
||||
MemoryDepChecker::getDependenceDistanceStrideAndSize(
|
||||
const AccessAnalysis::MemAccessInfo &A, Instruction *AInst,
|
||||
const AccessAnalysis::MemAccessInfo &B, Instruction *BInst,
|
||||
const DenseMap<Value *, SmallVector<const Value *, 16>>
|
||||
&UnderlyingObjects) {
|
||||
auto &DL = InnermostLoop->getHeader()->getDataLayout();
|
||||
const AccessAnalysis::MemAccessInfo &B, Instruction *BInst) {
|
||||
const auto &DL = InnermostLoop->getHeader()->getDataLayout();
|
||||
auto &SE = *PSE.getSE();
|
||||
auto [APtr, AIsWrite] = A;
|
||||
auto [BPtr, BIsWrite] = B;
|
||||
|
|
@ -1933,12 +1917,10 @@ MemoryDepChecker::getDependenceDistanceStrideAndSize(
|
|||
BPtr->getType()->getPointerAddressSpace())
|
||||
return MemoryDepChecker::Dependence::Unknown;
|
||||
|
||||
int64_t StrideAPtr =
|
||||
getPtrStride(PSE, ATy, APtr, InnermostLoop, SymbolicStrides, true)
|
||||
.value_or(0);
|
||||
int64_t StrideBPtr =
|
||||
getPtrStride(PSE, BTy, BPtr, InnermostLoop, SymbolicStrides, true)
|
||||
.value_or(0);
|
||||
std::optional<int64_t> StrideAPtr =
|
||||
getPtrStride(PSE, ATy, APtr, InnermostLoop, SymbolicStrides, true, true);
|
||||
std::optional<int64_t> StrideBPtr =
|
||||
getPtrStride(PSE, BTy, BPtr, InnermostLoop, SymbolicStrides, true, true);
|
||||
|
||||
const SCEV *Src = PSE.getSCEV(APtr);
|
||||
const SCEV *Sink = PSE.getSCEV(BPtr);
|
||||
|
|
@ -1946,26 +1928,19 @@ MemoryDepChecker::getDependenceDistanceStrideAndSize(
|
|||
// If the induction step is negative we have to invert source and sink of the
|
||||
// dependence when measuring the distance between them. We should not swap
|
||||
// AIsWrite with BIsWrite, as their uses expect them in program order.
|
||||
if (StrideAPtr < 0) {
|
||||
if (StrideAPtr && *StrideAPtr < 0) {
|
||||
std::swap(Src, Sink);
|
||||
std::swap(AInst, BInst);
|
||||
std::swap(StrideAPtr, StrideBPtr);
|
||||
}
|
||||
|
||||
const SCEV *Dist = SE.getMinusSCEV(Sink, Src);
|
||||
|
||||
LLVM_DEBUG(dbgs() << "LAA: Src Scev: " << *Src << "Sink Scev: " << *Sink
|
||||
<< "(Induction step: " << StrideAPtr << ")\n");
|
||||
<< "\n");
|
||||
LLVM_DEBUG(dbgs() << "LAA: Distance for " << *AInst << " to " << *BInst
|
||||
<< ": " << *Dist << "\n");
|
||||
|
||||
// Needs accesses where the addresses of the accessed underlying objects do
|
||||
// not change within the loop.
|
||||
if (isLoopVariantIndirectAddress(UnderlyingObjects.find(APtr)->second, SE,
|
||||
InnermostLoop) ||
|
||||
isLoopVariantIndirectAddress(UnderlyingObjects.find(BPtr)->second, SE,
|
||||
InnermostLoop))
|
||||
return MemoryDepChecker::Dependence::IndirectUnsafe;
|
||||
|
||||
// Check if we can prove that Sink only accesses memory after Src's end or
|
||||
// vice versa. At the moment this is limited to cases where either source or
|
||||
// sink are loop invariant to avoid compile-time increases. This is not
|
||||
|
|
@ -1987,12 +1962,33 @@ MemoryDepChecker::getDependenceDistanceStrideAndSize(
|
|||
}
|
||||
}
|
||||
|
||||
// Need accesses with constant strides and the same direction. We don't want
|
||||
// to vectorize "A[B[i]] += ..." and similar code or pointer arithmetic that
|
||||
// could wrap in the address space.
|
||||
if (!StrideAPtr || !StrideBPtr || (StrideAPtr > 0 && StrideBPtr < 0) ||
|
||||
(StrideAPtr < 0 && StrideBPtr > 0)) {
|
||||
// Need accesses with constant strides and the same direction for further
|
||||
// dependence analysis. We don't want to vectorize "A[B[i]] += ..." and
|
||||
// similar code or pointer arithmetic that could wrap in the address space.
|
||||
|
||||
// If either Src or Sink are not strided (i.e. not a non-wrapping AddRec) and
|
||||
// not loop-invariant (stride will be 0 in that case), we cannot analyze the
|
||||
// dependence further and also cannot generate runtime checks.
|
||||
if (!StrideAPtr || !StrideBPtr) {
|
||||
LLVM_DEBUG(dbgs() << "Pointer access with non-constant stride\n");
|
||||
return MemoryDepChecker::Dependence::IndirectUnsafe;
|
||||
}
|
||||
|
||||
int64_t StrideAPtrInt = *StrideAPtr;
|
||||
int64_t StrideBPtrInt = *StrideBPtr;
|
||||
LLVM_DEBUG(dbgs() << "LAA: Src induction step: " << StrideAPtrInt
|
||||
<< " Sink induction step: " << StrideBPtrInt << "\n");
|
||||
// At least Src or Sink are loop invariant and the other is strided or
|
||||
// invariant. We can generate a runtime check to disambiguate the accesses.
|
||||
if (StrideAPtrInt == 0 || StrideBPtrInt == 0)
|
||||
return MemoryDepChecker::Dependence::Unknown;
|
||||
|
||||
// Both Src and Sink have a constant stride, check if they are in the same
|
||||
// direction.
|
||||
if ((StrideAPtrInt > 0 && StrideBPtrInt < 0) ||
|
||||
(StrideAPtrInt < 0 && StrideBPtrInt > 0)) {
|
||||
LLVM_DEBUG(
|
||||
dbgs() << "Pointer access with strides in different directions\n");
|
||||
return MemoryDepChecker::Dependence::Unknown;
|
||||
}
|
||||
|
||||
|
|
@ -2001,22 +1997,20 @@ MemoryDepChecker::getDependenceDistanceStrideAndSize(
|
|||
DL.getTypeStoreSizeInBits(ATy) == DL.getTypeStoreSizeInBits(BTy);
|
||||
if (!HasSameSize)
|
||||
TypeByteSize = 0;
|
||||
return DepDistanceStrideAndSizeInfo(Dist, std::abs(StrideAPtr),
|
||||
std::abs(StrideBPtr), TypeByteSize,
|
||||
return DepDistanceStrideAndSizeInfo(Dist, std::abs(StrideAPtrInt),
|
||||
std::abs(StrideBPtrInt), TypeByteSize,
|
||||
AIsWrite, BIsWrite);
|
||||
}
|
||||
|
||||
MemoryDepChecker::Dependence::DepType MemoryDepChecker::isDependent(
|
||||
const MemAccessInfo &A, unsigned AIdx, const MemAccessInfo &B,
|
||||
unsigned BIdx,
|
||||
const DenseMap<Value *, SmallVector<const Value *, 16>>
|
||||
&UnderlyingObjects) {
|
||||
MemoryDepChecker::Dependence::DepType
|
||||
MemoryDepChecker::isDependent(const MemAccessInfo &A, unsigned AIdx,
|
||||
const MemAccessInfo &B, unsigned BIdx) {
|
||||
assert(AIdx < BIdx && "Must pass arguments in program order");
|
||||
|
||||
// Get the dependence distance, stride, type size and what access writes for
|
||||
// the dependence between A and B.
|
||||
auto Res = getDependenceDistanceStrideAndSize(
|
||||
A, InstMap[AIdx], B, InstMap[BIdx], UnderlyingObjects);
|
||||
auto Res =
|
||||
getDependenceDistanceStrideAndSize(A, InstMap[AIdx], B, InstMap[BIdx]);
|
||||
if (std::holds_alternative<Dependence::DepType>(Res))
|
||||
return std::get<Dependence::DepType>(Res);
|
||||
|
||||
|
|
@ -2250,10 +2244,8 @@ MemoryDepChecker::Dependence::DepType MemoryDepChecker::isDependent(
|
|||
return Dependence::BackwardVectorizable;
|
||||
}
|
||||
|
||||
bool MemoryDepChecker::areDepsSafe(
|
||||
DepCandidates &AccessSets, MemAccessInfoList &CheckDeps,
|
||||
const DenseMap<Value *, SmallVector<const Value *, 16>>
|
||||
&UnderlyingObjects) {
|
||||
bool MemoryDepChecker::areDepsSafe(const DepCandidates &AccessSets,
|
||||
const MemAccessInfoList &CheckDeps) {
|
||||
|
||||
MinDepDistBytes = -1;
|
||||
SmallPtrSet<MemAccessInfo, 8> Visited;
|
||||
|
|
@ -2296,8 +2288,8 @@ bool MemoryDepChecker::areDepsSafe(
|
|||
if (*I1 > *I2)
|
||||
std::swap(A, B);
|
||||
|
||||
Dependence::DepType Type = isDependent(*A.first, A.second, *B.first,
|
||||
B.second, UnderlyingObjects);
|
||||
Dependence::DepType Type =
|
||||
isDependent(*A.first, A.second, *B.first, B.second);
|
||||
mergeInStatus(Dependence::isSafeForVectorization(Type));
|
||||
|
||||
// Gather dependences unless we accumulated MaxDependences
|
||||
|
|
@ -2652,8 +2644,7 @@ bool LoopAccessInfo::analyzeLoop(AAResults *AA, LoopInfo *LI,
|
|||
if (Accesses.isDependencyCheckNeeded()) {
|
||||
LLVM_DEBUG(dbgs() << "LAA: Checking memory dependencies\n");
|
||||
DepsAreSafe = DepChecker->areDepsSafe(DependentAccesses,
|
||||
Accesses.getDependenciesToCheck(),
|
||||
Accesses.getUnderlyingObjects());
|
||||
Accesses.getDependenciesToCheck());
|
||||
|
||||
if (!DepsAreSafe && DepChecker->shouldRetryWithRuntimeCheck()) {
|
||||
LLVM_DEBUG(dbgs() << "LAA: Retrying with memory checks\n");
|
||||
|
|
|
|||
|
|
@ -822,16 +822,16 @@ MDNode *AAMDNodes::extendToTBAA(MDNode *MD, ssize_t Len) {
|
|||
AAMDNodes AAMDNodes::adjustForAccess(unsigned AccessSize) {
|
||||
AAMDNodes New = *this;
|
||||
MDNode *M = New.TBAAStruct;
|
||||
if (M && M->getNumOperands() >= 3 && M->getOperand(0) &&
|
||||
if (!New.TBAA && M && M->getNumOperands() >= 3 && M->getOperand(0) &&
|
||||
mdconst::hasa<ConstantInt>(M->getOperand(0)) &&
|
||||
mdconst::extract<ConstantInt>(M->getOperand(0))->isZero() &&
|
||||
M->getOperand(1) && mdconst::hasa<ConstantInt>(M->getOperand(1)) &&
|
||||
mdconst::extract<ConstantInt>(M->getOperand(1))->getValue() ==
|
||||
AccessSize &&
|
||||
M->getOperand(2) && isa<MDNode>(M->getOperand(2))) {
|
||||
New.TBAAStruct = nullptr;
|
||||
M->getOperand(2) && isa<MDNode>(M->getOperand(2)))
|
||||
New.TBAA = cast<MDNode>(M->getOperand(2));
|
||||
}
|
||||
|
||||
New.TBAAStruct = nullptr;
|
||||
return New;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3889,6 +3889,7 @@ bool IRTranslator::runOnMachineFunction(MachineFunction &CurMF) {
|
|||
F.getSubprogram(), &F.getEntryBlock());
|
||||
R << "unable to translate in big endian mode";
|
||||
reportTranslationError(*MF, *TPC, *ORE, R);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Release the per-function state when we return, whether we succeeded or not.
|
||||
|
|
|
|||
|
|
@ -341,6 +341,9 @@ bool PEI::runOnMachineFunction(MachineFunction &MF) {
|
|||
<< ore::NV("Function", MF.getFunction().getName()) << "'";
|
||||
});
|
||||
|
||||
// Emit any remarks implemented for the target, based on final frame layout.
|
||||
TFI->emitRemarks(MF, ORE);
|
||||
|
||||
delete RS;
|
||||
SaveBlocks.clear();
|
||||
RestoreBlocks.clear();
|
||||
|
|
|
|||
|
|
@ -1,196 +0,0 @@
|
|||
//===-- CodeGenData.cpp ---------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains support for codegen data that has stable summary which
|
||||
// can be used to optimize the code in the subsequent codegen.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Bitcode/BitcodeWriter.h"
|
||||
#include "llvm/CodeGenData/CodeGenDataReader.h"
|
||||
#include "llvm/CodeGenData/OutlinedHashTreeRecord.h"
|
||||
#include "llvm/Object/ObjectFile.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/FileSystem.h"
|
||||
#include "llvm/Support/WithColor.h"
|
||||
|
||||
#define DEBUG_TYPE "cg-data"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace cgdata;
|
||||
|
||||
static std::string getCGDataErrString(cgdata_error Err,
|
||||
const std::string &ErrMsg = "") {
|
||||
std::string Msg;
|
||||
raw_string_ostream OS(Msg);
|
||||
|
||||
switch (Err) {
|
||||
case cgdata_error::success:
|
||||
OS << "success";
|
||||
break;
|
||||
case cgdata_error::eof:
|
||||
OS << "end of File";
|
||||
break;
|
||||
case cgdata_error::bad_magic:
|
||||
OS << "invalid codegen data (bad magic)";
|
||||
break;
|
||||
case cgdata_error::bad_header:
|
||||
OS << "invalid codegen data (file header is corrupt)";
|
||||
break;
|
||||
case cgdata_error::empty_cgdata:
|
||||
OS << "empty codegen data";
|
||||
break;
|
||||
case cgdata_error::malformed:
|
||||
OS << "malformed codegen data";
|
||||
break;
|
||||
case cgdata_error::unsupported_version:
|
||||
OS << "unsupported codegen data version";
|
||||
break;
|
||||
}
|
||||
|
||||
// If optional error message is not empty, append it to the message.
|
||||
if (!ErrMsg.empty())
|
||||
OS << ": " << ErrMsg;
|
||||
|
||||
return OS.str();
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// FIXME: This class is only here to support the transition to llvm::Error. It
|
||||
// will be removed once this transition is complete. Clients should prefer to
|
||||
// deal with the Error value directly, rather than converting to error_code.
|
||||
class CGDataErrorCategoryType : public std::error_category {
|
||||
const char *name() const noexcept override { return "llvm.cgdata"; }
|
||||
|
||||
std::string message(int IE) const override {
|
||||
return getCGDataErrString(static_cast<cgdata_error>(IE));
|
||||
}
|
||||
};
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
const std::error_category &llvm::cgdata_category() {
|
||||
static CGDataErrorCategoryType ErrorCategory;
|
||||
return ErrorCategory;
|
||||
}
|
||||
|
||||
std::string CGDataError::message() const {
|
||||
return getCGDataErrString(Err, Msg);
|
||||
}
|
||||
|
||||
char CGDataError::ID = 0;
|
||||
|
||||
namespace {
|
||||
|
||||
const char *CodeGenDataSectNameCommon[] = {
|
||||
#define CG_DATA_SECT_ENTRY(Kind, SectNameCommon, SectNameCoff, Prefix) \
|
||||
SectNameCommon,
|
||||
#include "llvm/CodeGenData/CodeGenData.inc"
|
||||
};
|
||||
|
||||
const char *CodeGenDataSectNameCoff[] = {
|
||||
#define CG_DATA_SECT_ENTRY(Kind, SectNameCommon, SectNameCoff, Prefix) \
|
||||
SectNameCoff,
|
||||
#include "llvm/CodeGenData/CodeGenData.inc"
|
||||
};
|
||||
|
||||
const char *CodeGenDataSectNamePrefix[] = {
|
||||
#define CG_DATA_SECT_ENTRY(Kind, SectNameCommon, SectNameCoff, Prefix) Prefix,
|
||||
#include "llvm/CodeGenData/CodeGenData.inc"
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace llvm {
|
||||
|
||||
std::string getCodeGenDataSectionName(CGDataSectKind CGSK,
|
||||
Triple::ObjectFormatType OF,
|
||||
bool AddSegmentInfo) {
|
||||
std::string SectName;
|
||||
|
||||
if (OF == Triple::MachO && AddSegmentInfo)
|
||||
SectName = CodeGenDataSectNamePrefix[CGSK];
|
||||
|
||||
if (OF == Triple::COFF)
|
||||
SectName += CodeGenDataSectNameCoff[CGSK];
|
||||
else
|
||||
SectName += CodeGenDataSectNameCommon[CGSK];
|
||||
|
||||
return SectName;
|
||||
}
|
||||
|
||||
std::unique_ptr<CodeGenData> CodeGenData::Instance = nullptr;
|
||||
std::once_flag CodeGenData::OnceFlag;
|
||||
|
||||
CodeGenData &CodeGenData::getInstance() {
|
||||
std::call_once(CodeGenData::OnceFlag, []() {
|
||||
Instance = std::unique_ptr<CodeGenData>(new CodeGenData());
|
||||
|
||||
// TODO: Initialize writer or reader mode for the client optimization.
|
||||
});
|
||||
return *(Instance.get());
|
||||
}
|
||||
|
||||
namespace IndexedCGData {
|
||||
|
||||
Expected<Header> Header::readFromBuffer(const unsigned char *Curr) {
|
||||
using namespace support;
|
||||
|
||||
static_assert(std::is_standard_layout_v<llvm::IndexedCGData::Header>,
|
||||
"The header should be standard layout type since we use offset "
|
||||
"of fields to read.");
|
||||
Header H;
|
||||
H.Magic = endian::readNext<uint64_t, endianness::little, unaligned>(Curr);
|
||||
if (H.Magic != IndexedCGData::Magic)
|
||||
return make_error<CGDataError>(cgdata_error::bad_magic);
|
||||
H.Version = endian::readNext<uint32_t, endianness::little, unaligned>(Curr);
|
||||
if (H.Version > IndexedCGData::CGDataVersion::CurrentVersion)
|
||||
return make_error<CGDataError>(cgdata_error::unsupported_version);
|
||||
H.DataKind = endian::readNext<uint32_t, endianness::little, unaligned>(Curr);
|
||||
|
||||
switch (H.Version) {
|
||||
// When a new field is added to the header add a case statement here to
|
||||
// compute the size as offset of the new field + size of the new field. This
|
||||
// relies on the field being added to the end of the list.
|
||||
static_assert(IndexedCGData::CGDataVersion::CurrentVersion == Version1,
|
||||
"Please update the size computation below if a new field has "
|
||||
"been added to the header, if not add a case statement to "
|
||||
"fall through to the latest version.");
|
||||
case 1ull:
|
||||
H.OutlinedHashTreeOffset =
|
||||
endian::readNext<uint64_t, endianness::little, unaligned>(Curr);
|
||||
}
|
||||
|
||||
return H;
|
||||
}
|
||||
|
||||
} // end namespace IndexedCGData
|
||||
|
||||
namespace cgdata {
|
||||
|
||||
void warn(Twine Message, std::string Whence, std::string Hint) {
|
||||
WithColor::warning();
|
||||
if (!Whence.empty())
|
||||
errs() << Whence << ": ";
|
||||
errs() << Message << "\n";
|
||||
if (!Hint.empty())
|
||||
WithColor::note() << Hint << "\n";
|
||||
}
|
||||
|
||||
void warn(Error E, StringRef Whence) {
|
||||
if (E.isA<CGDataError>()) {
|
||||
handleAllErrors(std::move(E), [&](const CGDataError &IPE) {
|
||||
warn(IPE.message(), Whence.str(), "");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
} // end namespace cgdata
|
||||
|
||||
} // end namespace llvm
|
||||
|
|
@ -1,175 +0,0 @@
|
|||
//===- CodeGenDataReader.cpp ----------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains support for reading codegen data.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/CodeGenData/CodeGenDataReader.h"
|
||||
#include "llvm/CodeGenData/OutlinedHashTreeRecord.h"
|
||||
#include "llvm/Object/ObjectFile.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
|
||||
#define DEBUG_TYPE "cg-data-reader"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
namespace llvm {
|
||||
|
||||
static Expected<std::unique_ptr<MemoryBuffer>>
|
||||
setupMemoryBuffer(const Twine &Filename, vfs::FileSystem &FS) {
|
||||
auto BufferOrErr = Filename.str() == "-" ? MemoryBuffer::getSTDIN()
|
||||
: FS.getBufferForFile(Filename);
|
||||
if (std::error_code EC = BufferOrErr.getError())
|
||||
return errorCodeToError(EC);
|
||||
return std::move(BufferOrErr.get());
|
||||
}
|
||||
|
||||
Error CodeGenDataReader::mergeFromObjectFile(
|
||||
const object::ObjectFile *Obj,
|
||||
OutlinedHashTreeRecord &GlobalOutlineRecord) {
|
||||
Triple TT = Obj->makeTriple();
|
||||
auto CGOutLineName =
|
||||
getCodeGenDataSectionName(CG_outline, TT.getObjectFormat(), false);
|
||||
|
||||
for (auto &Section : Obj->sections()) {
|
||||
Expected<StringRef> NameOrErr = Section.getName();
|
||||
if (!NameOrErr)
|
||||
return NameOrErr.takeError();
|
||||
Expected<StringRef> ContentsOrErr = Section.getContents();
|
||||
if (!ContentsOrErr)
|
||||
return ContentsOrErr.takeError();
|
||||
auto *Data = reinterpret_cast<const unsigned char *>(ContentsOrErr->data());
|
||||
auto *EndData = Data + ContentsOrErr->size();
|
||||
|
||||
if (*NameOrErr == CGOutLineName) {
|
||||
// In case dealing with an executable that has concatenated cgdata,
|
||||
// we want to merge them into a single cgdata.
|
||||
// Although it's not a typical workflow, we support this scenario.
|
||||
while (Data != EndData) {
|
||||
OutlinedHashTreeRecord LocalOutlineRecord;
|
||||
LocalOutlineRecord.deserialize(Data);
|
||||
GlobalOutlineRecord.merge(LocalOutlineRecord);
|
||||
}
|
||||
}
|
||||
// TODO: Add support for other cgdata sections.
|
||||
}
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error IndexedCodeGenDataReader::read() {
|
||||
using namespace support;
|
||||
|
||||
// The smallest header with the version 1 is 24 bytes
|
||||
const unsigned MinHeaderSize = 24;
|
||||
if (DataBuffer->getBufferSize() < MinHeaderSize)
|
||||
return error(cgdata_error::bad_header);
|
||||
|
||||
auto *Start =
|
||||
reinterpret_cast<const unsigned char *>(DataBuffer->getBufferStart());
|
||||
auto *End =
|
||||
reinterpret_cast<const unsigned char *>(DataBuffer->getBufferEnd());
|
||||
if (auto E = IndexedCGData::Header::readFromBuffer(Start).moveInto(Header))
|
||||
return E;
|
||||
|
||||
if (hasOutlinedHashTree()) {
|
||||
const unsigned char *Ptr = Start + Header.OutlinedHashTreeOffset;
|
||||
if (Ptr >= End)
|
||||
return error(cgdata_error::eof);
|
||||
HashTreeRecord.deserialize(Ptr);
|
||||
}
|
||||
|
||||
return success();
|
||||
}
|
||||
|
||||
Expected<std::unique_ptr<CodeGenDataReader>>
|
||||
CodeGenDataReader::create(const Twine &Path, vfs::FileSystem &FS) {
|
||||
// Set up the buffer to read.
|
||||
auto BufferOrError = setupMemoryBuffer(Path, FS);
|
||||
if (Error E = BufferOrError.takeError())
|
||||
return std::move(E);
|
||||
return CodeGenDataReader::create(std::move(BufferOrError.get()));
|
||||
}
|
||||
|
||||
Expected<std::unique_ptr<CodeGenDataReader>>
|
||||
CodeGenDataReader::create(std::unique_ptr<MemoryBuffer> Buffer) {
|
||||
if (Buffer->getBufferSize() == 0)
|
||||
return make_error<CGDataError>(cgdata_error::empty_cgdata);
|
||||
|
||||
std::unique_ptr<CodeGenDataReader> Reader;
|
||||
// Create the reader.
|
||||
if (IndexedCodeGenDataReader::hasFormat(*Buffer))
|
||||
Reader = std::make_unique<IndexedCodeGenDataReader>(std::move(Buffer));
|
||||
else if (TextCodeGenDataReader::hasFormat(*Buffer))
|
||||
Reader = std::make_unique<TextCodeGenDataReader>(std::move(Buffer));
|
||||
else
|
||||
return make_error<CGDataError>(cgdata_error::malformed);
|
||||
|
||||
// Initialize the reader and return the result.
|
||||
if (Error E = Reader->read())
|
||||
return std::move(E);
|
||||
|
||||
return std::move(Reader);
|
||||
}
|
||||
|
||||
bool IndexedCodeGenDataReader::hasFormat(const MemoryBuffer &DataBuffer) {
|
||||
using namespace support;
|
||||
if (DataBuffer.getBufferSize() < sizeof(IndexedCGData::Magic))
|
||||
return false;
|
||||
|
||||
uint64_t Magic = endian::read<uint64_t, llvm::endianness::little, aligned>(
|
||||
DataBuffer.getBufferStart());
|
||||
// Verify that it's magical.
|
||||
return Magic == IndexedCGData::Magic;
|
||||
}
|
||||
|
||||
bool TextCodeGenDataReader::hasFormat(const MemoryBuffer &Buffer) {
|
||||
// Verify that this really looks like plain ASCII text by checking a
|
||||
// 'reasonable' number of characters (up to the magic size).
|
||||
StringRef Prefix = Buffer.getBuffer().take_front(sizeof(uint64_t));
|
||||
return llvm::all_of(Prefix, [](char c) { return isPrint(c) || isSpace(c); });
|
||||
}
|
||||
Error TextCodeGenDataReader::read() {
|
||||
using namespace support;
|
||||
|
||||
// Parse the custom header line by line.
|
||||
for (; !Line.is_at_eof(); ++Line) {
|
||||
// Skip empty or whitespace-only lines
|
||||
if (Line->trim().empty())
|
||||
continue;
|
||||
|
||||
if (!Line->starts_with(":"))
|
||||
break;
|
||||
StringRef Str = Line->drop_front().rtrim();
|
||||
if (Str.equals_insensitive("outlined_hash_tree"))
|
||||
DataKind |= CGDataKind::FunctionOutlinedHashTree;
|
||||
else
|
||||
return error(cgdata_error::bad_header);
|
||||
}
|
||||
|
||||
// We treat an empty header (that is a comment # only) as a valid header.
|
||||
if (Line.is_at_eof()) {
|
||||
if (DataKind == CGDataKind::Unknown)
|
||||
return Error::success();
|
||||
return error(cgdata_error::bad_header);
|
||||
}
|
||||
|
||||
// The YAML docs follow after the header.
|
||||
const char *Pos = Line->data();
|
||||
size_t Size = reinterpret_cast<size_t>(DataBuffer->getBufferEnd()) -
|
||||
reinterpret_cast<size_t>(Pos);
|
||||
yaml::Input YOS(StringRef(Pos, Size));
|
||||
if (hasOutlinedHashTree())
|
||||
HashTreeRecord.deserializeYAML(YOS);
|
||||
|
||||
// TODO: Add more yaml cgdata in order
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
} // end namespace llvm
|
||||
|
|
@ -1,162 +0,0 @@
|
|||
//===- CodeGenDataWriter.cpp ----------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains support for writing codegen data.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/CodeGenData/CodeGenDataWriter.h"
|
||||
#include "llvm/Support/Endian.h"
|
||||
#include "llvm/Support/EndianStream.h"
|
||||
|
||||
#define DEBUG_TYPE "cg-data-writer"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
namespace llvm {
|
||||
|
||||
/// A struct to define how the data stream should be patched.
|
||||
struct CGDataPatchItem {
|
||||
uint64_t Pos; // Where to patch.
|
||||
uint64_t *D; // Pointer to an array of source data.
|
||||
int N; // Number of elements in \c D array.
|
||||
};
|
||||
|
||||
// A wrapper class to abstract writer stream with support of bytes
|
||||
// back patching.
|
||||
class CGDataOStream {
|
||||
public:
|
||||
CGDataOStream(raw_fd_ostream &FD)
|
||||
: IsFDOStream(true), OS(FD), LE(FD, llvm::endianness::little) {}
|
||||
CGDataOStream(raw_string_ostream &STR)
|
||||
: IsFDOStream(false), OS(STR), LE(STR, llvm::endianness::little) {}
|
||||
|
||||
uint64_t tell() { return OS.tell(); }
|
||||
void write(uint64_t V) { LE.write<uint64_t>(V); }
|
||||
void write32(uint32_t V) { LE.write<uint32_t>(V); }
|
||||
void write8(uint8_t V) { LE.write<uint8_t>(V); }
|
||||
|
||||
// \c patch can only be called when all data is written and flushed.
|
||||
// For raw_string_ostream, the patch is done on the target string
|
||||
// directly and it won't be reflected in the stream's internal buffer.
|
||||
void patch(ArrayRef<CGDataPatchItem> P) {
|
||||
using namespace support;
|
||||
|
||||
if (IsFDOStream) {
|
||||
raw_fd_ostream &FDOStream = static_cast<raw_fd_ostream &>(OS);
|
||||
const uint64_t LastPos = FDOStream.tell();
|
||||
for (const auto &K : P) {
|
||||
FDOStream.seek(K.Pos);
|
||||
for (int I = 0; I < K.N; I++)
|
||||
write(K.D[I]);
|
||||
}
|
||||
// Reset the stream to the last position after patching so that users
|
||||
// don't accidentally overwrite data. This makes it consistent with
|
||||
// the string stream below which replaces the data directly.
|
||||
FDOStream.seek(LastPos);
|
||||
} else {
|
||||
raw_string_ostream &SOStream = static_cast<raw_string_ostream &>(OS);
|
||||
std::string &Data = SOStream.str(); // with flush
|
||||
for (const auto &K : P) {
|
||||
for (int I = 0; I < K.N; I++) {
|
||||
uint64_t Bytes =
|
||||
endian::byte_swap<uint64_t, llvm::endianness::little>(K.D[I]);
|
||||
Data.replace(K.Pos + I * sizeof(uint64_t), sizeof(uint64_t),
|
||||
(const char *)&Bytes, sizeof(uint64_t));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If \c OS is an instance of \c raw_fd_ostream, this field will be
|
||||
// true. Otherwise, \c OS will be an raw_string_ostream.
|
||||
bool IsFDOStream;
|
||||
raw_ostream &OS;
|
||||
support::endian::Writer LE;
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
void CodeGenDataWriter::addRecord(OutlinedHashTreeRecord &Record) {
|
||||
assert(Record.HashTree && "empty hash tree in the record");
|
||||
HashTreeRecord.HashTree = std::move(Record.HashTree);
|
||||
|
||||
DataKind |= CGDataKind::FunctionOutlinedHashTree;
|
||||
}
|
||||
|
||||
Error CodeGenDataWriter::write(raw_fd_ostream &OS) {
|
||||
CGDataOStream COS(OS);
|
||||
return writeImpl(COS);
|
||||
}
|
||||
|
||||
Error CodeGenDataWriter::writeHeader(CGDataOStream &COS) {
|
||||
using namespace support;
|
||||
IndexedCGData::Header Header;
|
||||
Header.Magic = IndexedCGData::Magic;
|
||||
Header.Version = IndexedCGData::Version;
|
||||
|
||||
// Set the CGDataKind depending on the kind.
|
||||
Header.DataKind = 0;
|
||||
if (static_cast<bool>(DataKind & CGDataKind::FunctionOutlinedHashTree))
|
||||
Header.DataKind |=
|
||||
static_cast<uint32_t>(CGDataKind::FunctionOutlinedHashTree);
|
||||
|
||||
Header.OutlinedHashTreeOffset = 0;
|
||||
|
||||
// Only write up to the CGDataKind. We need to remember the offset of the
|
||||
// remaining fields to allow back-patching later.
|
||||
COS.write(Header.Magic);
|
||||
COS.write32(Header.Version);
|
||||
COS.write32(Header.DataKind);
|
||||
|
||||
// Save the location of Header.OutlinedHashTreeOffset field in \c COS.
|
||||
OutlinedHashTreeOffset = COS.tell();
|
||||
|
||||
// Reserve the space for OutlinedHashTreeOffset field.
|
||||
COS.write(0);
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error CodeGenDataWriter::writeImpl(CGDataOStream &COS) {
|
||||
if (Error E = writeHeader(COS))
|
||||
return E;
|
||||
|
||||
uint64_t OutlinedHashTreeFieldStart = COS.tell();
|
||||
if (hasOutlinedHashTree())
|
||||
HashTreeRecord.serialize(COS.OS);
|
||||
|
||||
// Back patch the offsets.
|
||||
CGDataPatchItem PatchItems[] = {
|
||||
{OutlinedHashTreeOffset, &OutlinedHashTreeFieldStart, 1}};
|
||||
COS.patch(PatchItems);
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error CodeGenDataWriter::writeHeaderText(raw_fd_ostream &OS) {
|
||||
if (hasOutlinedHashTree())
|
||||
OS << "# Outlined stable hash tree\n:outlined_hash_tree\n";
|
||||
|
||||
// TODO: Add more data types in this header
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error CodeGenDataWriter::writeText(raw_fd_ostream &OS) {
|
||||
if (Error E = writeHeaderText(OS))
|
||||
return E;
|
||||
|
||||
yaml::Output YOS(OS);
|
||||
if (hasOutlinedHashTree())
|
||||
HashTreeRecord.serializeYAML(YOS);
|
||||
|
||||
// TODO: Write more yaml cgdata in order
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
|
|
@ -12,7 +12,6 @@
|
|||
|
||||
#include "llvm/IR/LegacyPassManager.h"
|
||||
#include "llvm/ADT/MapVector.h"
|
||||
#include "llvm/Demangle/Demangle.h"
|
||||
#include "llvm/IR/DiagnosticInfo.h"
|
||||
#include "llvm/IR/IRPrintingPasses.h"
|
||||
#include "llvm/IR/LLVMContext.h"
|
||||
|
|
@ -1416,8 +1415,7 @@ bool FPPassManager::runOnFunction(Function &F) {
|
|||
|
||||
// Store name outside of loop to avoid redundant calls.
|
||||
const StringRef Name = F.getName();
|
||||
llvm::TimeTraceScope FunctionScope(
|
||||
"OptFunction", [&F]() { return demangle(F.getName().str()); });
|
||||
llvm::TimeTraceScope FunctionScope("OptFunction", Name);
|
||||
|
||||
for (unsigned Index = 0; Index < getNumContainedPasses(); ++Index) {
|
||||
FunctionPass *FP = getContainedPass(Index);
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@
|
|||
#include "llvm/CodeGen/MachineFunction.h"
|
||||
#include "llvm/CodeGen/MachineModuleInfo.h"
|
||||
#include "llvm/CodeGen/MachineVerifier.h"
|
||||
#include "llvm/Demangle/Demangle.h"
|
||||
#include "llvm/IR/Constants.h"
|
||||
#include "llvm/IR/Function.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
|
|
@ -236,12 +235,12 @@ void printIR(raw_ostream &OS, const MachineFunction *MF) {
|
|||
MF->print(OS);
|
||||
}
|
||||
|
||||
std::string getIRName(Any IR, bool demangled = false) {
|
||||
std::string getIRName(Any IR) {
|
||||
if (unwrapIR<Module>(IR))
|
||||
return "[module]";
|
||||
|
||||
if (const auto *F = unwrapIR<Function>(IR))
|
||||
return demangled ? demangle(F->getName()) : F->getName().str();
|
||||
return F->getName().str();
|
||||
|
||||
if (const auto *C = unwrapIR<LazyCallGraph::SCC>(IR))
|
||||
return C->getName();
|
||||
|
|
@ -251,7 +250,7 @@ std::string getIRName(Any IR, bool demangled = false) {
|
|||
L->getHeader()->getParent()->getName().str();
|
||||
|
||||
if (const auto *MF = unwrapIR<MachineFunction>(IR))
|
||||
return demangled ? demangle(MF->getName()) : MF->getName().str();
|
||||
return MF->getName().str();
|
||||
|
||||
llvm_unreachable("Unknown wrapped IR type");
|
||||
}
|
||||
|
|
@ -1589,7 +1588,7 @@ void TimeProfilingPassesHandler::registerCallbacks(
|
|||
}
|
||||
|
||||
void TimeProfilingPassesHandler::runBeforePass(StringRef PassID, Any IR) {
|
||||
timeTraceProfilerBegin(PassID, getIRName(IR, true));
|
||||
timeTraceProfilerBegin(PassID, getIRName(IR));
|
||||
}
|
||||
|
||||
void TimeProfilingPassesHandler::runAfterPass() { timeTraceProfilerEnd(); }
|
||||
|
|
|
|||
|
|
@ -278,7 +278,7 @@ static char nuls[10]; /* place to point scanner in event of error */
|
|||
#else
|
||||
#define DUPMAX 255
|
||||
#endif
|
||||
#define INFINITY (DUPMAX + 1)
|
||||
#define REGINFINITY (DUPMAX + 1)
|
||||
|
||||
#ifndef NDEBUG
|
||||
static int never = 0; /* for use in asserts; shuts lint up */
|
||||
|
|
@ -582,7 +582,7 @@ p_ere_exp(struct parse *p)
|
|||
count2 = p_count(p);
|
||||
REQUIRE(count <= count2, REG_BADBR);
|
||||
} else /* single number with comma */
|
||||
count2 = INFINITY;
|
||||
count2 = REGINFINITY;
|
||||
} else /* just a single number */
|
||||
count2 = count;
|
||||
repeat(p, pos, count, count2);
|
||||
|
|
@ -753,7 +753,7 @@ p_simp_re(struct parse *p,
|
|||
count2 = p_count(p);
|
||||
REQUIRE(count <= count2, REG_BADBR);
|
||||
} else /* single number with comma */
|
||||
count2 = INFINITY;
|
||||
count2 = REGINFINITY;
|
||||
} else /* just a single number */
|
||||
count2 = count;
|
||||
repeat(p, pos, count, count2);
|
||||
|
|
@ -1115,7 +1115,7 @@ repeat(struct parse *p,
|
|||
# define N 2
|
||||
# define INF 3
|
||||
# define REP(f, t) ((f)*8 + (t))
|
||||
# define MAP(n) (((n) <= 1) ? (n) : ((n) == INFINITY) ? INF : N)
|
||||
# define MAP(n) (((n) <= 1) ? (n) : ((n) == REGINFINITY) ? INF : N)
|
||||
sopno copy;
|
||||
|
||||
if (p->error != 0) /* head off possible runaway recursion */
|
||||
|
|
|
|||
|
|
@ -1292,6 +1292,13 @@ void AArch64AsmPrinter::emitGlobalAlias(const Module &M,
|
|||
StringRef ExpStr = cast<MDString>(Node->getOperand(0))->getString();
|
||||
MCSymbol *ExpSym = MMI->getContext().getOrCreateSymbol(ExpStr);
|
||||
MCSymbol *Sym = MMI->getContext().getOrCreateSymbol(GA.getName());
|
||||
|
||||
OutStreamer->beginCOFFSymbolDef(ExpSym);
|
||||
OutStreamer->emitCOFFSymbolStorageClass(COFF::IMAGE_SYM_CLASS_EXTERNAL);
|
||||
OutStreamer->emitCOFFSymbolType(COFF::IMAGE_SYM_DTYPE_FUNCTION
|
||||
<< COFF::SCT_COMPLEX_TYPE_SHIFT);
|
||||
OutStreamer->endCOFFSymbolDef();
|
||||
|
||||
OutStreamer->beginCOFFSymbolDef(Sym);
|
||||
OutStreamer->emitCOFFSymbolStorageClass(COFF::IMAGE_SYM_CLASS_EXTERNAL);
|
||||
OutStreamer->emitCOFFSymbolType(COFF::IMAGE_SYM_DTYPE_FUNCTION
|
||||
|
|
|
|||
|
|
@ -108,6 +108,10 @@ static bool atomicReadDroppedOnZero(unsigned Opcode) {
|
|||
case AArch64::LDUMINW: case AArch64::LDUMINX:
|
||||
case AArch64::LDUMINLB: case AArch64::LDUMINLH:
|
||||
case AArch64::LDUMINLW: case AArch64::LDUMINLX:
|
||||
case AArch64::SWPB: case AArch64::SWPH:
|
||||
case AArch64::SWPW: case AArch64::SWPX:
|
||||
case AArch64::SWPLB: case AArch64::SWPLH:
|
||||
case AArch64::SWPLW: case AArch64::SWPLX:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -438,6 +438,15 @@ def FeatureSVE2p1: ExtensionWithMArch<"sve2p1", "SVE2p1", "FEAT_SVE2p1",
|
|||
def FeatureB16B16 : ExtensionWithMArch<"b16b16", "B16B16", "FEAT_SVE_B16B16",
|
||||
"Enable SVE2.1 or SME2.1 non-widening BFloat16 to BFloat16 instructions", [FeatureBF16]>;
|
||||
|
||||
// FeatureSVEB16B16 and FeatureSMEB16B16 act as aliases for {FeatureB16B16}, and
|
||||
// {FeatureB16B16, FeatureSME2} respectively. This allows LLVM-20 interfacing programs
|
||||
// that use '+sve-b16b16' and '+sme-b16b16' to compile in LLVM-19.
|
||||
def FeatureSVEB16B16 : ExtensionWithMArch<"sve-b16b16", "SVEB16B16", "FEAT_SVE_B16B16",
|
||||
"Enable SVE2 non-widening and SME2 Z-targeting non-widening BFloat16 instructions", [FeatureB16B16]>;
|
||||
|
||||
def FeatureSMEB16B16 : ExtensionWithMArch<"sme-b16b16", "SMEB16B16", "FEAT_SME_B16B16",
|
||||
"Enable SME2.1 ZA-targeting non-widening BFloat16 instructions", [FeatureSME2, FeatureB16B16]>;
|
||||
|
||||
def FeatureSMEF16F16 : ExtensionWithMArch<"sme-f16f16", "SMEF16F16", "FEAT_SME_F16F16",
|
||||
"Enable SME non-widening Float16 instructions", [FeatureSME2]>;
|
||||
|
||||
|
|
@ -778,27 +787,26 @@ def HasV8_2aOps : Architecture64<8, 2, "a", "v8.2a",
|
|||
[HasV8_1aOps, FeaturePsUAO, FeaturePAN_RWV, FeatureRAS, FeatureCCPP],
|
||||
!listconcat(HasV8_1aOps.DefaultExts, [FeatureRAS])>;
|
||||
def HasV8_3aOps : Architecture64<8, 3, "a", "v8.3a",
|
||||
[HasV8_2aOps, FeatureRCPC, FeaturePAuth, FeatureJS, FeatureCCIDX,
|
||||
FeatureComplxNum],
|
||||
[HasV8_2aOps, FeatureRCPC, FeaturePAuth, FeatureJS, FeatureComplxNum],
|
||||
!listconcat(HasV8_2aOps.DefaultExts, [FeatureComplxNum, FeatureJS,
|
||||
FeaturePAuth, FeatureRCPC])>;
|
||||
FeaturePAuth, FeatureRCPC, FeatureCCIDX])>;
|
||||
def HasV8_4aOps : Architecture64<8, 4, "a", "v8.4a",
|
||||
[HasV8_3aOps, FeatureDotProd, FeatureNV, FeatureMPAM, FeatureDIT,
|
||||
FeatureTRACEV8_4, FeatureAM, FeatureSEL2, FeatureTLB_RMI, FeatureFlagM,
|
||||
FeatureRCPC_IMMO, FeatureLSE2],
|
||||
!listconcat(HasV8_3aOps.DefaultExts, [FeatureDotProd])>;
|
||||
!listconcat(HasV8_3aOps.DefaultExts, [FeatureDotProd, FeatureDIT, FeatureFlagM])>;
|
||||
def HasV8_5aOps : Architecture64<8, 5, "a", "v8.5a",
|
||||
[HasV8_4aOps, FeatureAltFPCmp, FeatureFRInt3264, FeatureSpecRestrict,
|
||||
FeatureSSBS, FeatureSB, FeaturePredRes, FeatureCacheDeepPersist,
|
||||
FeatureSB, FeaturePredRes, FeatureCacheDeepPersist,
|
||||
FeatureBranchTargetId],
|
||||
!listconcat(HasV8_4aOps.DefaultExts, [])>;
|
||||
!listconcat(HasV8_4aOps.DefaultExts, [FeaturePredRes, FeatureSSBS, FeatureBranchTargetId, FeatureSB])>;
|
||||
def HasV8_6aOps : Architecture64<8, 6, "a", "v8.6a",
|
||||
[HasV8_5aOps, FeatureAMVS, FeatureBF16, FeatureFineGrainedTraps,
|
||||
FeatureEnhancedCounterVirtualization, FeatureMatMulInt8],
|
||||
!listconcat(HasV8_5aOps.DefaultExts, [FeatureBF16, FeatureMatMulInt8])>;
|
||||
def HasV8_7aOps : Architecture64<8, 7, "a", "v8.7a",
|
||||
[HasV8_6aOps, FeatureXS, FeatureWFxT, FeatureHCX],
|
||||
!listconcat(HasV8_6aOps.DefaultExts, [])>;
|
||||
!listconcat(HasV8_6aOps.DefaultExts, [FeatureWFxT])>;
|
||||
def HasV8_8aOps : Architecture64<8, 8, "a", "v8.8a",
|
||||
[HasV8_7aOps, FeatureHBC, FeatureMOPS, FeatureNMI],
|
||||
!listconcat(HasV8_7aOps.DefaultExts, [FeatureMOPS, FeatureHBC])>;
|
||||
|
|
@ -816,7 +824,7 @@ def HasV9_1aOps : Architecture64<9, 1, "a", "v9.1a",
|
|||
!listconcat(HasV9_0aOps.DefaultExts, [FeatureBF16, FeatureMatMulInt8, FeatureRME])>;
|
||||
def HasV9_2aOps : Architecture64<9, 2, "a", "v9.2a",
|
||||
[HasV8_7aOps, HasV9_1aOps],
|
||||
!listconcat(HasV9_1aOps.DefaultExts, [FeatureMEC])>;
|
||||
!listconcat(HasV9_1aOps.DefaultExts, [FeatureMEC, FeatureWFxT])>;
|
||||
def HasV9_3aOps : Architecture64<9, 3, "a", "v9.3a",
|
||||
[HasV8_8aOps, HasV9_2aOps],
|
||||
!listconcat(HasV9_2aOps.DefaultExts, [FeatureMOPS, FeatureHBC])>;
|
||||
|
|
@ -833,7 +841,7 @@ def HasV8_0rOps : Architecture64<8, 0, "r", "v8r",
|
|||
//v8.2
|
||||
FeatureRAS, FeaturePsUAO, FeatureCCPP, FeaturePAN_RWV,
|
||||
//v8.3
|
||||
FeatureCCIDX, FeaturePAuth, FeatureRCPC,
|
||||
FeaturePAuth, FeatureRCPC,
|
||||
//v8.4
|
||||
FeatureTRACEV8_4, FeatureTLB_RMI, FeatureFlagM, FeatureDIT, FeatureSEL2,
|
||||
FeatureRCPC_IMMO,
|
||||
|
|
@ -844,7 +852,7 @@ def HasV8_0rOps : Architecture64<8, 0, "r", "v8r",
|
|||
// For v8-R, we do not enable crypto and align with GCC that enables a more
|
||||
// minimal set of optional architecture extensions.
|
||||
!listconcat(
|
||||
!listremove(HasV8_5aOps.DefaultExts, [FeatureLSE]),
|
||||
!listremove(HasV8_5aOps.DefaultExts, [FeatureBranchTargetId, FeaturePredRes]),
|
||||
[FeatureSSBS, FeatureFullFP16, FeatureFP16FML, FeatureSB]
|
||||
)>;
|
||||
|
||||
|
|
|
|||
|
|
@ -240,6 +240,7 @@
|
|||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/FormatVariadic.h"
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
|
|
@ -275,6 +276,10 @@ cl::opt<bool> EnableHomogeneousPrologEpilog(
|
|||
// Stack hazard padding size. 0 = disabled.
|
||||
static cl::opt<unsigned> StackHazardSize("aarch64-stack-hazard-size",
|
||||
cl::init(0), cl::Hidden);
|
||||
// Stack hazard size for analysis remarks. StackHazardSize takes precedence.
|
||||
static cl::opt<unsigned>
|
||||
StackHazardRemarkSize("aarch64-stack-hazard-remark-size", cl::init(0),
|
||||
cl::Hidden);
|
||||
// Whether to insert padding into non-streaming functions (for testing).
|
||||
static cl::opt<bool>
|
||||
StackHazardInNonStreaming("aarch64-stack-hazard-in-non-streaming",
|
||||
|
|
@ -2615,9 +2620,16 @@ AArch64FrameLowering::getFrameIndexReferenceFromSP(const MachineFunction &MF,
|
|||
const auto &MFI = MF.getFrameInfo();
|
||||
|
||||
int64_t ObjectOffset = MFI.getObjectOffset(FI);
|
||||
StackOffset SVEStackSize = getSVEStackSize(MF);
|
||||
|
||||
// For VLA-area objects, just emit an offset at the end of the stack frame.
|
||||
// Whilst not quite correct, these objects do live at the end of the frame and
|
||||
// so it is more useful for analysis for the offset to reflect this.
|
||||
if (MFI.isVariableSizedObjectIndex(FI)) {
|
||||
return StackOffset::getFixed(-((int64_t)MFI.getStackSize())) - SVEStackSize;
|
||||
}
|
||||
|
||||
// This is correct in the absence of any SVE stack objects.
|
||||
StackOffset SVEStackSize = getSVEStackSize(MF);
|
||||
if (!SVEStackSize)
|
||||
return StackOffset::getFixed(ObjectOffset - getOffsetOfLocalArea());
|
||||
|
||||
|
|
@ -3528,13 +3540,9 @@ bool AArch64FrameLowering::restoreCalleeSavedRegisters(
|
|||
return true;
|
||||
}
|
||||
|
||||
// Return the FrameID for a Load/Store instruction by looking at the MMO.
|
||||
static std::optional<int> getLdStFrameID(const MachineInstr &MI,
|
||||
const MachineFrameInfo &MFI) {
|
||||
if (!MI.mayLoadOrStore() || MI.getNumMemOperands() < 1)
|
||||
return std::nullopt;
|
||||
|
||||
MachineMemOperand *MMO = *MI.memoperands_begin();
|
||||
// Return the FrameID for a MMO.
|
||||
static std::optional<int> getMMOFrameID(MachineMemOperand *MMO,
|
||||
const MachineFrameInfo &MFI) {
|
||||
auto *PSV =
|
||||
dyn_cast_or_null<FixedStackPseudoSourceValue>(MMO->getPseudoValue());
|
||||
if (PSV)
|
||||
|
|
@ -3552,6 +3560,15 @@ static std::optional<int> getLdStFrameID(const MachineInstr &MI,
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
// Return the FrameID for a Load/Store instruction by looking at the first MMO.
|
||||
static std::optional<int> getLdStFrameID(const MachineInstr &MI,
|
||||
const MachineFrameInfo &MFI) {
|
||||
if (!MI.mayLoadOrStore() || MI.getNumMemOperands() < 1)
|
||||
return std::nullopt;
|
||||
|
||||
return getMMOFrameID(*MI.memoperands_begin(), MFI);
|
||||
}
|
||||
|
||||
// Check if a Hazard slot is needed for the current function, and if so create
|
||||
// one for it. The index is stored in AArch64FunctionInfo->StackHazardSlotIndex,
|
||||
// which can be used to determine if any hazard padding is needed.
|
||||
|
|
@ -5029,3 +5046,174 @@ void AArch64FrameLowering::inlineStackProbe(MachineFunction &MF,
|
|||
MI->eraseFromParent();
|
||||
}
|
||||
}
|
||||
|
||||
struct StackAccess {
|
||||
enum AccessType {
|
||||
NotAccessed = 0, // Stack object not accessed by load/store instructions.
|
||||
GPR = 1 << 0, // A general purpose register.
|
||||
PPR = 1 << 1, // A predicate register.
|
||||
FPR = 1 << 2, // A floating point/Neon/SVE register.
|
||||
};
|
||||
|
||||
int Idx;
|
||||
StackOffset Offset;
|
||||
int64_t Size;
|
||||
unsigned AccessTypes;
|
||||
|
||||
StackAccess() : Idx(0), Offset(), Size(0), AccessTypes(NotAccessed) {}
|
||||
|
||||
bool operator<(const StackAccess &Rhs) const {
|
||||
return std::make_tuple(start(), Idx) <
|
||||
std::make_tuple(Rhs.start(), Rhs.Idx);
|
||||
}
|
||||
|
||||
bool isCPU() const {
|
||||
// Predicate register load and store instructions execute on the CPU.
|
||||
return AccessTypes & (AccessType::GPR | AccessType::PPR);
|
||||
}
|
||||
bool isSME() const { return AccessTypes & AccessType::FPR; }
|
||||
bool isMixed() const { return isCPU() && isSME(); }
|
||||
|
||||
int64_t start() const { return Offset.getFixed() + Offset.getScalable(); }
|
||||
int64_t end() const { return start() + Size; }
|
||||
|
||||
std::string getTypeString() const {
|
||||
switch (AccessTypes) {
|
||||
case AccessType::FPR:
|
||||
return "FPR";
|
||||
case AccessType::PPR:
|
||||
return "PPR";
|
||||
case AccessType::GPR:
|
||||
return "GPR";
|
||||
case AccessType::NotAccessed:
|
||||
return "NA";
|
||||
default:
|
||||
return "Mixed";
|
||||
}
|
||||
}
|
||||
|
||||
void print(raw_ostream &OS) const {
|
||||
OS << getTypeString() << " stack object at [SP"
|
||||
<< (Offset.getFixed() < 0 ? "" : "+") << Offset.getFixed();
|
||||
if (Offset.getScalable())
|
||||
OS << (Offset.getScalable() < 0 ? "" : "+") << Offset.getScalable()
|
||||
<< " * vscale";
|
||||
OS << "]";
|
||||
}
|
||||
};
|
||||
|
||||
static inline raw_ostream &operator<<(raw_ostream &OS, const StackAccess &SA) {
|
||||
SA.print(OS);
|
||||
return OS;
|
||||
}
|
||||
|
||||
void AArch64FrameLowering::emitRemarks(
|
||||
const MachineFunction &MF, MachineOptimizationRemarkEmitter *ORE) const {
|
||||
|
||||
SMEAttrs Attrs(MF.getFunction());
|
||||
if (Attrs.hasNonStreamingInterfaceAndBody())
|
||||
return;
|
||||
|
||||
const uint64_t HazardSize =
|
||||
(StackHazardSize) ? StackHazardSize : StackHazardRemarkSize;
|
||||
|
||||
if (HazardSize == 0)
|
||||
return;
|
||||
|
||||
const MachineFrameInfo &MFI = MF.getFrameInfo();
|
||||
// Bail if function has no stack objects.
|
||||
if (!MFI.hasStackObjects())
|
||||
return;
|
||||
|
||||
std::vector<StackAccess> StackAccesses(MFI.getNumObjects());
|
||||
|
||||
size_t NumFPLdSt = 0;
|
||||
size_t NumNonFPLdSt = 0;
|
||||
|
||||
// Collect stack accesses via Load/Store instructions.
|
||||
for (const MachineBasicBlock &MBB : MF) {
|
||||
for (const MachineInstr &MI : MBB) {
|
||||
if (!MI.mayLoadOrStore() || MI.getNumMemOperands() < 1)
|
||||
continue;
|
||||
for (MachineMemOperand *MMO : MI.memoperands()) {
|
||||
std::optional<int> FI = getMMOFrameID(MMO, MFI);
|
||||
if (FI && !MFI.isDeadObjectIndex(*FI)) {
|
||||
int FrameIdx = *FI;
|
||||
|
||||
size_t ArrIdx = FrameIdx + MFI.getNumFixedObjects();
|
||||
if (StackAccesses[ArrIdx].AccessTypes == StackAccess::NotAccessed) {
|
||||
StackAccesses[ArrIdx].Idx = FrameIdx;
|
||||
StackAccesses[ArrIdx].Offset =
|
||||
getFrameIndexReferenceFromSP(MF, FrameIdx);
|
||||
StackAccesses[ArrIdx].Size = MFI.getObjectSize(FrameIdx);
|
||||
}
|
||||
|
||||
unsigned RegTy = StackAccess::AccessType::GPR;
|
||||
if (MFI.getStackID(FrameIdx) == TargetStackID::ScalableVector) {
|
||||
if (AArch64::PPRRegClass.contains(MI.getOperand(0).getReg()))
|
||||
RegTy = StackAccess::PPR;
|
||||
else
|
||||
RegTy = StackAccess::FPR;
|
||||
} else if (AArch64InstrInfo::isFpOrNEON(MI)) {
|
||||
RegTy = StackAccess::FPR;
|
||||
}
|
||||
|
||||
StackAccesses[ArrIdx].AccessTypes |= RegTy;
|
||||
|
||||
if (RegTy == StackAccess::FPR)
|
||||
++NumFPLdSt;
|
||||
else
|
||||
++NumNonFPLdSt;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (NumFPLdSt == 0 || NumNonFPLdSt == 0)
|
||||
return;
|
||||
|
||||
llvm::sort(StackAccesses);
|
||||
StackAccesses.erase(llvm::remove_if(StackAccesses,
|
||||
[](const StackAccess &S) {
|
||||
return S.AccessTypes ==
|
||||
StackAccess::NotAccessed;
|
||||
}),
|
||||
StackAccesses.end());
|
||||
|
||||
SmallVector<const StackAccess *> MixedObjects;
|
||||
SmallVector<std::pair<const StackAccess *, const StackAccess *>> HazardPairs;
|
||||
|
||||
if (StackAccesses.front().isMixed())
|
||||
MixedObjects.push_back(&StackAccesses.front());
|
||||
|
||||
for (auto It = StackAccesses.begin(), End = std::prev(StackAccesses.end());
|
||||
It != End; ++It) {
|
||||
const auto &First = *It;
|
||||
const auto &Second = *(It + 1);
|
||||
|
||||
if (Second.isMixed())
|
||||
MixedObjects.push_back(&Second);
|
||||
|
||||
if ((First.isSME() && Second.isCPU()) ||
|
||||
(First.isCPU() && Second.isSME())) {
|
||||
uint64_t Distance = static_cast<uint64_t>(Second.start() - First.end());
|
||||
if (Distance < HazardSize)
|
||||
HazardPairs.emplace_back(&First, &Second);
|
||||
}
|
||||
}
|
||||
|
||||
auto EmitRemark = [&](llvm::StringRef Str) {
|
||||
ORE->emit([&]() {
|
||||
auto R = MachineOptimizationRemarkAnalysis(
|
||||
"sme", "StackHazard", MF.getFunction().getSubprogram(), &MF.front());
|
||||
return R << formatv("stack hazard in '{0}': ", MF.getName()).str() << Str;
|
||||
});
|
||||
};
|
||||
|
||||
for (const auto &P : HazardPairs)
|
||||
EmitRemark(formatv("{0} is too close to {1}", *P.first, *P.second).str());
|
||||
|
||||
for (const auto *Obj : MixedObjects)
|
||||
EmitRemark(
|
||||
formatv("{0} accessed by both GP and FP instructions", *Obj).str());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,8 +13,9 @@
|
|||
#ifndef LLVM_LIB_TARGET_AARCH64_AARCH64FRAMELOWERING_H
|
||||
#define LLVM_LIB_TARGET_AARCH64_AARCH64FRAMELOWERING_H
|
||||
|
||||
#include "llvm/Support/TypeSize.h"
|
||||
#include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h"
|
||||
#include "llvm/CodeGen/TargetFrameLowering.h"
|
||||
#include "llvm/Support/TypeSize.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
|
|
@ -178,6 +179,9 @@ private:
|
|||
inlineStackProbeLoopExactMultiple(MachineBasicBlock::iterator MBBI,
|
||||
int64_t NegProbeSize,
|
||||
Register TargetReg) const;
|
||||
|
||||
void emitRemarks(const MachineFunction &MF,
|
||||
MachineOptimizationRemarkEmitter *ORE) const override;
|
||||
};
|
||||
|
||||
} // End llvm namespace
|
||||
|
|
|
|||
|
|
@ -17719,6 +17719,9 @@ static SDValue performVecReduceAddCombineWithUADDLP(SDNode *N,
|
|||
// and generate vecreduce.add(concat_vector(DOT, DOT2, ..)).
|
||||
static SDValue performVecReduceAddCombine(SDNode *N, SelectionDAG &DAG,
|
||||
const AArch64Subtarget *ST) {
|
||||
if (!ST->isNeonAvailable())
|
||||
return SDValue();
|
||||
|
||||
if (!ST->hasDotProd())
|
||||
return performVecReduceAddCombineWithUADDLP(N, DAG);
|
||||
|
||||
|
|
|
|||
|
|
@ -688,6 +688,7 @@ def ProcessorFeatures {
|
|||
FeatureMatMulInt8, FeatureBF16, FeatureAM,
|
||||
FeatureMTE, FeatureETE, FeatureSVE2BitPerm,
|
||||
FeatureFP16FML,
|
||||
FeatureCCIDX,
|
||||
FeatureSB, FeaturePAuth, FeatureSSBS, FeatureSVE, FeatureSVE2,
|
||||
FeatureComplxNum, FeatureCRC, FeatureDotProd,
|
||||
FeatureFPARMv8,FeatureFullFP16, FeatureJS, FeatureLSE,
|
||||
|
|
@ -695,6 +696,7 @@ def ProcessorFeatures {
|
|||
list<SubtargetFeature> A520 = [HasV9_2aOps, FeaturePerfMon, FeatureAM,
|
||||
FeatureMTE, FeatureETE, FeatureSVE2BitPerm,
|
||||
FeatureFP16FML,
|
||||
FeatureCCIDX,
|
||||
FeatureSB, FeatureSSBS, FeaturePAuth, FeatureFlagM, FeaturePredRes,
|
||||
FeatureSVE, FeatureSVE2, FeatureBF16, FeatureComplxNum, FeatureCRC,
|
||||
FeatureFPARMv8, FeatureFullFP16, FeatureMatMulInt8, FeatureJS,
|
||||
|
|
@ -703,6 +705,7 @@ def ProcessorFeatures {
|
|||
list<SubtargetFeature> A520AE = [HasV9_2aOps, FeaturePerfMon, FeatureAM,
|
||||
FeatureMTE, FeatureETE, FeatureSVE2BitPerm,
|
||||
FeatureFP16FML,
|
||||
FeatureCCIDX,
|
||||
FeatureSB, FeatureSSBS, FeaturePAuth, FeatureFlagM, FeaturePredRes,
|
||||
FeatureSVE, FeatureSVE2, FeatureBF16, FeatureComplxNum, FeatureCRC,
|
||||
FeatureFPARMv8, FeatureFullFP16, FeatureMatMulInt8, FeatureJS,
|
||||
|
|
@ -734,12 +737,14 @@ def ProcessorFeatures {
|
|||
FeaturePerfMon, FeatureRCPC, FeatureSPE,
|
||||
FeatureSSBS, FeatureCRC, FeatureLSE, FeatureRAS, FeatureRDM];
|
||||
list<SubtargetFeature> A710 = [HasV9_0aOps, FeatureNEON, FeaturePerfMon,
|
||||
FeatureCCIDX, FeatureSSBS,
|
||||
FeatureETE, FeatureMTE, FeatureFP16FML,
|
||||
FeatureSVE2BitPerm, FeatureBF16, FeatureMatMulInt8,
|
||||
FeaturePAuth, FeatureFlagM, FeatureSB, FeatureSVE, FeatureSVE2,
|
||||
FeatureComplxNum, FeatureCRC, FeatureDotProd, FeatureFPARMv8,
|
||||
FeatureFullFP16, FeatureJS, FeatureLSE, FeatureRAS, FeatureRCPC, FeatureRDM];
|
||||
list<SubtargetFeature> A715 = [HasV9_0aOps, FeatureNEON, FeatureMTE,
|
||||
FeatureCCIDX,
|
||||
FeatureFP16FML, FeatureSVE, FeatureTRBE,
|
||||
FeatureSVE2BitPerm, FeatureBF16, FeatureETE,
|
||||
FeaturePerfMon, FeatureMatMulInt8, FeatureSPE,
|
||||
|
|
@ -749,6 +754,7 @@ def ProcessorFeatures {
|
|||
FeatureJS, FeatureLSE, FeatureRAS,
|
||||
FeatureRCPC, FeatureRDM];
|
||||
list<SubtargetFeature> A720 = [HasV9_2aOps, FeatureMTE, FeatureFP16FML,
|
||||
FeatureCCIDX,
|
||||
FeatureTRBE, FeatureSVE2BitPerm, FeatureETE,
|
||||
FeaturePerfMon, FeatureSPE, FeatureSPE_EEF,
|
||||
FeatureSB, FeatureSSBS, FeaturePAuth, FeatureFlagM, FeaturePredRes,
|
||||
|
|
@ -757,6 +763,7 @@ def ProcessorFeatures {
|
|||
FeatureJS, FeatureLSE, FeatureNEON, FeatureRAS,
|
||||
FeatureRCPC, FeatureRDM];
|
||||
list<SubtargetFeature> A720AE = [HasV9_2aOps, FeatureMTE, FeatureFP16FML,
|
||||
FeatureCCIDX,
|
||||
FeatureTRBE, FeatureSVE2BitPerm, FeatureETE,
|
||||
FeaturePerfMon, FeatureSPE, FeatureSPE_EEF,
|
||||
FeatureSB, FeatureSSBS, FeaturePAuth, FeatureFlagM, FeaturePredRes,
|
||||
|
|
@ -765,6 +772,7 @@ def ProcessorFeatures {
|
|||
FeatureJS, FeatureLSE, FeatureNEON, FeatureRAS,
|
||||
FeatureRCPC, FeatureRDM];
|
||||
list<SubtargetFeature> A725 = [HasV9_2aOps, FeatureMTE, FeatureFP16FML,
|
||||
FeatureCCIDX,
|
||||
FeatureETE, FeaturePerfMon, FeatureSPE,
|
||||
FeatureSVE2BitPerm, FeatureSPE_EEF, FeatureTRBE,
|
||||
FeatureFlagM, FeaturePredRes, FeatureSB, FeatureSSBS,
|
||||
|
|
@ -800,6 +808,7 @@ def ProcessorFeatures {
|
|||
FeatureMatMulInt8, FeatureBF16, FeatureAM,
|
||||
FeatureMTE, FeatureETE, FeatureSVE2BitPerm,
|
||||
FeatureFP16FML,
|
||||
FeatureCCIDX,
|
||||
FeaturePAuth, FeatureSSBS, FeatureSB, FeatureSVE, FeatureSVE2, FeatureFlagM,
|
||||
FeatureComplxNum, FeatureCRC, FeatureDotProd, FeatureFPARMv8, FeatureFullFP16,
|
||||
FeatureJS, FeatureLSE, FeatureRAS, FeatureRCPC, FeatureRDM];
|
||||
|
|
@ -808,6 +817,7 @@ def ProcessorFeatures {
|
|||
FeatureSPE, FeatureBF16, FeatureMatMulInt8,
|
||||
FeatureMTE, FeatureSVE2BitPerm, FeatureFullFP16,
|
||||
FeatureFP16FML,
|
||||
FeatureCCIDX,
|
||||
FeatureSB, FeaturePAuth, FeaturePredRes, FeatureFlagM, FeatureSSBS,
|
||||
FeatureSVE2, FeatureComplxNum, FeatureCRC, FeatureFPARMv8, FeatureJS,
|
||||
FeatureLSE, FeatureRAS, FeatureRCPC, FeatureRDM, FeatureDotProd];
|
||||
|
|
@ -815,11 +825,13 @@ def ProcessorFeatures {
|
|||
FeaturePerfMon, FeatureETE, FeatureTRBE,
|
||||
FeatureSPE, FeatureMTE, FeatureSVE2BitPerm,
|
||||
FeatureFP16FML, FeatureSPE_EEF,
|
||||
FeatureCCIDX,
|
||||
FeatureSB, FeatureSSBS, FeaturePAuth, FeatureFlagM, FeaturePredRes,
|
||||
FeatureSVE, FeatureSVE2, FeatureComplxNum, FeatureCRC, FeatureDotProd,
|
||||
FeatureFPARMv8, FeatureFullFP16, FeatureMatMulInt8, FeatureJS, FeatureLSE,
|
||||
FeatureNEON, FeatureRAS, FeatureRCPC, FeatureRDM, FeatureBF16];
|
||||
list<SubtargetFeature> X925 = [HasV9_2aOps, FeatureMTE, FeatureFP16FML,
|
||||
FeatureCCIDX,
|
||||
FeatureETE, FeaturePerfMon, FeatureSPE,
|
||||
FeatureSVE2BitPerm, FeatureSPE_EEF, FeatureTRBE,
|
||||
FeatureFlagM, FeaturePredRes, FeatureSB, FeatureSSBS,
|
||||
|
|
@ -863,23 +875,26 @@ def ProcessorFeatures {
|
|||
list<SubtargetFeature> AppleA15 = [HasV8_6aOps, FeatureSHA2, FeatureAES, FeatureFPARMv8,
|
||||
FeatureNEON, FeaturePerfMon, FeatureSHA3,
|
||||
FeatureFullFP16, FeatureFP16FML,
|
||||
FeatureComplxNum, FeatureCRC, FeatureJS, FeatureLSE,
|
||||
FeaturePAuth, FeatureRAS, FeatureRCPC, FeatureRDM,
|
||||
FeatureBF16, FeatureDotProd, FeatureMatMulInt8];
|
||||
FeatureComplxNum, FeatureCRC, FeatureJS,
|
||||
FeatureLSE, FeaturePAuth,
|
||||
FeatureRAS, FeatureRCPC, FeatureRDM,
|
||||
FeatureBF16, FeatureDotProd, FeatureMatMulInt8, FeatureSSBS];
|
||||
list<SubtargetFeature> AppleA16 = [HasV8_6aOps, FeatureSHA2, FeatureAES, FeatureFPARMv8,
|
||||
FeatureNEON, FeaturePerfMon, FeatureSHA3,
|
||||
FeatureFullFP16, FeatureFP16FML,
|
||||
FeatureHCX,
|
||||
FeatureComplxNum, FeatureCRC, FeatureJS, FeatureLSE,
|
||||
FeaturePAuth, FeatureRAS, FeatureRCPC, FeatureRDM,
|
||||
FeatureBF16, FeatureDotProd, FeatureMatMulInt8];
|
||||
FeatureComplxNum, FeatureCRC, FeatureJS,
|
||||
FeatureLSE, FeaturePAuth,
|
||||
FeatureRAS, FeatureRCPC, FeatureRDM,
|
||||
FeatureBF16, FeatureDotProd, FeatureMatMulInt8, FeatureSSBS];
|
||||
list<SubtargetFeature> AppleA17 = [HasV8_6aOps, FeatureSHA2, FeatureAES, FeatureFPARMv8,
|
||||
FeatureNEON, FeaturePerfMon, FeatureSHA3,
|
||||
FeatureFullFP16, FeatureFP16FML,
|
||||
FeatureHCX,
|
||||
FeatureComplxNum, FeatureCRC, FeatureJS, FeatureLSE,
|
||||
FeaturePAuth, FeatureRAS, FeatureRCPC, FeatureRDM,
|
||||
FeatureBF16, FeatureDotProd, FeatureMatMulInt8];
|
||||
FeatureComplxNum, FeatureCRC, FeatureJS,
|
||||
FeatureLSE, FeaturePAuth,
|
||||
FeatureRAS, FeatureRCPC, FeatureRDM,
|
||||
FeatureBF16, FeatureDotProd, FeatureMatMulInt8, FeatureSSBS];
|
||||
list<SubtargetFeature> AppleM4 = [HasV9_2aOps, FeatureSHA2, FeatureFPARMv8,
|
||||
FeatureNEON, FeaturePerfMon, FeatureSHA3,
|
||||
FeatureFullFP16, FeatureFP16FML,
|
||||
|
|
@ -909,6 +924,7 @@ def ProcessorFeatures {
|
|||
FeatureMatMulInt8, FeatureMTE, FeatureSVE2,
|
||||
FeatureSVE2BitPerm, FeatureTRBE,
|
||||
FeaturePerfMon,
|
||||
FeatureCCIDX,
|
||||
FeatureDotProd, FeatureFullFP16, FeatureSB, FeatureSSBS, FeatureSVE,
|
||||
FeatureComplxNum, FeatureCRC, FeatureFPARMv8, FeatureJS, FeatureLSE,
|
||||
FeatureNEON, FeaturePAuth, FeatureRAS, FeatureRCPC, FeatureRDM];
|
||||
|
|
@ -916,6 +932,7 @@ def ProcessorFeatures {
|
|||
FeatureFullFP16, FeatureMTE, FeaturePerfMon,
|
||||
FeatureRandGen, FeatureSPE, FeatureSPE_EEF,
|
||||
FeatureSVE2BitPerm,
|
||||
FeatureCCIDX,
|
||||
FeatureSSBS, FeatureSB, FeaturePredRes, FeaturePAuth, FeatureFlagM,
|
||||
FeatureSVE, FeatureSVE2, FeatureBF16, FeatureComplxNum,
|
||||
FeatureCRC, FeatureDotProd, FeatureFPARMv8, FeatureMatMulInt8,
|
||||
|
|
@ -926,6 +943,7 @@ def ProcessorFeatures {
|
|||
FeatureFullFP16, FeatureMatMulInt8, FeatureNEON,
|
||||
FeaturePerfMon, FeatureRandGen, FeatureSPE,
|
||||
FeatureSSBS, FeatureSVE,
|
||||
FeatureCCIDX,
|
||||
FeatureSHA3, FeatureSM4, FeatureDotProd, FeatureComplxNum,
|
||||
FeatureCRC, FeatureJS, FeatureLSE, FeaturePAuth, FeatureRAS,
|
||||
FeatureRCPC, FeatureRDM];
|
||||
|
|
@ -934,6 +952,7 @@ def ProcessorFeatures {
|
|||
FeatureFullFP16, FeatureMatMulInt8, FeatureNEON,
|
||||
FeaturePerfMon, FeatureRandGen, FeatureSPE,
|
||||
FeatureSSBS, FeatureSVE,
|
||||
FeatureCCIDX,
|
||||
FeatureSHA3, FeatureSM4, FeatureDotProd, FeatureComplxNum,
|
||||
FeatureCRC, FeatureJS, FeatureLSE, FeaturePAuth, FeatureRAS,
|
||||
FeatureRCPC, FeatureRDM];
|
||||
|
|
@ -941,12 +960,14 @@ def ProcessorFeatures {
|
|||
FeaturePerfMon, FeatureETE, FeatureMatMulInt8,
|
||||
FeatureNEON, FeatureSVE2BitPerm, FeatureFP16FML,
|
||||
FeatureMTE, FeatureRandGen,
|
||||
FeatureCCIDX,
|
||||
FeatureSVE, FeatureSVE2, FeatureSSBS, FeatureFullFP16, FeatureDotProd,
|
||||
FeatureComplxNum, FeatureCRC, FeatureFPARMv8, FeatureJS, FeatureLSE,
|
||||
FeaturePAuth, FeatureRAS, FeatureRCPC, FeatureRDM];
|
||||
list<SubtargetFeature> NeoverseV3 = [HasV9_2aOps, FeatureETE, FeatureFP16FML,
|
||||
FeatureFullFP16, FeatureLS64, FeatureMTE,
|
||||
FeaturePerfMon, FeatureRandGen, FeatureSPE,
|
||||
FeatureCCIDX,
|
||||
FeatureSPE_EEF, FeatureSVE2BitPerm, FeatureBRBE,
|
||||
FeatureSSBS, FeatureSB, FeaturePredRes, FeaturePAuth, FeatureFlagM,
|
||||
FeatureSVE, FeatureSVE2, FeatureBF16, FeatureComplxNum, FeatureCRC,
|
||||
|
|
@ -957,12 +978,14 @@ def ProcessorFeatures {
|
|||
FeaturePerfMon, FeatureRandGen, FeatureSPE,
|
||||
FeatureSPE_EEF, FeatureSVE2BitPerm, FeatureBRBE,
|
||||
FeatureSSBS, FeatureSB, FeaturePredRes, FeaturePAuth, FeatureFlagM,
|
||||
FeatureCCIDX,
|
||||
FeatureSVE, FeatureSVE2, FeatureBF16, FeatureComplxNum, FeatureCRC,
|
||||
FeatureDotProd, FeatureFPARMv8, FeatureMatMulInt8, FeatureJS,
|
||||
FeatureLSE, FeatureNEON, FeatureRAS, FeatureRCPC, FeatureRDM,
|
||||
FeatureRME];
|
||||
list<SubtargetFeature> Saphira = [HasV8_4aOps, FeatureSHA2, FeatureAES, FeatureFPARMv8,
|
||||
FeatureNEON, FeatureSPE, FeaturePerfMon, FeatureCRC,
|
||||
FeatureCCIDX,
|
||||
FeatureLSE, FeatureRDM, FeatureRAS, FeatureRCPC];
|
||||
list<SubtargetFeature> ThunderX = [HasV8_0aOps, FeatureCRC, FeatureSHA2, FeatureAES,
|
||||
FeatureFPARMv8, FeaturePerfMon, FeatureNEON];
|
||||
|
|
@ -971,6 +994,7 @@ def ProcessorFeatures {
|
|||
FeatureRDM];
|
||||
list<SubtargetFeature> ThunderX3T110 = [HasV8_3aOps, FeatureCRC, FeatureSHA2, FeatureAES,
|
||||
FeatureFPARMv8, FeatureNEON, FeatureLSE,
|
||||
FeatureCCIDX,
|
||||
FeaturePAuth, FeaturePerfMon, FeatureComplxNum,
|
||||
FeatureJS, FeatureRAS, FeatureRCPC, FeatureRDM];
|
||||
list<SubtargetFeature> TSV110 = [HasV8_2aOps, FeatureSHA2, FeatureAES, FeatureFPARMv8,
|
||||
|
|
@ -983,6 +1007,7 @@ def ProcessorFeatures {
|
|||
FeatureSHA2, FeatureSHA3, FeatureAES,
|
||||
FeatureFullFP16, FeatureBF16, FeatureComplxNum, FeatureCRC,
|
||||
FeatureDotProd, FeatureFPARMv8, FeatureMatMulInt8, FeatureJS,
|
||||
FeatureCCIDX,
|
||||
FeatureLSE, FeaturePAuth, FeatureRAS, FeatureRCPC, FeatureRDM];
|
||||
list<SubtargetFeature> Ampere1A = [HasV8_6aOps, FeatureNEON, FeaturePerfMon,
|
||||
FeatureMTE, FeatureSSBS, FeatureRandGen,
|
||||
|
|
@ -991,6 +1016,7 @@ def ProcessorFeatures {
|
|||
FeatureFullFP16, FeatureBF16, FeatureComplxNum,
|
||||
FeatureCRC, FeatureDotProd, FeatureFPARMv8, FeatureMatMulInt8,
|
||||
FeatureJS, FeatureLSE, FeaturePAuth, FeatureRAS, FeatureRCPC,
|
||||
FeatureCCIDX,
|
||||
FeatureRDM];
|
||||
list<SubtargetFeature> Ampere1B = [HasV8_7aOps, FeatureNEON, FeaturePerfMon,
|
||||
FeatureMTE, FeatureSSBS, FeatureRandGen,
|
||||
|
|
@ -999,6 +1025,7 @@ def ProcessorFeatures {
|
|||
FeatureWFxT, FeatureFullFP16, FeatureBF16, FeatureComplxNum,
|
||||
FeatureCRC, FeatureDotProd, FeatureFPARMv8, FeatureMatMulInt8,
|
||||
FeatureJS, FeatureLSE, FeaturePAuth, FeatureRAS, FeatureRCPC,
|
||||
FeatureCCIDX,
|
||||
FeatureRDM];
|
||||
|
||||
list<SubtargetFeature> Oryon = [HasV8_6aOps, FeatureNEON, FeaturePerfMon,
|
||||
|
|
@ -1007,6 +1034,7 @@ def ProcessorFeatures {
|
|||
FeatureSHA3, FeatureAES,
|
||||
FeatureSPE, FeatureBF16, FeatureComplxNum, FeatureCRC,
|
||||
FeatureDotProd, FeatureFPARMv8, FeatureMatMulInt8,
|
||||
FeatureSSBS, FeatureCCIDX,
|
||||
FeatureJS, FeatureLSE, FeatureRAS, FeatureRCPC, FeatureRDM];
|
||||
|
||||
// ETE and TRBE are future architecture extensions. We temporarily enable them
|
||||
|
|
|
|||
|
|
@ -254,7 +254,8 @@ bool AArch64TTIImpl::areInlineCompatible(const Function *Caller,
|
|||
return false;
|
||||
|
||||
if (CallerAttrs.requiresLazySave(CalleeAttrs) ||
|
||||
CallerAttrs.requiresSMChange(CalleeAttrs)) {
|
||||
CallerAttrs.requiresSMChange(CalleeAttrs) ||
|
||||
CallerAttrs.requiresPreservingZT0(CalleeAttrs)) {
|
||||
if (hasPossibleIncompatibleOps(Callee))
|
||||
return false;
|
||||
}
|
||||
|
|
@ -540,7 +541,15 @@ static InstructionCost getHistogramCost(const IntrinsicCostAttributes &ICA) {
|
|||
InstructionCost
|
||||
AArch64TTIImpl::getIntrinsicInstrCost(const IntrinsicCostAttributes &ICA,
|
||||
TTI::TargetCostKind CostKind) {
|
||||
// The code-generator is currently not able to handle scalable vectors
|
||||
// of <vscale x 1 x eltty> yet, so return an invalid cost to avoid selecting
|
||||
// it. This change will be removed when code-generation for these types is
|
||||
// sufficiently reliable.
|
||||
auto *RetTy = ICA.getReturnType();
|
||||
if (auto *VTy = dyn_cast<ScalableVectorType>(RetTy))
|
||||
if (VTy->getElementCount() == ElementCount::getScalable(1))
|
||||
return InstructionCost::getInvalid();
|
||||
|
||||
switch (ICA.getID()) {
|
||||
case Intrinsic::experimental_vector_histogram_add:
|
||||
if (!ST->hasSVE2())
|
||||
|
|
@ -2295,6 +2304,11 @@ std::optional<Value *> AArch64TTIImpl::simplifyDemandedVectorEltsIntrinsic(
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
bool AArch64TTIImpl::enableScalableVectorization() const {
|
||||
return ST->isSVEAvailable() || (ST->isSVEorStreamingSVEAvailable() &&
|
||||
EnableScalableAutovecInStreamingMode);
|
||||
}
|
||||
|
||||
TypeSize
|
||||
AArch64TTIImpl::getRegisterBitWidth(TargetTransformInfo::RegisterKind K) const {
|
||||
switch (K) {
|
||||
|
|
@ -3018,6 +3032,14 @@ InstructionCost AArch64TTIImpl::getArithmeticInstrCost(
|
|||
ArrayRef<const Value *> Args,
|
||||
const Instruction *CxtI) {
|
||||
|
||||
// The code-generator is currently not able to handle scalable vectors
|
||||
// of <vscale x 1 x eltty> yet, so return an invalid cost to avoid selecting
|
||||
// it. This change will be removed when code-generation for these types is
|
||||
// sufficiently reliable.
|
||||
if (auto *VTy = dyn_cast<ScalableVectorType>(Ty))
|
||||
if (VTy->getElementCount() == ElementCount::getScalable(1))
|
||||
return InstructionCost::getInvalid();
|
||||
|
||||
// TODO: Handle more cost kinds.
|
||||
if (CostKind != TTI::TCK_RecipThroughput)
|
||||
return BaseT::getArithmeticInstrCost(Opcode, Ty, CostKind, Op1Info,
|
||||
|
|
@ -3792,6 +3814,14 @@ InstructionCost
|
|||
AArch64TTIImpl::getMinMaxReductionCost(Intrinsic::ID IID, VectorType *Ty,
|
||||
FastMathFlags FMF,
|
||||
TTI::TargetCostKind CostKind) {
|
||||
// The code-generator is currently not able to handle scalable vectors
|
||||
// of <vscale x 1 x eltty> yet, so return an invalid cost to avoid selecting
|
||||
// it. This change will be removed when code-generation for these types is
|
||||
// sufficiently reliable.
|
||||
if (auto *VTy = dyn_cast<ScalableVectorType>(Ty))
|
||||
if (VTy->getElementCount() == ElementCount::getScalable(1))
|
||||
return InstructionCost::getInvalid();
|
||||
|
||||
std::pair<InstructionCost, MVT> LT = getTypeLegalizationCost(Ty);
|
||||
|
||||
if (LT.second.getScalarType() == MVT::f16 && !ST->hasFullFP16())
|
||||
|
|
@ -3836,6 +3866,14 @@ InstructionCost
|
|||
AArch64TTIImpl::getArithmeticReductionCost(unsigned Opcode, VectorType *ValTy,
|
||||
std::optional<FastMathFlags> FMF,
|
||||
TTI::TargetCostKind CostKind) {
|
||||
// The code-generator is currently not able to handle scalable vectors
|
||||
// of <vscale x 1 x eltty> yet, so return an invalid cost to avoid selecting
|
||||
// it. This change will be removed when code-generation for these types is
|
||||
// sufficiently reliable.
|
||||
if (auto *VTy = dyn_cast<ScalableVectorType>(ValTy))
|
||||
if (VTy->getElementCount() == ElementCount::getScalable(1))
|
||||
return InstructionCost::getInvalid();
|
||||
|
||||
if (TTI::requiresOrderedReduction(FMF)) {
|
||||
if (auto *FixedVTy = dyn_cast<FixedVectorType>(ValTy)) {
|
||||
InstructionCost BaseCost =
|
||||
|
|
|
|||
|
|
@ -381,7 +381,7 @@ public:
|
|||
return ST->isSVEorStreamingSVEAvailable();
|
||||
}
|
||||
|
||||
bool enableScalableVectorization() const { return ST->isSVEAvailable(); }
|
||||
bool enableScalableVectorization() const;
|
||||
|
||||
bool isLegalToVectorizeReduction(const RecurrenceDescriptor &RdxDesc,
|
||||
ElementCount VF) const;
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue