8 changes: 5 additions & 3 deletions clang/include/clang/Basic/DiagnosticGroups.td
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ def DeprecatedWritableStr : DiagGroup<"deprecated-writable-strings",
[CXX11CompatDeprecatedWritableStr]>;
def DeprecatedPragma : DiagGroup<"deprecated-pragma">;
def DeprecatedType : DiagGroup<"deprecated-type">;
def DeprecatedMissingCommaVariadicParam : DiagGroup<"deprecated-missing-comma-variadic-parameter">;
// FIXME: Why is DeprecatedImplementations not in this group?
def Deprecated : DiagGroup<"deprecated", [DeprecatedAnonEnumEnumConversion,
DeprecatedArrayCompare,
Expand All @@ -235,7 +236,8 @@ def Deprecated : DiagGroup<"deprecated", [DeprecatedAnonEnumEnumConversion,
DeprecatedType,
DeprecatedVolatile,
DeprecatedWritableStr,
DeprecatedRedundantConstexprStaticDef
DeprecatedRedundantConstexprStaticDef,
DeprecatedMissingCommaVariadicParam
]>,
DiagCategory<"Deprecations">;

Expand Down Expand Up @@ -683,7 +685,8 @@ def SizeofArrayDecay : DiagGroup<"sizeof-array-decay">;
def SizeofPointerMemaccess : DiagGroup<"sizeof-pointer-memaccess">;
def MemsetTransposedArgs : DiagGroup<"memset-transposed-args">;
def DynamicClassMemaccess : DiagGroup<"dynamic-class-memaccess">;
def NonTrivialMemaccess : DiagGroup<"nontrivial-memaccess">;
def NonTrivialMemcall : DiagGroup<"nontrivial-memcall">;
def NonTrivialMemaccess : DiagGroup<"nontrivial-memaccess", [NonTrivialMemcall]>;
def SuspiciousBzero : DiagGroup<"suspicious-bzero">;
def SuspiciousMemaccess : DiagGroup<"suspicious-memaccess",
[SizeofPointerMemaccess, DynamicClassMemaccess,
Expand Down Expand Up @@ -1589,4 +1592,3 @@ def ExplicitSpecializationStorageClass : DiagGroup<"explicit-specialization-stor

// A warning for options that enable a feature that is not yet complete
def ExperimentalOption : DiagGroup<"experimental-option">;

3 changes: 3 additions & 0 deletions clang/include/clang/Basic/DiagnosticParseKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,9 @@ def err_function_scope_depth_exceeded : Error<
"function scope depth exceeded maximum of %0">, DefaultFatal;
def err_missing_comma_before_ellipsis : Error<
"C requires a comma prior to the ellipsis in a variadic function type">;
def warn_deprecated_missing_comma_before_ellipsis : Warning<
"declaration of a variadic function without a comma before '...' is deprecated">,
InGroup<DeprecatedMissingCommaVariadicParam>;
def err_unexpected_typedef_ident : Error<
"unexpected type name %0: expected identifier">;
def warn_cxx98_compat_decltype : Warning<
Expand Down
29 changes: 20 additions & 9 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -798,7 +798,7 @@ def warn_cstruct_memaccess : Warning<
def warn_cxxstruct_memaccess : Warning<
"first argument in call to "
"%0 is a pointer to non-trivially copyable type %1">,
InGroup<NonTrivialMemaccess>;
InGroup<NonTrivialMemcall>;
def note_nontrivial_field : Note<
"field is non-trivial to %select{copy|default-initialize}0">;
def err_non_trivial_c_union_in_invalid_context : Error<
Expand Down Expand Up @@ -5445,6 +5445,10 @@ def note_dependent_function_template_spec_discard_reason : Note<
"candidate ignored: %select{not a function template|"
"not a member of the enclosing %select{class template|"
"namespace; did you mean to explicitly qualify the specialization?}1}0">;
def warn_invalid_specialization : Warning<
"%0 cannot be specialized%select{|: %2}1">,
DefaultError, InGroup<DiagGroup<"invalid-specialization">>;
def note_marked_here : Note<"marked %0 here">;

// C++ class template specializations and out-of-line definitions
def err_template_spec_needs_header : Error<
Expand Down Expand Up @@ -6270,7 +6274,7 @@ def err_typecheck_invalid_restrict_invalid_pointee : Error<
def ext_typecheck_zero_array_size : Extension<
"zero size arrays are an extension">, InGroup<ZeroLengthArray>;
def err_typecheck_zero_array_size : Error<
"zero-length arrays are not permitted in %select{C++|SYCL device code}0">;
"zero-length arrays are not permitted in %select{C++|SYCL device code|HIP device code}0">;
def err_array_size_non_int : Error<"size of array has non-integer type %0">;
def err_init_element_not_constant : Error<
"initializer element is not a compile-time constant">;
Expand Down Expand Up @@ -6417,7 +6421,7 @@ def warn_signed_bitfield_enum_conversion : Warning<
"enumerators of %1">,
InGroup<BitFieldEnumConversion>, DefaultIgnore;
def note_change_bitfield_sign : Note<
"consider making the bitfield type %select{unsigned|signed}0">;
"consider making the bit-field type %select{unsigned|signed}0">;

def warn_missing_braces : Warning<
"suggest braces around initialization of subobject">,
Expand Down Expand Up @@ -6670,14 +6674,15 @@ def warn_counted_by_attr_elt_type_unknown_size :
// __builtin_counted_by_ref diagnostics:
def err_builtin_counted_by_ref_must_be_flex_array_member : Error<
"'__builtin_counted_by_ref' argument must reference a flexible array member">;
def err_builtin_counted_by_ref_has_side_effects : Error<
"'__builtin_counted_by_ref' argument cannot have side-effects">;

def err_builtin_counted_by_ref_cannot_leak_reference : Error<
"value returned by '__builtin_counted_by_ref' cannot be assigned to a "
"variable, have its address taken, or passed into or returned from a function">;
def err_builtin_counted_by_ref_invalid_lhs_use : Error<
"value returned by '__builtin_counted_by_ref' cannot be %select{assigned to a "
"variable|passed into a function|returned from a function}0">;
def err_builtin_counted_by_ref_invalid_use : Error<
"value returned by '__builtin_counted_by_ref' cannot be used in "
"%select{an array subscript|a binary}0 expression">;
def err_builtin_counted_by_ref_has_side_effects : Error<
"'__builtin_counted_by_ref' argument cannot have side-effects">;

let CategoryName = "ARC Semantic Issue" in {

Expand Down Expand Up @@ -7287,6 +7292,8 @@ def err_typecheck_illegal_increment_decrement : Error<
"cannot %select{decrement|increment}1 value of type %0">;
def err_typecheck_expect_int : Error<
"used type %0 where integer is required">;
def err_typecheck_expect_hlsl_resource : Error<
"used type %0 where __hlsl_resource_t is required">;
def err_typecheck_arithmetic_incomplete_or_sizeless_type : Error<
"arithmetic on a pointer to %select{an incomplete|sizeless}0 type %1">;
def err_typecheck_pointer_arith_function_type : Error<
Expand Down Expand Up @@ -12528,6 +12535,10 @@ def warn_attr_min_eq_max: Warning<

def err_hlsl_attribute_number_arguments_insufficient_shader_model: Error<
"attribute %0 with %1 arguments requires shader model %2 or greater">;
def err_hlsl_expect_arg_const_int_one_or_neg_one: Error<
"argument %0 must be constant integer 1 or -1">;
def err_invalid_hlsl_resource_type: Error<
"invalid __hlsl_resource_t type attributes">;

// Layout randomization diagnostics.
def err_non_designated_init_used : Error<
Expand Down Expand Up @@ -12781,5 +12792,5 @@ def err_acc_loop_not_monotonic

// AMDGCN builtins diagnostics
def err_amdgcn_global_load_lds_size_invalid_value : Error<"invalid size value">;
def note_amdgcn_global_load_lds_size_valid_value : Note<"size must be 1, 2, or 4">;
def note_amdgcn_global_load_lds_size_valid_value : Note<"size must be %select{1, 2, or 4|1, 2, 4, 12 or 16}0">;
} // end of sema component.
1 change: 1 addition & 0 deletions clang/include/clang/Basic/TargetBuiltins.h
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,7 @@ namespace clang {
bool isTupleSet() const { return Flags & IsTupleSet; }
bool isReadZA() const { return Flags & IsReadZA; }
bool isWriteZA() const { return Flags & IsWriteZA; }
bool setsFPMR() const { return Flags & SetsFPMR; }
bool isReductionQV() const { return Flags & IsReductionQV; }
uint64_t getBits() const { return Flags; }
bool isFlagSet(uint64_t Flag) const { return Flags & Flag; }
Expand Down
6 changes: 1 addition & 5 deletions clang/include/clang/Basic/TargetInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -1525,14 +1525,10 @@ class TargetInfo : public TransferrableTargetInfo,

// Return the target-specific priority for features/cpus/vendors so
// that they can be properly sorted for checking.
virtual unsigned multiVersionSortPriority(StringRef Name) const {
virtual unsigned getFMVPriority(ArrayRef<StringRef> Features) const {
return 0;
}

// Return the target-specific cost for feature
// that taken into account in priority sorting.
virtual unsigned multiVersionFeatureCost() const { return 0; }

// Validate the contents of the __builtin_cpu_is(const char*)
// argument.
virtual bool validateCpuIs(StringRef Name) const { return false; }
Expand Down
12 changes: 7 additions & 5 deletions clang/include/clang/Basic/arm_sve.td
Original file line number Diff line number Diff line change
Expand Up @@ -2286,7 +2286,7 @@ let SVETargetGuard = "sve2p1", SMETargetGuard = InvalidMode in {
def SVTBLQ : SInst<"svtblq[_{d}]", "ddu", "cUcsUsiUilUlbhfd", MergeNone, "aarch64_sve_tblq">;
def SVTBXQ : SInst<"svtbxq[_{d}]", "dddu", "cUcsUsiUilUlbhfd", MergeNone, "aarch64_sve_tbxq">;
// EXTQ
def EXTQ : SInst<"svextq[_{d}]", "dddk", "cUcsUsiUilUlbhfd", MergeNone, "aarch64_sve_extq", [], [ImmCheck<2, ImmCheck0_15>]>;
def EXTQ : SInst<"svextq[_{d}]", "dddk", "cUcsUsiUilUlbhfd", MergeNone, "aarch64_sve_extq", [], [ImmCheck<2, ImmCheckLaneIndex, 0>]>;

// PMOV
// Move to Pred
Expand Down Expand Up @@ -2422,14 +2422,16 @@ let SVETargetGuard = InvalidMode, SMETargetGuard = "sme2" in {
def SVUUNPK_X4 : SInst<"svunpk_{d}[_{3}_x4]", "42.h", "UsUiUl", MergeNone, "aarch64_sve_uunpk_x4", [IsStreaming], []>;
}

//
// Multi-vector scaling
//
let SVETargetGuard = InvalidMode, SMETargetGuard = "sme2,fp8" in {
let SVETargetGuard = InvalidMode, SMETargetGuard = "sme2,fp8" in {
// Multi-vector scaling
def FSCALE_SINGLE_X2 : Inst<"svscale[_single_{d}_x2]", "22x", "fhd", MergeNone, "aarch64_sme_fp8_scale_single_x2", [IsStreaming],[]>;
def FSCALE_SINGLE_X4 : Inst<"svscale[_single_{d}_x4]", "44x", "fhd", MergeNone, "aarch64_sme_fp8_scale_single_x4", [IsStreaming],[]>;
def FSCALE_X2 : Inst<"svscale[_{d}_x2]", "222.x", "fhd", MergeNone, "aarch64_sme_fp8_scale_x2", [IsStreaming],[]>;
def FSCALE_X4 : Inst<"svscale[_{d}_x4]", "444.x", "fhd", MergeNone, "aarch64_sme_fp8_scale_x4", [IsStreaming],[]>;

// Convert from FP8 to deinterleaved half-precision/BFloat16 multi-vector
def SVF1CVTL : Inst<"svcvtl1_{d}[_mf8]_x2_fpm", "2~>", "bh", MergeNone, "aarch64_sve_fp8_cvtl1_x2", [IsStreaming, SetsFPMR], []>;
def SVF2CVTL : Inst<"svcvtl2_{d}[_mf8]_x2_fpm", "2~>", "bh", MergeNone, "aarch64_sve_fp8_cvtl2_x2", [IsStreaming, SetsFPMR], []>;
}

let SVETargetGuard = "sve2p1", SMETargetGuard = "sme2" in {
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Basic/arm_sve_sme_incl.td
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ include "arm_immcheck_incl.td"
// l: int64_t
// m: uint32_t
// n: uint64_t
// >: fpm_t

// [: svuint8_t
// t: svint32_t
Expand All @@ -103,6 +104,7 @@ include "arm_immcheck_incl.td"
// M: svfloat32_t
// N: svfloat64_t
// $: svbfloat16_t
// ~: svmfloat8_t

// J: Prefetch type (sv_prfop)

Expand Down Expand Up @@ -235,6 +237,7 @@ def IsInOutZA : FlagType<0x200000000000>;
def IsInZT0 : FlagType<0x400000000000>;
def IsOutZT0 : FlagType<0x800000000000>;
def IsInOutZT0 : FlagType<0x1000000000000>;
def SetsFPMR : FlagType<0x2000000000000>;

defvar InvalidMode = "";

Expand Down
10 changes: 9 additions & 1 deletion clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -1736,7 +1736,7 @@ def fno_profile_sample_use : Flag<["-"], "fno-profile-sample-use">, Group<f_Grou
Visibility<[ClangOption, CLOption]>;
def fprofile_sample_use_EQ : Joined<["-"], "fprofile-sample-use=">,
Group<f_Group>,
Visibility<[ClangOption, CC1Option]>,
Visibility<[ClangOption, CLOption, CC1Option]>,
HelpText<"Enable sample-based profile guided optimizations">,
MarshallingInfoString<CodeGenOpts<"SampleProfileFile">>;
def fprofile_sample_accurate : Flag<["-"], "fprofile-sample-accurate">,
Expand Down Expand Up @@ -5413,10 +5413,18 @@ def mlam_bh : Flag<["-"], "mlam-bh">, Group<m_loongarch_Features_Group>,
HelpText<"Enable amswap[_db].{b/h} and amadd[_db].{b/h}">;
def mno_lam_bh : Flag<["-"], "mno-lam-bh">, Group<m_loongarch_Features_Group>,
HelpText<"Disable amswap[_db].{b/h} and amadd[_db].{b/h}">;
def mlamcas : Flag<["-"], "mlamcas">, Group<m_loongarch_Features_Group>,
HelpText<"Enable amcas[_db].{b/h/w/d}">;
def mno_lamcas : Flag<["-"], "mno-lamcas">, Group<m_loongarch_Features_Group>,
HelpText<"Disable amcas[_db].{b/h/w/d}">;
def mld_seq_sa : Flag<["-"], "mld-seq-sa">, Group<m_loongarch_Features_Group>,
HelpText<"Do not generate load-load barrier instructions (dbar 0x700)">;
def mno_ld_seq_sa : Flag<["-"], "mno-ld-seq-sa">, Group<m_loongarch_Features_Group>,
HelpText<"Generate load-load barrier instructions (dbar 0x700)">;
def mdiv32 : Flag<["-"], "mdiv32">, Group<m_loongarch_Features_Group>,
HelpText<"Use div.w[u] and mod.w[u] instructions with input not sign-extended.">;
def mno_div32 : Flag<["-"], "mno-div32">, Group<m_loongarch_Features_Group>,
HelpText<"Do not use div.w[u] and mod.w[u] instructions with input not sign-extended.">;
def mannotate_tablejump : Flag<["-"], "mannotate-tablejump">, Group<m_loongarch_Features_Group>,
HelpText<"Enable annotate table jump instruction to correlate it with the jump table.">;
def mno_annotate_tablejump : Flag<["-"], "mno-annotate-tablejump">, Group<m_loongarch_Features_Group>,
Expand Down
39 changes: 19 additions & 20 deletions clang/include/clang/Format/Format.h
Original file line number Diff line number Diff line change
Expand Up @@ -2506,9 +2506,9 @@ struct FormatStyle {
/// lists.
///
/// Important differences:
/// - No spaces inside the braced list.
/// - No line break before the closing brace.
/// - Indentation with the continuation indent, not with the block indent.
/// * No spaces inside the braced list.
/// * No line break before the closing brace.
/// * Indentation with the continuation indent, not with the block indent.
///
/// Fundamentally, C++11 braced lists are formatted exactly like function
/// calls would be formatted in their place. If the braced list follows a name
Expand Down Expand Up @@ -3742,19 +3742,19 @@ struct FormatStyle {
QualifierAlignmentStyle QualifierAlignment;

/// The order in which the qualifiers appear.
/// Order is an array that can contain any of the following:
/// The order is an array that can contain any of the following:
///
/// * const
/// * inline
/// * static
/// * friend
/// * constexpr
/// * volatile
/// * restrict
/// * type
/// * ``const``
/// * ``inline``
/// * ``static``
/// * ``friend``
/// * ``constexpr``
/// * ``volatile``
/// * ``restrict``
/// * ``type``
///
/// \note
/// It **must** contain ``type``.
/// It must contain ``type``.
/// \endnote
///
/// Items to the left of ``type`` will be placed to the left of the type and
Expand Down Expand Up @@ -5449,10 +5449,10 @@ formatReplacements(StringRef Code, const tooling::Replacements &Replaces,
/// cleaning up the code after that on success; otherwise, return an llvm::Error
/// carrying llvm::StringError.
/// This also supports inserting/deleting C++ #include directives:
/// - If a replacement has offset UINT_MAX, length 0, and a replacement text
/// * If a replacement has offset UINT_MAX, length 0, and a replacement text
/// that is an #include directive, this will insert the #include into the
/// correct block in the \p Code.
/// - If a replacement has offset UINT_MAX, length 1, and a replacement text
/// * If a replacement has offset UINT_MAX, length 1, and a replacement text
/// that is the name of the header to be removed, the header will be removed
/// from \p Code if it exists.
/// The include manipulation is done via ``tooling::HeaderInclude``, see its
Expand Down Expand Up @@ -5558,13 +5558,12 @@ extern const char *DefaultFallbackStyle;
///
/// ``StyleName`` can take several forms:
/// * "{<key>: <value>, ...}" - Set specic style parameters.
/// * "<style name>" - One of the style names supported by
/// getPredefinedStyle().
/// * "<style name>" - One of the style names supported by getPredefinedStyle().
/// * "file" - Load style configuration from a file called ``.clang-format``
/// located in one of the parent directories of ``FileName`` or the current
/// directory if ``FileName`` is empty.
/// located in one of the parent directories of ``FileName`` or the current
/// directory if ``FileName`` is empty.
/// * "file:<format_file_path>" to explicitly specify the configuration file to
/// use.
/// use.
///
/// \param[in] StyleName Style name to interpret according to the description
/// above.
Expand Down
11 changes: 11 additions & 0 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -2524,6 +2524,17 @@ class Sema final : public SemaBase {

bool BuiltinNonDeterministicValue(CallExpr *TheCall);

enum BuiltinCountedByRefKind {
AssignmentKind,
InitializerKind,
FunctionArgKind,
ReturnArgKind,
ArraySubscriptKind,
BinaryExprKind,
};

bool CheckInvalidBuiltinCountedByRef(const Expr *E,
BuiltinCountedByRefKind K);
bool BuiltinCountedByRef(CallExpr *TheCall);

// Matrix builtin handling.
Expand Down
4 changes: 4 additions & 0 deletions clang/include/clang/Sema/SemaHLSL.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ class SemaHLSL : public SemaBase {
void handleNumThreadsAttr(Decl *D, const ParsedAttr &AL);
void handleWaveSizeAttr(Decl *D, const ParsedAttr &AL);
void handleSV_DispatchThreadIDAttr(Decl *D, const ParsedAttr &AL);
void handleSV_GroupIDAttr(Decl *D, const ParsedAttr &AL);
void handlePackOffsetAttr(Decl *D, const ParsedAttr &AL);
void handleShaderAttr(Decl *D, const ParsedAttr &AL);
void handleResourceBindingAttr(Decl *D, const ParsedAttr &AL);
Expand All @@ -136,6 +137,9 @@ class SemaHLSL : public SemaBase {

bool CheckCompatibleParameterABI(FunctionDecl *New, FunctionDecl *Old);

// Diagnose whether the input ID is uint/unit2/uint3 type.
bool diagnoseInputIDType(QualType T, const ParsedAttr &AL);

ExprResult ActOnOutParamExpr(ParmVarDecl *Param, Expr *Arg);

QualType getInoutParameterType(QualType Ty);
Expand Down
23 changes: 10 additions & 13 deletions clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
Original file line number Diff line number Diff line change
Expand Up @@ -275,10 +275,6 @@ def ConversionChecker : Checker<"Conversion">,
HelpText<"Loss of sign/precision in implicit conversions">,
Documentation<HasDocumentation>;

def IdenticalExprChecker : Checker<"IdenticalExpr">,
HelpText<"Warn about unintended use of identical expressions in operators">,
Documentation<HasDocumentation>;

def FixedAddressChecker : Checker<"FixedAddr">,
HelpText<"Check for assignment of a fixed address to a pointer">,
Documentation<HasDocumentation>;
Expand Down Expand Up @@ -457,6 +453,12 @@ def CStringModeling : Checker<"CStringModeling">,
Documentation<NotDocumented>,
Hidden;

def CStringNotNullTerm : Checker<"NotNullTerminated">,
HelpText<"Check for arguments passed to C string functions which are not "
"null-terminated strings">,
Dependencies<[CStringModeling]>,
Documentation<HasDocumentation>;

def CStringNullArg : Checker<"NullArg">,
HelpText<"Check for null pointers being passed as arguments to C string "
"functions">,
Expand All @@ -483,11 +485,6 @@ def CStringBufferOverlap : Checker<"BufferOverlap">,
Dependencies<[CStringModeling]>,
Documentation<HasDocumentation>;

def CStringNotNullTerm : Checker<"NotNullTerminated">,
HelpText<"Check for arguments which are not null-terminating strings">,
Dependencies<[CStringModeling]>,
Documentation<HasDocumentation>;

def CStringUninitializedRead : Checker<"UninitializedRead">,
HelpText<"Checks if the string manipulation function would read uninitialized bytes">,
Dependencies<[CStringModeling]>,
Expand Down Expand Up @@ -598,14 +595,14 @@ def VforkChecker : Checker<"Vfork">,
HelpText<"Check for proper usage of vfork">,
Documentation<HasDocumentation>;

} // end "unix"

let ParentPackage = UnixAlpha in {

def ChrootChecker : Checker<"Chroot">,
HelpText<"Check improper use of chroot">,
Documentation<HasDocumentation>;

} // end "unix"

let ParentPackage = UnixAlpha in {

def PthreadLockChecker : Checker<"PthreadLock">,
HelpText<"Simple lock -> unlock checker">,
Dependencies<[PthreadLockBase]>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,7 @@ class ProgramState : public llvm::FoldingSetNode {
friend void ProgramStateRetain(const ProgramState *state);
friend void ProgramStateRelease(const ProgramState *state);

SVal desugarReference(SVal Val) const;
SVal wrapSymbolicRegion(SVal Base) const;
};

Expand Down
6 changes: 3 additions & 3 deletions clang/include/clang/Tooling/Inclusions/IncludeStyle.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,10 +123,10 @@ struct IncludeStyle {
/// When guessing whether a #include is the "main" include (to assign
/// category 0, see above), use this regex of allowed suffixes to the header
/// stem. A partial match is done, so that:
/// - "" means "arbitrary suffix"
/// - "$" means "no suffix"
/// * ``""`` means "arbitrary suffix"
/// * ``"$"`` means "no suffix"
///
/// For example, if configured to "(_test)?$", then a header a.h would be seen
/// For example, if configured to ``"(_test)?$"``, then a header a.h would be seen
/// as the "main" include in both a.cc and a_test.cc.
/// \version 3.9
std::string IncludeIsMainRegex;
Expand Down
10 changes: 8 additions & 2 deletions clang/lib/AST/ASTDiagnostic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1899,11 +1899,17 @@ class TemplateDiff {

E = E->IgnoreImpCasts();

if (isa<IntegerLiteral>(E)) return false;
auto CheckIntegerLiteral = [](Expr *E) {
if (auto *TemplateExpr = dyn_cast<SubstNonTypeTemplateParmExpr>(E))
E = TemplateExpr->getReplacement();
return isa<IntegerLiteral>(E);
};

if (CheckIntegerLiteral(E)) return false;

if (UnaryOperator *UO = dyn_cast<UnaryOperator>(E))
if (UO->getOpcode() == UO_Minus)
if (isa<IntegerLiteral>(UO->getSubExpr()))
if (CheckIntegerLiteral(UO->getSubExpr()))
return false;

if (isa<CXXBoolLiteralExpr>(E))
Expand Down
16 changes: 14 additions & 2 deletions clang/lib/AST/ASTImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6093,8 +6093,7 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
Decl::IDNS_TagFriend))
continue;

Decl *Found = FoundDecl;
auto *FoundTemplate = dyn_cast<ClassTemplateDecl>(Found);
auto *FoundTemplate = dyn_cast<ClassTemplateDecl>(FoundDecl);
if (FoundTemplate) {
if (!hasSameVisibilityContextAndLinkage(FoundTemplate, D))
continue;
Expand All @@ -6118,6 +6117,19 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
// see ASTTests test ImportExistingFriendClassTemplateDef.
continue;
}
// When importing a friend, it is possible that multiple declarations
// with same name can co-exist in specific cases (if a template contains
// a friend template and has a specialization). For this case the
// declarations should match, except that the "template depth" is
// different. No linking of previous declaration is needed in this case.
// FIXME: This condition may need refinement.
if (D->getFriendObjectKind() != Decl::FOK_None &&
FoundTemplate->getFriendObjectKind() != Decl::FOK_None &&
D->getFriendObjectKind() != FoundTemplate->getFriendObjectKind() &&
IsStructuralMatch(D, FoundTemplate, /*Complain=*/false,
/*IgnoreTemplateParmDepth=*/true))
continue;

ConflictingDecls.push_back(FoundDecl);
}
}
Expand Down
23 changes: 22 additions & 1 deletion clang/lib/AST/ByteCode/Compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,10 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) {

QualType SubExprTy = SubExpr->getType();
std::optional<PrimType> FromT = classify(SubExprTy);
// Casts from integer/vector to vector.
if (CE->getType()->isVectorType())
return this->emitBuiltinBitCast(CE);

std::optional<PrimType> ToT = classify(CE->getType());
if (!FromT || !ToT)
return false;
Expand Down Expand Up @@ -6494,8 +6498,25 @@ bool Compiler<Emitter>::emitBuiltinBitCast(const CastExpr *E) {
}

// Get a pointer to the value-to-cast on the stack.
if (!this->visit(SubExpr))
// For CK_LValueToRValueBitCast, this is always an lvalue and
// we later assume it to be one (i.e. a PT_Ptr). However,
// we call this function for other utility methods where
// a bitcast might be useful, so convert it to a PT_Ptr in that case.
if (SubExpr->isGLValue() || FromType->isVectorType()) {
if (!this->visit(SubExpr))
return false;
} else if (std::optional<PrimType> FromT = classify(SubExpr)) {
unsigned TempOffset = allocateLocalPrimitive(
SubExpr, *FromT, /*IsConst=*/true, /*IsExtended=*/false);
if (!this->visit(SubExpr))
return false;
if (!this->emitSetLocal(*FromT, TempOffset, E))
return false;
if (!this->emitGetPtrLocal(TempOffset, E))
return false;
} else {
return false;
}

if (!ToT || ToT == PT_Ptr) {
if (!this->emitBitCastPtr(E))
Expand Down
7 changes: 3 additions & 4 deletions clang/lib/AST/ByteCode/Context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,7 @@ bool Context::isPotentialConstantExpr(State &Parent, const FunctionDecl *FD) {
if (!Func)
return false;

APValue DummyResult;
if (!Run(Parent, Func, DummyResult))
if (!Run(Parent, Func))
return false;

return Func->isConstexpr();
Expand Down Expand Up @@ -213,13 +212,13 @@ const llvm::fltSemantics &Context::getFloatSemantics(QualType T) const {
return Ctx.getFloatTypeSemantics(T);
}

bool Context::Run(State &Parent, const Function *Func, APValue &Result) {
bool Context::Run(State &Parent, const Function *Func) {

{
InterpState State(Parent, *P, Stk, *this);
State.Current = new InterpFrame(State, Func, /*Caller=*/nullptr, CodePtr(),
Func->getArgSize());
if (Interpret(State, Result)) {
if (Interpret(State)) {
assert(Stk.empty());
return true;
}
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/ByteCode/Context.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ class Context final {

private:
/// Runs a function.
bool Run(State &Parent, const Function *Func, APValue &Result);
bool Run(State &Parent, const Function *Func);

/// Current compilation context.
ASTContext &Ctx;
Expand Down
4 changes: 3 additions & 1 deletion clang/lib/AST/ByteCode/Integral.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,9 @@ template <unsigned Bits, bool Signed> class Integral final {
APSInt toAPSInt() const {
return APSInt(APInt(Bits, static_cast<uint64_t>(V), Signed), !Signed);
}
APSInt toAPSInt(unsigned BitWidth) const { return APSInt(toAPInt(BitWidth)); }
APSInt toAPSInt(unsigned BitWidth) const {
return APSInt(toAPInt(BitWidth), !Signed);
}
APInt toAPInt(unsigned BitWidth) const {
if constexpr (Signed)
return APInt(Bits, static_cast<uint64_t>(V), Signed)
Expand Down
10 changes: 4 additions & 6 deletions clang/lib/AST/ByteCode/Interp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
using namespace clang;
using namespace clang::interp;

static bool RetValue(InterpState &S, CodePtr &Pt, APValue &Result) {
static bool RetValue(InterpState &S, CodePtr &Pt) {
llvm::report_fatal_error("Interpreter cannot return values");
}

Expand Down Expand Up @@ -1205,11 +1205,10 @@ bool CallVar(InterpState &S, CodePtr OpPC, const Function *Func,
InterpFrame *FrameBefore = S.Current;
S.Current = NewFrame.get();

APValue CallResult;
// Note that we cannot assert(CallResult.hasValue()) here since
// Ret() above only sets the APValue if the curent frame doesn't
// have a caller set.
if (Interpret(S, CallResult)) {
if (Interpret(S)) {
NewFrame.release(); // Frame was delete'd already.
assert(S.Current == FrameBefore);
return true;
Expand Down Expand Up @@ -1270,11 +1269,10 @@ bool Call(InterpState &S, CodePtr OpPC, const Function *Func,
S.Current = NewFrame.get();

InterpStateCCOverride CCOverride(S, Func->getDecl()->isImmediateFunction());
APValue CallResult;
// Note that we cannot assert(CallResult.hasValue()) here since
// Ret() above only sets the APValue if the curent frame doesn't
// have a caller set.
if (Interpret(S, CallResult)) {
if (Interpret(S)) {
NewFrame.release(); // Frame was delete'd already.
assert(S.Current == FrameBefore);
return true;
Expand Down Expand Up @@ -1598,7 +1596,7 @@ bool CheckBitCast(InterpState &S, CodePtr OpPC, bool HasIndeterminateBits,
#if defined(_MSC_VER) && !defined(__clang__) && !defined(NDEBUG)
#pragma optimize("", off)
#endif
bool Interpret(InterpState &S, APValue &Result) {
bool Interpret(InterpState &S) {
// The current stack frame when we started Interpret().
// This is being used by the ops to determine wheter
// to return from this function and thus terminate
Expand Down
17 changes: 5 additions & 12 deletions clang/lib/AST/ByteCode/Interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,6 @@ namespace interp {
using APSInt = llvm::APSInt;
using FixedPointSemantics = llvm::FixedPointSemantics;

/// Convert a value to an APValue.
template <typename T>
bool ReturnValue(const InterpState &S, const T &V, APValue &R) {
R = V.toAPValue(S.getASTContext());
return true;
}

/// Checks if the variable has externally defined storage.
bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr);

Expand Down Expand Up @@ -299,7 +292,7 @@ bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result,
bool CheckDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR);

/// Interpreter entry point.
bool Interpret(InterpState &S, APValue &Result);
bool Interpret(InterpState &S);

/// Interpret a builtin function.
bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
Expand All @@ -321,7 +314,7 @@ void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC,
const Function *Func);

template <PrimType Name, class T = typename PrimConv<Name>::T>
bool Ret(InterpState &S, CodePtr &PC, APValue &Result) {
bool Ret(InterpState &S, CodePtr &PC) {
const T &Ret = S.Stk.pop<T>();

// Make sure returned pointers are live. We might be trying to return a
Expand Down Expand Up @@ -349,13 +342,13 @@ bool Ret(InterpState &S, CodePtr &PC, APValue &Result) {
} else {
delete S.Current;
S.Current = nullptr;
if (!ReturnValue<T>(S, Ret, Result))
return false;
// The topmost frame should come from an EvalEmitter,
// which has its own implementation of the Ret<> instruction.
}
return true;
}

inline bool RetVoid(InterpState &S, CodePtr &PC, APValue &Result) {
inline bool RetVoid(InterpState &S, CodePtr &PC) {
assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");

if (!S.checkingPotentialConstantExpression() || S.Current->Caller)
Expand Down
103 changes: 96 additions & 7 deletions clang/lib/AST/ByteCode/InterpBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,13 +89,14 @@ static void pushInteger(InterpState &S, const APSInt &Val, QualType QT) {
std::optional<PrimType> T = S.getContext().classify(QT);
assert(T);

unsigned BitWidth = S.getASTContext().getTypeSize(QT);
if (QT->isSignedIntegerOrEnumerationType()) {
int64_t V = Val.getSExtValue();
INT_TYPE_SWITCH(*T, { S.Stk.push<T>(T::from(V)); });
INT_TYPE_SWITCH(*T, { S.Stk.push<T>(T::from(V, BitWidth)); });
} else {
assert(QT->isUnsignedIntegerOrEnumerationType());
uint64_t V = Val.getZExtValue();
INT_TYPE_SWITCH(*T, { S.Stk.push<T>(T::from(V)); });
INT_TYPE_SWITCH(*T, { S.Stk.push<T>(T::from(V, BitWidth)); });
}
}

Expand All @@ -116,14 +117,14 @@ static void assignInteger(Pointer &Dest, PrimType ValueT, const APSInt &Value) {
ValueT, { Dest.deref<T>() = T::from(static_cast<T>(Value)); });
}

static bool retPrimValue(InterpState &S, CodePtr OpPC, APValue &Result,
static bool retPrimValue(InterpState &S, CodePtr OpPC,
std::optional<PrimType> &T) {
if (!T)
return RetVoid(S, OpPC, Result);
return RetVoid(S, OpPC);

#define RET_CASE(X) \
case X: \
return Ret<X>(S, OpPC, Result);
return Ret<X>(S, OpPC);
switch (*T) {
RET_CASE(PT_Ptr);
RET_CASE(PT_FnPtr);
Expand All @@ -137,6 +138,8 @@ static bool retPrimValue(InterpState &S, CodePtr OpPC, APValue &Result,
RET_CASE(PT_Uint32);
RET_CASE(PT_Sint64);
RET_CASE(PT_Uint64);
RET_CASE(PT_IntAP);
RET_CASE(PT_IntAPS);
default:
llvm_unreachable("Unsupported return type for builtin function");
}
Expand Down Expand Up @@ -1684,10 +1687,84 @@ static bool interp__builtin_arithmetic_fence(InterpState &S, CodePtr OpPC,
return true;
}

static bool interp__builtin_vector_reduce(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame,
const Function *Func,
const CallExpr *Call) {
const Pointer &Arg = S.Stk.peek<Pointer>();
assert(Arg.getFieldDesc()->isPrimitiveArray());

unsigned ID = Func->getBuiltinID();
QualType ElemType = Arg.getFieldDesc()->getElemQualType();
assert(Call->getType() == ElemType);
PrimType ElemT = *S.getContext().classify(ElemType);
unsigned NumElems = Arg.getNumElems();

INT_TYPE_SWITCH_NO_BOOL(ElemT, {
T Result = Arg.atIndex(0).deref<T>();
unsigned BitWidth = Result.bitWidth();
for (unsigned I = 1; I != NumElems; ++I) {
T Elem = Arg.atIndex(I).deref<T>();
T PrevResult = Result;

if (ID == Builtin::BI__builtin_reduce_add) {
if (T::add(Result, Elem, BitWidth, &Result)) {
unsigned OverflowBits = BitWidth + 1;
(void)handleOverflow(S, OpPC,
(PrevResult.toAPSInt(OverflowBits) +
Elem.toAPSInt(OverflowBits)));
return false;
}
} else if (ID == Builtin::BI__builtin_reduce_mul) {
if (T::mul(Result, Elem, BitWidth, &Result)) {
unsigned OverflowBits = BitWidth * 2;
(void)handleOverflow(S, OpPC,
(PrevResult.toAPSInt(OverflowBits) *
Elem.toAPSInt(OverflowBits)));
return false;
}

} else if (ID == Builtin::BI__builtin_reduce_and) {
(void)T::bitAnd(Result, Elem, BitWidth, &Result);
} else {
llvm_unreachable("Unhandled vector reduce builtin");
}
}
pushInteger(S, Result, Call->getType());
});

return true;
}

static bool interp__builtin_memcpy(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame,
const Function *Func, const CallExpr *Call) {
assert(Call->getNumArgs() == 3);
Pointer DestPtr = getParam<Pointer>(Frame, 0);
const Pointer &SrcPtr = getParam<Pointer>(Frame, 1);
const APSInt &Size =
peekToAPSInt(S.Stk, *S.getContext().classify(Call->getArg(2)));
assert(!Size.isSigned() && "memcpy and friends take an unsigned size");

if (DestPtr.isDummy() || SrcPtr.isDummy())
return false;

// If the size is zero, we treat this as always being a valid no-op.
if (Size.isZero()) {
S.Stk.push<Pointer>(DestPtr);
return true;
}

if (!DoBitCastPtr(S, OpPC, SrcPtr, DestPtr))
return false;

S.Stk.push<Pointer>(DestPtr);
return true;
}

bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
const CallExpr *Call, uint32_t BuiltinID) {
const InterpFrame *Frame = S.Current;
APValue Dummy;

std::optional<PrimType> ReturnT = S.getContext().classify(Call);

Expand Down Expand Up @@ -2130,6 +2207,18 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
return false;
break;

case Builtin::BI__builtin_reduce_add:
case Builtin::BI__builtin_reduce_mul:
case Builtin::BI__builtin_reduce_and:
if (!interp__builtin_vector_reduce(S, OpPC, Frame, F, Call))
return false;
break;

case Builtin::BI__builtin_memcpy:
if (!interp__builtin_memcpy(S, OpPC, Frame, F, Call))
return false;
break;

default:
S.FFDiag(S.Current->getLocation(OpPC),
diag::note_invalid_subexpr_in_const_expr)
Expand All @@ -2138,7 +2227,7 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
return false;
}

return retPrimValue(S, OpPC, Dummy, ReturnT);
return retPrimValue(S, OpPC, ReturnT);
}

bool InterpretOffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E,
Expand Down
13 changes: 9 additions & 4 deletions clang/lib/AST/DeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -546,9 +546,9 @@ void CXXRecordDecl::addedClassSubobject(CXXRecordDecl *Subobj) {
data().NeedOverloadResolutionForDestructor = true;
}

// C++2a [dcl.constexpr]p4:
// The definition of a constexpr destructor [shall] satisfy the
// following requirement:
// C++20 [dcl.constexpr]p5:
// The definition of a constexpr destructor whose function-body is not
// = delete shall additionally satisfy the following requirement:
// -- for every subobject of class type or (possibly multi-dimensional)
// array thereof, that class type shall have a constexpr destructor
if (!Subobj->hasConstexprDestructor())
Expand Down Expand Up @@ -1213,8 +1213,13 @@ void CXXRecordDecl::addedMember(Decl *D) {
data().DefaultedCopyAssignmentIsDeleted = true;
if (FieldRec->hasNonTrivialMoveAssignment())
data().DefaultedMoveAssignmentIsDeleted = true;
if (FieldRec->hasNonTrivialDestructor())
if (FieldRec->hasNonTrivialDestructor()) {
data().DefaultedDestructorIsDeleted = true;
// C++20 [dcl.constexpr]p5:
// The definition of a constexpr destructor whose function-body is
// not = delete shall additionally satisfy...
data().DefaultedDestructorIsConstexpr = true;
}
}

// For an anonymous union member, our overload resolution will perform
Expand Down
31 changes: 31 additions & 0 deletions clang/lib/AST/ExprConstant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11005,6 +11005,7 @@ namespace {
bool VisitUnaryImag(const UnaryOperator *E);
bool VisitBinaryOperator(const BinaryOperator *E);
bool VisitUnaryOperator(const UnaryOperator *E);
bool VisitCallExpr(const CallExpr *E);
bool VisitConvertVectorExpr(const ConvertVectorExpr *E);
bool VisitShuffleVectorExpr(const ShuffleVectorExpr *E);

Expand Down Expand Up @@ -11302,6 +11303,35 @@ static bool handleVectorElementCast(EvalInfo &Info, const FPOptions FPO,
return false;
}

bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) {
if (!IsConstantEvaluatedBuiltinCall(E))
return ExprEvaluatorBaseTy::VisitCallExpr(E);

switch (E->getBuiltinCallee()) {
default:
return false;
case Builtin::BI__builtin_elementwise_popcount: {
APValue Source;
if (!EvaluateAsRValue(Info, E->getArg(0), Source))
return false;

QualType DestEltTy = E->getType()->castAs<VectorType>()->getElementType();
unsigned SourceLen = Source.getVectorLength();
SmallVector<APValue, 4> ResultElements;
ResultElements.reserve(SourceLen);

for (unsigned EltNum = 0; EltNum < SourceLen; ++EltNum) {
APSInt Elt = Source.getVectorElt(EltNum).getInt();
ResultElements.push_back(
APValue(APSInt(APInt(Info.Ctx.getIntWidth(DestEltTy), Elt.popcount()),
DestEltTy->isUnsignedIntegerOrEnumerationType())));
}

return Success(APValue(ResultElements.data(), ResultElements.size()), E);
}
}
}

bool VectorExprEvaluator::VisitConvertVectorExpr(const ConvertVectorExpr *E) {
APValue Source;
QualType SourceVecType = E->getSrcExpr()->getType();
Expand Down Expand Up @@ -13118,6 +13148,7 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
case Builtin::BI__builtin_popcountl:
case Builtin::BI__builtin_popcountll:
case Builtin::BI__builtin_popcountg:
case Builtin::BI__builtin_elementwise_popcount:
case Builtin::BI__popcnt16: // Microsoft variants of popcount
case Builtin::BI__popcnt:
case Builtin::BI__popcnt64: {
Expand Down
71 changes: 71 additions & 0 deletions clang/lib/AST/ItaniumMangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -574,6 +574,7 @@ class CXXNameMangler {
static StringRef getCallingConvQualifierName(CallingConv CC);
void mangleExtParameterInfo(FunctionProtoType::ExtParameterInfo info);
void mangleExtFunctionInfo(const FunctionType *T);
void mangleSMEAttrs(unsigned SMEAttrs);
void mangleBareFunctionType(const FunctionProtoType *T, bool MangleReturnType,
const FunctionDecl *FD = nullptr);
void mangleNeonVectorType(const VectorType *T);
Expand Down Expand Up @@ -3532,6 +3533,69 @@ void CXXNameMangler::mangleExtFunctionInfo(const FunctionType *T) {
// FIXME: noreturn
}

enum class AAPCSBitmaskSME : unsigned {
ArmStreamingBit = 1 << 0,
ArmStreamingCompatibleBit = 1 << 1,
ArmAgnosticSMEZAStateBit = 1 << 2,
ZA_Shift = 3,
ZT0_Shift = 6,
NoState = 0b000,
ArmIn = 0b001,
ArmOut = 0b010,
ArmInOut = 0b011,
ArmPreserves = 0b100,
LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/ArmPreserves << ZT0_Shift)
};

static AAPCSBitmaskSME encodeAAPCSZAState(unsigned SMEAttrs) {
switch (SMEAttrs) {
case FunctionType::ARM_None:
return AAPCSBitmaskSME::NoState;
case FunctionType::ARM_In:
return AAPCSBitmaskSME::ArmIn;
case FunctionType::ARM_Out:
return AAPCSBitmaskSME::ArmOut;
case FunctionType::ARM_InOut:
return AAPCSBitmaskSME::ArmInOut;
case FunctionType::ARM_Preserves:
return AAPCSBitmaskSME::ArmPreserves;
default:
llvm_unreachable("Unrecognised SME attribute");
}
}

// The mangling scheme for function types which have SME attributes is
// implemented as a "pseudo" template:
//
// '__SME_ATTRS<<normal_function_type>, <sme_state>>'
//
// Combining the function type with a bitmask representing the streaming and ZA
// properties of the function's interface.
//
// Mangling of SME keywords is described in more detail in the AArch64 ACLE:
// https://github.com/ARM-software/acle/blob/main/main/acle.md#c-mangling-of-sme-keywords
//
void CXXNameMangler::mangleSMEAttrs(unsigned SMEAttrs) {
if (!SMEAttrs)
return;

AAPCSBitmaskSME Bitmask = AAPCSBitmaskSME(0);
if (SMEAttrs & FunctionType::SME_PStateSMEnabledMask)
Bitmask |= AAPCSBitmaskSME::ArmStreamingBit;
else if (SMEAttrs & FunctionType::SME_PStateSMCompatibleMask)
Bitmask |= AAPCSBitmaskSME::ArmStreamingCompatibleBit;

// TODO: Must represent __arm_agnostic("sme_za_state")

Bitmask |= encodeAAPCSZAState(FunctionType::getArmZAState(SMEAttrs))
<< AAPCSBitmaskSME::ZA_Shift;

Bitmask |= encodeAAPCSZAState(FunctionType::getArmZT0State(SMEAttrs))
<< AAPCSBitmaskSME::ZT0_Shift;

Out << "Lj" << static_cast<unsigned>(Bitmask) << "EE";
}

void
CXXNameMangler::mangleExtParameterInfo(FunctionProtoType::ExtParameterInfo PI) {
// Vendor-specific qualifiers are emitted in reverse alphabetical order.
Expand Down Expand Up @@ -3569,6 +3633,11 @@ CXXNameMangler::mangleExtParameterInfo(FunctionProtoType::ExtParameterInfo PI) {
// <function-type> ::= [<CV-qualifiers>] F [Y]
// <bare-function-type> [<ref-qualifier>] E
void CXXNameMangler::mangleType(const FunctionProtoType *T) {
unsigned SMEAttrs = T->getAArch64SMEAttributes();

if (SMEAttrs)
Out << "11__SME_ATTRSI";

mangleExtFunctionInfo(T);

// Mangle CV-qualifiers, if present. These are 'this' qualifiers,
Expand Down Expand Up @@ -3603,6 +3672,8 @@ void CXXNameMangler::mangleType(const FunctionProtoType *T) {
mangleRefQualifier(T->getRefQualifier());

Out << 'E';

mangleSMEAttrs(SMEAttrs);
}

void CXXNameMangler::mangleType(const FunctionNoProtoType *T) {
Expand Down
5 changes: 4 additions & 1 deletion clang/lib/AST/StmtPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2514,7 +2514,10 @@ void StmtPrinter::VisitSizeOfPackExpr(SizeOfPackExpr *E) {
}

void StmtPrinter::VisitPackIndexingExpr(PackIndexingExpr *E) {
OS << E->getPackIdExpression() << "...[" << E->getIndexExpr() << "]";
PrintExpr(E->getPackIdExpression());
OS << "...[";
PrintExpr(E->getIndexExpr());
OS << "]";
}

void StmtPrinter::VisitSubstNonTypeTemplateParmPackExpr(
Expand Down
1 change: 1 addition & 0 deletions clang/lib/ASTMatchers/ASTMatchersInternal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -799,6 +799,7 @@ const internal::VariadicDynCastAllOfMatcher<TypeLoc, ElaboratedTypeLoc>

const internal::VariadicDynCastAllOfMatcher<Stmt, UnaryExprOrTypeTraitExpr>
unaryExprOrTypeTraitExpr;
const internal::VariadicDynCastAllOfMatcher<Decl, ExportDecl> exportDecl;
const internal::VariadicDynCastAllOfMatcher<Decl, ValueDecl> valueDecl;
const internal::VariadicDynCastAllOfMatcher<Decl, CXXConstructorDecl>
cxxConstructorDecl;
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Analysis/Consumed.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1229,6 +1229,9 @@ bool ConsumedAnalyzer::splitState(const CFGBlock *CurrBlock,

if (const auto *IfNode =
dyn_cast_or_null<IfStmt>(CurrBlock->getTerminator().getStmt())) {
if (IfNode->isConsteval())
return false;

const Expr *Cond = IfNode->getCond();

PInfo = Visitor.getInfo(Cond);
Expand Down
23 changes: 23 additions & 0 deletions clang/lib/Analysis/FlowSensitive/ASTOps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
//===----------------------------------------------------------------------===//

#include "clang/Analysis/FlowSensitive/ASTOps.h"
#include "clang/AST/ASTLambda.h"
#include "clang/AST/ComputeDependence.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclBase.h"
Expand Down Expand Up @@ -282,6 +283,28 @@ ReferencedDecls getReferencedDecls(const FunctionDecl &FD) {
if (const auto *CtorDecl = dyn_cast<CXXConstructorDecl>(&FD))
Visitor.traverseConstructorInits(CtorDecl);

// If analyzing a lambda call operator, collect all captures of parameters (of
// the surrounding function). This collects them even if they are not
// referenced in the body of the lambda call operator. Non-parameter local
// variables that are captured are already collected into
// `ReferencedDecls.Locals` when traversing the call operator body, but we
// collect parameters here to avoid needing to check at each referencing node
// whether the parameter is a lambda capture from a surrounding function or is
// a parameter of the current function. If it becomes necessary to limit this
// set to the parameters actually referenced in the body, alternative
// optimizations can be implemented to minimize duplicative work.
if (const auto *Method = dyn_cast<CXXMethodDecl>(&FD);
Method && isLambdaCallOperator(Method)) {
for (const auto &Capture : Method->getParent()->captures()) {
if (Capture.capturesVariable()) {
if (const auto *Param =
dyn_cast<ParmVarDecl>(Capture.getCapturedVar())) {
Result.LambdaCapturedParams.insert(Param);
}
}
}
}

return Result;
}

Expand Down
4 changes: 2 additions & 2 deletions clang/lib/Analysis/FlowSensitive/Arena.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ canonicalFormulaPair(const Formula &LHS, const Formula &RHS) {
}

template <class Key, class ComputeFunc>
const Formula &cached(llvm::DenseMap<Key, const Formula *> &Cache, Key K,
ComputeFunc &&Compute) {
static const Formula &cached(llvm::DenseMap<Key, const Formula *> &Cache, Key K,
ComputeFunc &&Compute) {
auto [It, Inserted] = Cache.try_emplace(std::forward<Key>(K));
if (Inserted)
It->second = Compute();
Expand Down
14 changes: 8 additions & 6 deletions clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ static llvm::DenseMap<const ValueDecl *, StorageLocation *> intersectDeclToLoc(
// expression must map to the same location / value. This is the case if we are
// performing a join for control flow within a full-expression (which is the
// only case when this function should be used).
template <typename MapT> MapT joinExprMaps(const MapT &Map1, const MapT &Map2) {
template <typename MapT>
static MapT joinExprMaps(const MapT &Map1, const MapT &Map2) {
MapT Result = Map1;

for (const auto &Entry : Map2) {
Expand Down Expand Up @@ -204,10 +205,11 @@ static WidenResult widenDistinctValues(QualType Type, Value &Prev,
// Returns whether the values in `Map1` and `Map2` compare equal for those
// keys that `Map1` and `Map2` have in common.
template <typename Key>
bool compareKeyToValueMaps(const llvm::MapVector<Key, Value *> &Map1,
const llvm::MapVector<Key, Value *> &Map2,
const Environment &Env1, const Environment &Env2,
Environment::ValueModel &Model) {
static bool compareKeyToValueMaps(const llvm::MapVector<Key, Value *> &Map1,
const llvm::MapVector<Key, Value *> &Map2,
const Environment &Env1,
const Environment &Env2,
Environment::ValueModel &Model) {
for (auto &Entry : Map1) {
Key K = Entry.first;
assert(K != nullptr);
Expand Down Expand Up @@ -260,7 +262,7 @@ joinLocToVal(const llvm::MapVector<const StorageLocation *, Value *> &LocToVal,
// Perform widening on either `LocToVal` or `ExprToVal`. `Key` must be either
// `const StorageLocation *` or `const Expr *`.
template <typename Key>
llvm::MapVector<Key, Value *>
static llvm::MapVector<Key, Value *>
widenKeyToValueMap(const llvm::MapVector<Key, Value *> &CurMap,
const llvm::MapVector<Key, Value *> &PrevMap,
Environment &CurEnv, const Environment &PrevEnv,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ namespace dataflow {

/// Determines whether `D` is one of the methods used to implement Chromium's
/// `CHECK` macros. Populates `CheckDecls`, if empty.
bool isCheckLikeMethod(llvm::SmallDenseSet<const CXXMethodDecl *> &CheckDecls,
const CXXMethodDecl &D) {
static bool
isCheckLikeMethod(llvm::SmallDenseSet<const CXXMethodDecl *> &CheckDecls,
const CXXMethodDecl &D) {
// All of the methods of interest are static, so avoid any lookup for
// non-static methods (the common case).
if (!D.isStatic())
Expand Down
16 changes: 8 additions & 8 deletions clang/lib/Analysis/IntervalPartition.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ static unsigned getID(const CFGIntervalNode &I) { return I.ID; }

// `Node` must be one of `CFGBlock` or `CFGIntervalNode`.
template <typename Node>
BuildResult<Node> buildInterval(llvm::BitVector &Partitioned,
const Node *Header) {
static BuildResult<Node> buildInterval(llvm::BitVector &Partitioned,
const Node *Header) {
assert(Header != nullptr);
BuildResult<Node> Interval;
Interval.Nodes.push_back(Header);
Expand Down Expand Up @@ -102,10 +102,10 @@ BuildResult<Node> buildInterval(llvm::BitVector &Partitioned,
}

template <typename Node>
void fillIntervalNode(CFGIntervalGraph &Graph,
std::vector<CFGIntervalNode *> &Index,
std::queue<const Node *> &Successors,
llvm::BitVector &Partitioned, const Node *Header) {
static void fillIntervalNode(CFGIntervalGraph &Graph,
std::vector<CFGIntervalNode *> &Index,
std::queue<const Node *> &Successors,
llvm::BitVector &Partitioned, const Node *Header) {
BuildResult<Node> Result = buildInterval(Partitioned, Header);
for (const auto *S : Result.Successors)
Successors.push(S);
Expand Down Expand Up @@ -138,8 +138,8 @@ void fillIntervalNode(CFGIntervalGraph &Graph,
}

template <typename Node>
CFGIntervalGraph partitionIntoIntervalsImpl(unsigned NumBlockIDs,
const Node *EntryBlock) {
static CFGIntervalGraph partitionIntoIntervalsImpl(unsigned NumBlockIDs,
const Node *EntryBlock) {
assert(EntryBlock != nullptr);
CFGIntervalGraph Graph;
// `Index` maps all of the nodes of the input graph to the interval to which
Expand Down
130 changes: 84 additions & 46 deletions clang/lib/Analysis/UnsafeBufferUsage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,12 @@ class MatchDescendantVisitor : public DynamicRecursiveASTVisitor {
return DynamicRecursiveASTVisitor::TraverseCXXTypeidExpr(Node);
}

bool TraverseCXXDefaultInitExpr(CXXDefaultInitExpr *Node) override {
if (!TraverseStmt(Node->getExpr()))
return false;
return DynamicRecursiveASTVisitor::TraverseCXXDefaultInitExpr(Node);
}

bool TraverseStmt(Stmt *Node) override {
if (!Node)
return true;
Expand Down Expand Up @@ -1987,14 +1993,18 @@ class DerefSimplePtrArithFixableGadget : public FixableGadget {
};

/// Scan the function and return a list of gadgets found with provided kits.
static std::tuple<FixableGadgetList, WarningGadgetList, DeclUseTracker>
findGadgets(const Decl *D, const UnsafeBufferUsageHandler &Handler,
bool EmitSuggestions) {
static void findGadgets(const Stmt *S, ASTContext &Ctx,
const UnsafeBufferUsageHandler &Handler,
bool EmitSuggestions, FixableGadgetList &FixableGadgets,
WarningGadgetList &WarningGadgets,
DeclUseTracker &Tracker) {

struct GadgetFinderCallback : MatchFinder::MatchCallback {
FixableGadgetList FixableGadgets;
WarningGadgetList WarningGadgets;
DeclUseTracker Tracker;
GadgetFinderCallback(FixableGadgetList &FixableGadgets,
WarningGadgetList &WarningGadgets,
DeclUseTracker &Tracker)
: FixableGadgets(FixableGadgets), WarningGadgets(WarningGadgets),
Tracker(Tracker) {}

void run(const MatchFinder::MatchResult &Result) override {
// In debug mode, assert that we've found exactly one gadget.
Expand Down Expand Up @@ -2035,10 +2045,14 @@ findGadgets(const Decl *D, const UnsafeBufferUsageHandler &Handler,
assert(numFound >= 1 && "Gadgets not found in match result!");
assert(numFound <= 1 && "Conflicting bind tags in gadgets!");
}

FixableGadgetList &FixableGadgets;
WarningGadgetList &WarningGadgets;
DeclUseTracker &Tracker;
};

MatchFinder M;
GadgetFinderCallback CB;
GadgetFinderCallback CB{FixableGadgets, WarningGadgets, Tracker};

// clang-format off
M.addMatcher(
Expand Down Expand Up @@ -2083,9 +2097,7 @@ findGadgets(const Decl *D, const UnsafeBufferUsageHandler &Handler,
// clang-format on
}

M.match(*D->getBody(), D->getASTContext());
return {std::move(CB.FixableGadgets), std::move(CB.WarningGadgets),
std::move(CB.Tracker)};
M.match(*S, Ctx);
}

// Compares AST nodes by source locations.
Expand Down Expand Up @@ -2326,7 +2338,8 @@ static StringRef getEndOfLine() {
}

// Returns the text indicating that the user needs to provide input there:
std::string getUserFillPlaceHolder(StringRef HintTextToUser = "placeholder") {
static std::string
getUserFillPlaceHolder(StringRef HintTextToUser = "placeholder") {
std::string s = std::string("<# ");
s += HintTextToUser;
s += " #>";
Expand Down Expand Up @@ -3629,39 +3642,9 @@ class VariableGroupsManagerImpl : public VariableGroupsManager {
}
};

void clang::checkUnsafeBufferUsage(const Decl *D,
UnsafeBufferUsageHandler &Handler,
bool EmitSuggestions) {
#ifndef NDEBUG
Handler.clearDebugNotes();
#endif

assert(D && D->getBody());
// We do not want to visit a Lambda expression defined inside a method
// independently. Instead, it should be visited along with the outer method.
// FIXME: do we want to do the same thing for `BlockDecl`s?
if (const auto *fd = dyn_cast<CXXMethodDecl>(D)) {
if (fd->getParent()->isLambda() && fd->getParent()->isLocalClass())
return;
}

// Do not emit fixit suggestions for functions declared in an
// extern "C" block.
if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
for (FunctionDecl *FReDecl : FD->redecls()) {
if (FReDecl->isExternC()) {
EmitSuggestions = false;
break;
}
}
}

WarningGadgetSets UnsafeOps;
FixableGadgetSets FixablesForAllVars;

auto [FixableGadgets, WarningGadgets, Tracker] =
findGadgets(D, Handler, EmitSuggestions);

void applyGadgets(const Decl *D, FixableGadgetList FixableGadgets,
WarningGadgetList WarningGadgets, DeclUseTracker Tracker,
UnsafeBufferUsageHandler &Handler, bool EmitSuggestions) {
if (!EmitSuggestions) {
// Our job is very easy without suggestions. Just warn about
// every problematic operation and consider it done. No need to deal
Expand Down Expand Up @@ -3705,8 +3688,10 @@ void clang::checkUnsafeBufferUsage(const Decl *D,
if (WarningGadgets.empty())
return;

UnsafeOps = groupWarningGadgetsByVar(std::move(WarningGadgets));
FixablesForAllVars = groupFixablesByVar(std::move(FixableGadgets));
WarningGadgetSets UnsafeOps =
groupWarningGadgetsByVar(std::move(WarningGadgets));
FixableGadgetSets FixablesForAllVars =
groupFixablesByVar(std::move(FixableGadgets));

std::map<const VarDecl *, FixItList> FixItsForVariableGroup;

Expand Down Expand Up @@ -3927,3 +3912,56 @@ void clang::checkUnsafeBufferUsage(const Decl *D,
}
}
}

void clang::checkUnsafeBufferUsage(const Decl *D,
UnsafeBufferUsageHandler &Handler,
bool EmitSuggestions) {
#ifndef NDEBUG
Handler.clearDebugNotes();
#endif

assert(D);

SmallVector<Stmt *> Stmts;

if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
// We do not want to visit a Lambda expression defined inside a method
// independently. Instead, it should be visited along with the outer method.
// FIXME: do we want to do the same thing for `BlockDecl`s?
if (const auto *MD = dyn_cast<CXXMethodDecl>(D)) {
if (MD->getParent()->isLambda() && MD->getParent()->isLocalClass())
return;
}

for (FunctionDecl *FReDecl : FD->redecls()) {
if (FReDecl->isExternC()) {
// Do not emit fixit suggestions for functions declared in an
// extern "C" block.
EmitSuggestions = false;
break;
}
}

Stmts.push_back(FD->getBody());

if (const auto *ID = dyn_cast<CXXConstructorDecl>(D)) {
for (const CXXCtorInitializer *CI : ID->inits()) {
Stmts.push_back(CI->getInit());
}
}
} else if (isa<BlockDecl>(D) || isa<ObjCMethodDecl>(D)) {
Stmts.push_back(D->getBody());
}

assert(!Stmts.empty());

FixableGadgetList FixableGadgets;
WarningGadgetList WarningGadgets;
DeclUseTracker Tracker;
for (Stmt *S : Stmts) {
findGadgets(S, D->getASTContext(), Handler, EmitSuggestions, FixableGadgets,
WarningGadgets, Tracker);
}
applyGadgets(D, std::move(FixableGadgets), std::move(WarningGadgets),
std::move(Tracker), Handler, EmitSuggestions);
}
14 changes: 2 additions & 12 deletions clang/lib/Basic/Targets/AArch64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -705,18 +705,8 @@ AArch64TargetInfo::getVScaleRange(const LangOptions &LangOpts) const {
return std::nullopt;
}

unsigned AArch64TargetInfo::multiVersionSortPriority(StringRef Name) const {
if (Name == "default")
return 0;
if (auto Ext = llvm::AArch64::parseFMVExtension(Name))
return Ext->Priority;
return 0;
}

unsigned AArch64TargetInfo::multiVersionFeatureCost() const {
// Take the maximum priority as per feature cost, so more features win.
constexpr unsigned MaxFMVPriority = 1000;
return MaxFMVPriority;
unsigned AArch64TargetInfo::getFMVPriority(ArrayRef<StringRef> Features) const {
return llvm::AArch64::getFMVPriority(Features);
}

bool AArch64TargetInfo::doesFeatureAffectCodeGen(StringRef Name) const {
Expand Down
3 changes: 1 addition & 2 deletions clang/lib/Basic/Targets/AArch64.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,7 @@ class LLVM_LIBRARY_VISIBILITY AArch64TargetInfo : public TargetInfo {
void fillValidCPUList(SmallVectorImpl<StringRef> &Values) const override;
bool setCPU(const std::string &Name) override;

unsigned multiVersionSortPriority(StringRef Name) const override;
unsigned multiVersionFeatureCost() const override;
unsigned getFMVPriority(ArrayRef<StringRef> Features) const override;

bool useFP16ConversionIntrinsics() const override {
return false;
Expand Down
13 changes: 12 additions & 1 deletion clang/lib/Basic/Targets/LoongArch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,8 @@ void LoongArchTargetInfo::getTargetDefines(const LangOptions &Opts,
// TODO: As more features of the V1.1 ISA are supported, a unified "v1.1"
// arch feature set will be used to include all sub-features belonging to
// the V1.1 ISA version.
if (HasFeatureFrecipe && HasFeatureLAM_BH && HasFeatureLD_SEQ_SA)
if (HasFeatureFrecipe && HasFeatureLAM_BH && HasFeatureLAMCAS &&
HasFeatureLD_SEQ_SA && HasFeatureDiv32)
Builder.defineMacro("__loongarch_arch",
Twine('"') + "la64v1.1" + Twine('"'));
else
Expand Down Expand Up @@ -239,9 +240,15 @@ void LoongArchTargetInfo::getTargetDefines(const LangOptions &Opts,
if (HasFeatureLAM_BH)
Builder.defineMacro("__loongarch_lam_bh", Twine(1));

if (HasFeatureLAMCAS)
Builder.defineMacro("__loongarch_lamcas", Twine(1));

if (HasFeatureLD_SEQ_SA)
Builder.defineMacro("__loongarch_ld_seq_sa", Twine(1));

if (HasFeatureDiv32)
Builder.defineMacro("__loongarch_div32", Twine(1));

StringRef ABI = getABI();
if (ABI == "lp64d" || ABI == "lp64f" || ABI == "lp64s")
Builder.defineMacro("__loongarch_lp64");
Expand Down Expand Up @@ -320,8 +327,12 @@ bool LoongArchTargetInfo::handleTargetFeatures(
HasFeatureFrecipe = true;
else if (Feature == "+lam-bh")
HasFeatureLAM_BH = true;
else if (Feature == "+lamcas")
HasFeatureLAMCAS = true;
else if (Feature == "+ld-seq-sa")
HasFeatureLD_SEQ_SA = true;
else if (Feature == "+div32")
HasFeatureDiv32 = true;
}
return true;
}
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Basic/Targets/LoongArch.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ class LLVM_LIBRARY_VISIBILITY LoongArchTargetInfo : public TargetInfo {
bool HasFeatureLASX;
bool HasFeatureFrecipe;
bool HasFeatureLAM_BH;
bool HasFeatureLAMCAS;
bool HasFeatureLD_SEQ_SA;
bool HasFeatureDiv32;

public:
LoongArchTargetInfo(const llvm::Triple &Triple, const TargetOptions &)
Expand All @@ -42,7 +44,9 @@ class LLVM_LIBRARY_VISIBILITY LoongArchTargetInfo : public TargetInfo {
HasFeatureLASX = false;
HasFeatureFrecipe = false;
HasFeatureLAM_BH = false;
HasFeatureLAMCAS = false;
HasFeatureLD_SEQ_SA = false;
HasFeatureDiv32 = false;
LongDoubleWidth = 128;
LongDoubleAlign = 128;
LongDoubleFormat = &llvm::APFloat::IEEEquad();
Expand Down
65 changes: 47 additions & 18 deletions clang/lib/Basic/Targets/RISCV.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -216,11 +216,11 @@ void RISCVTargetInfo::getTargetDefines(const LangOptions &Opts,
if (ISAInfo->hasExtension("c"))
Builder.defineMacro("__riscv_compressed");

if (ISAInfo->hasExtension("zve32x")) {
if (ISAInfo->hasExtension("zve32x"))
Builder.defineMacro("__riscv_vector");
// Currently we support the v1.0 RISC-V V intrinsics.
Builder.defineMacro("__riscv_v_intrinsic", Twine(getVersionValue(1, 0)));
}

// Currently we support the v1.0 RISC-V V intrinsics.
Builder.defineMacro("__riscv_v_intrinsic", Twine(getVersionValue(1, 0)));

auto VScale = getVScaleRange(Opts);
if (VScale && VScale->first && VScale->first == VScale->second)
Expand Down Expand Up @@ -423,6 +423,24 @@ ParsedTargetAttr RISCVTargetInfo::parseTargetAttr(StringRef Features) const {
Features.split(AttrFeatures, ";");
bool FoundArch = false;

auto handleArchExtension = [](StringRef AttrString,
std::vector<std::string> &Features) {
SmallVector<StringRef, 1> Exts;
AttrString.split(Exts, ",");
for (auto Ext : Exts) {
if (Ext.empty())
continue;

StringRef ExtName = Ext.substr(1);
std::string TargetFeature =
llvm::RISCVISAInfo::getTargetFeatureForExtension(ExtName);
if (!TargetFeature.empty())
Features.push_back(Ext.front() + TargetFeature);
else
Features.push_back(Ext.str());
}
};

for (auto &Feature : AttrFeatures) {
Feature = Feature.trim();
StringRef AttrString = Feature.split("=").second.trim();
Expand All @@ -436,20 +454,7 @@ ParsedTargetAttr RISCVTargetInfo::parseTargetAttr(StringRef Features) const {

if (AttrString.starts_with("+")) {
// EXTENSION like arch=+v,+zbb
SmallVector<StringRef, 1> Exts;
AttrString.split(Exts, ",");
for (auto Ext : Exts) {
if (Ext.empty())
continue;

StringRef ExtName = Ext.substr(1);
std::string TargetFeature =
llvm::RISCVISAInfo::getTargetFeatureForExtension(ExtName);
if (!TargetFeature.empty())
Ret.Features.push_back(Ext.front() + TargetFeature);
else
Ret.Features.push_back(Ext.str());
}
handleArchExtension(AttrString, Ret.Features);
} else {
// full-arch-string like arch=rv64gcv
handleFullArchString(AttrString, Ret.Features);
Expand All @@ -475,11 +480,35 @@ ParsedTargetAttr RISCVTargetInfo::parseTargetAttr(StringRef Features) const {
Ret.Tune = AttrString;
} else if (Feature.starts_with("priority")) {
// Skip because it only use for FMV.
} else if (Feature.starts_with("+")) {
// Handle target_version/target_clones attribute strings
// that are already delimited by ','
handleArchExtension(Feature, Ret.Features);
}
}
return Ret;
}

unsigned RISCVTargetInfo::getFMVPriority(ArrayRef<StringRef> Features) const {
// Priority is explicitly specified on RISC-V unlike on other targets, where
// it is derived by all the features of a specific version. Therefore if a
// feature contains the priority string, then return it immediately.
for (StringRef Feature : Features) {
auto [LHS, RHS] = Feature.rsplit(';');
if (LHS.consume_front("priority="))
Feature = LHS;
else if (RHS.consume_front("priority="))
Feature = RHS;
else
continue;
unsigned Priority;
if (!Feature.getAsInteger(0, Priority))
return Priority;
}
// Default Priority is zero.
return 0;
}

TargetInfo::CallingConvCheckResult
RISCVTargetInfo::checkCallingConvention(CallingConv CC) const {
switch (CC) {
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Basic/Targets/RISCV.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ class RISCVTargetInfo : public TargetInfo {
void fillValidTuneCPUList(SmallVectorImpl<StringRef> &Values) const override;
bool supportsTargetAttributeTune() const override { return true; }
ParsedTargetAttr parseTargetAttr(StringRef Str) const override;
unsigned getFMVPriority(ArrayRef<StringRef> Features) const override;

std::pair<unsigned, unsigned> hardwareInterferenceSizes() const override {
return std::make_pair(32, 32);
Expand Down
33 changes: 20 additions & 13 deletions clang/lib/Basic/Targets/X86.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1364,19 +1364,26 @@ static llvm::X86::ProcessorFeatures getFeature(StringRef Name) {
// correct, so it asserts if the value is out of range.
}

unsigned X86TargetInfo::multiVersionSortPriority(StringRef Name) const {
// Valid CPUs have a 'key feature' that compares just better than its key
// feature.
using namespace llvm::X86;
CPUKind Kind = parseArchX86(Name);
if (Kind != CK_None) {
ProcessorFeatures KeyFeature = getKeyFeature(Kind);
return (getFeaturePriority(KeyFeature) << 1) + 1;
}

// Now we know we have a feature, so get its priority and shift it a few so
// that we have sufficient room for the CPUs (above).
return getFeaturePriority(getFeature(Name)) << 1;
unsigned X86TargetInfo::getFMVPriority(ArrayRef<StringRef> Features) const {
auto getPriority = [](StringRef Feature) -> unsigned {
// Valid CPUs have a 'key feature' that compares just better than its key
// feature.
using namespace llvm::X86;
CPUKind Kind = parseArchX86(Feature);
if (Kind != CK_None) {
ProcessorFeatures KeyFeature = getKeyFeature(Kind);
return (getFeaturePriority(KeyFeature) << 1) + 1;
}
// Now we know we have a feature, so get its priority and shift it a few so
// that we have sufficient room for the CPUs (above).
return getFeaturePriority(getFeature(Feature)) << 1;
};

unsigned Priority = 0;
for (StringRef Feature : Features)
if (!Feature.empty())
Priority = std::max(Priority, getPriority(Feature));
return Priority;
}

bool X86TargetInfo::validateCPUSpecificCPUDispatch(StringRef Name) const {
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Basic/Targets/X86.h
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,7 @@ class LLVM_LIBRARY_VISIBILITY X86TargetInfo : public TargetInfo {
return CPU != llvm::X86::CK_None;
}

unsigned multiVersionSortPriority(StringRef Name) const override;
unsigned getFMVPriority(ArrayRef<StringRef> Features) const override;

bool setFPMath(StringRef Name) override;

Expand Down
4 changes: 2 additions & 2 deletions clang/lib/CodeGen/ABIInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -218,8 +218,8 @@ void ABIInfo::appendAttributeMangling(StringRef AttrStr,
// only have "+" prefixes here.
assert(LHS.starts_with("+") && RHS.starts_with("+") &&
"Features should always have a prefix.");
return TI.multiVersionSortPriority(LHS.substr(1)) >
TI.multiVersionSortPriority(RHS.substr(1));
return TI.getFMVPriority({LHS.substr(1)}) >
TI.getFMVPriority({RHS.substr(1)});
});

bool IsFirst = true;
Expand Down
47 changes: 45 additions & 2 deletions clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -748,6 +748,18 @@ static Value *emitBuiltinWithOneOverloadedType(CodeGenFunction &CGF,
return CGF.Builder.CreateCall(F, Args, Name);
}

// Emit an intrinsic that has 4 operands of the same type as its result.
static Value *emitQuaternaryBuiltin(CodeGenFunction &CGF, const CallExpr *E,
unsigned IntrinsicID) {
llvm::Value *Src0 = CGF.EmitScalarExpr(E->getArg(0));
llvm::Value *Src1 = CGF.EmitScalarExpr(E->getArg(1));
llvm::Value *Src2 = CGF.EmitScalarExpr(E->getArg(2));
llvm::Value *Src3 = CGF.EmitScalarExpr(E->getArg(3));

Function *F = CGF.CGM.getIntrinsic(IntrinsicID, Src0->getType());
return CGF.Builder.CreateCall(F, {Src0, Src1, Src2, Src3});
}

// Emit an intrinsic that has 1 float or double operand, and 1 integer.
static Value *emitFPIntBuiltin(CodeGenFunction &CGF,
const CallExpr *E,
Expand Down Expand Up @@ -10847,6 +10859,10 @@ Value *CodeGenFunction::EmitAArch64SVEBuiltinExpr(unsigned BuiltinID,
else if (TypeFlags.isUndef())
return UndefValue::get(Ty);
else if (Builtin->LLVMIntrinsic != 0) {
// Emit set FPMR for intrinsics that require it
if (TypeFlags.setsFPMR())
Builder.CreateCall(CGM.getIntrinsic(Intrinsic::aarch64_set_fpmr),
Ops.pop_back_val());
if (TypeFlags.getMergeType() == SVETypeFlags::MergeZeroExp)
InsertExplicitZeroOperand(Builder, Ty, Ops);

Expand Down Expand Up @@ -19409,6 +19425,15 @@ case Builtin::BI__builtin_hlsl_elementwise_isinf: {
CGM.getHLSLRuntime().getRadiansIntrinsic(), ArrayRef<Value *>{Op0},
nullptr, "hlsl.radians");
}
case Builtin::BI__builtin_hlsl_buffer_update_counter: {
Value *ResHandle = EmitScalarExpr(E->getArg(0));
Value *Offset = EmitScalarExpr(E->getArg(1));
Value *OffsetI8 = Builder.CreateIntCast(Offset, Int8Ty, true);
return Builder.CreateIntrinsic(
/*ReturnType=*/Offset->getType(),
CGM.getHLSLRuntime().getBufferUpdateCounterIntrinsic(),
ArrayRef<Value *>{ResHandle, OffsetI8}, nullptr);
}
case Builtin::BI__builtin_hlsl_elementwise_splitdouble: {

assert((E->getArg(0)->getType()->hasFloatingRepresentation() &&
Expand Down Expand Up @@ -19697,8 +19722,11 @@ Value *CodeGenFunction::EmitAMDGPUBuiltinExpr(unsigned BuiltinID,
case AMDGPU::BI__builtin_amdgcn_global_load_tr_b128_v4bf16:
case AMDGPU::BI__builtin_amdgcn_global_load_tr_b128_v8i16:
case AMDGPU::BI__builtin_amdgcn_global_load_tr_b128_v8f16:
case AMDGPU::BI__builtin_amdgcn_global_load_tr_b128_v8bf16: {

case AMDGPU::BI__builtin_amdgcn_global_load_tr_b128_v8bf16:
case AMDGPU::BI__builtin_amdgcn_ds_read_tr4_b64_v2i32:
case AMDGPU::BI__builtin_amdgcn_ds_read_tr8_b64_v2i32:
case AMDGPU::BI__builtin_amdgcn_ds_read_tr6_b96_v3i32:
case AMDGPU::BI__builtin_amdgcn_ds_read_tr16_b64_v4i16: {
Intrinsic::ID IID;
switch (BuiltinID) {
case AMDGPU::BI__builtin_amdgcn_global_load_tr_b64_i32:
Expand All @@ -19713,6 +19741,18 @@ Value *CodeGenFunction::EmitAMDGPUBuiltinExpr(unsigned BuiltinID,
case AMDGPU::BI__builtin_amdgcn_global_load_tr_b128_v8bf16:
IID = Intrinsic::amdgcn_global_load_tr_b128;
break;
case AMDGPU::BI__builtin_amdgcn_ds_read_tr4_b64_v2i32:
IID = Intrinsic::amdgcn_ds_read_tr4_b64;
break;
case AMDGPU::BI__builtin_amdgcn_ds_read_tr8_b64_v2i32:
IID = Intrinsic::amdgcn_ds_read_tr8_b64;
break;
case AMDGPU::BI__builtin_amdgcn_ds_read_tr6_b96_v3i32:
IID = Intrinsic::amdgcn_ds_read_tr6_b96;
break;
case AMDGPU::BI__builtin_amdgcn_ds_read_tr16_b64_v4i16:
IID = Intrinsic::amdgcn_ds_read_tr16_b64;
break;
}
llvm::Type *LoadTy = ConvertType(E->getType());
llvm::Value *Addr = EmitScalarExpr(E->getArg(0));
Expand Down Expand Up @@ -20226,6 +20266,9 @@ Value *CodeGenFunction::EmitAMDGPUBuiltinExpr(unsigned BuiltinID,
Builder.CreateInsertElement(Insert0, Elt1, UINT64_C(1));
return AsVector;
}
case AMDGPU::BI__builtin_amdgcn_bitop3_b32:
case AMDGPU::BI__builtin_amdgcn_bitop3_b16:
return emitQuaternaryBuiltin(*this, E, Intrinsic::amdgcn_bitop3);
case AMDGPU::BI__builtin_amdgcn_make_buffer_rsrc:
return emitBuiltinWithOneOverloadedType<4>(
*this, E, Intrinsic::amdgcn_make_buffer_rsrc);
Expand Down
20 changes: 13 additions & 7 deletions clang/lib/CodeGen/CGCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1314,10 +1314,10 @@ static llvm::Value *CreateCoercedLoad(Address Src, llvm::Type *Ty,
}
if (ScalableDstTy->getElementType() == FixedSrcTy->getElementType()) {
auto *Load = CGF.Builder.CreateLoad(Src);
auto *UndefVec = llvm::UndefValue::get(ScalableDstTy);
auto *PoisonVec = llvm::PoisonValue::get(ScalableDstTy);
auto *Zero = llvm::Constant::getNullValue(CGF.CGM.Int64Ty);
llvm::Value *Result = CGF.Builder.CreateInsertVector(
ScalableDstTy, UndefVec, Load, Zero, "cast.scalable");
ScalableDstTy, PoisonVec, Load, Zero, "cast.scalable");
if (ScalableDstTy != Ty)
Result = CGF.Builder.CreateBitCast(Result, Ty);
return Result;
Expand Down Expand Up @@ -5111,9 +5111,10 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,

// Some architectures (such as x86-64) have the ABI changed based on
// attribute-target/features. Give them a chance to diagnose.
CGM.getTargetCodeGenInfo().checkFunctionCallABI(
CGM, Loc, dyn_cast_or_null<FunctionDecl>(CurCodeDecl),
dyn_cast_or_null<FunctionDecl>(TargetDecl), CallArgs, RetTy);
const FunctionDecl *CallerDecl = dyn_cast_or_null<FunctionDecl>(CurCodeDecl);
const FunctionDecl *CalleeDecl = dyn_cast_or_null<FunctionDecl>(TargetDecl);
CGM.getTargetCodeGenInfo().checkFunctionCallABI(CGM, Loc, CallerDecl,
CalleeDecl, CallArgs, RetTy);

// 1. Set up the arguments.

Expand Down Expand Up @@ -5688,7 +5689,10 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
Attrs = Attrs.addFnAttribute(getLLVMContext(), llvm::Attribute::NoInline);

// Add call-site always_inline attribute if exists.
if (InAlwaysInlineAttributedStmt)
// Note: This corresponds to the [[clang::always_inline]] statement attribute.
if (InAlwaysInlineAttributedStmt &&
!CGM.getTargetCodeGenInfo().wouldInliningViolateFunctionCallABI(
CallerDecl, CalleeDecl))
Attrs =
Attrs.addFnAttribute(getLLVMContext(), llvm::Attribute::AlwaysInline);

Expand All @@ -5704,7 +5708,9 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
// FIXME: should this really take priority over __try, below?
if (CurCodeDecl && CurCodeDecl->hasAttr<FlattenAttr>() &&
!InNoInlineAttributedStmt &&
!(TargetDecl && TargetDecl->hasAttr<NoInlineAttr>())) {
!(TargetDecl && TargetDecl->hasAttr<NoInlineAttr>()) &&
!CGM.getTargetCodeGenInfo().wouldInliningViolateFunctionCallABI(
CallerDecl, CalleeDecl)) {
Attrs =
Attrs.addFnAttribute(getLLVMContext(), llvm::Attribute::AlwaysInline);
}
Expand Down
19 changes: 10 additions & 9 deletions clang/lib/CodeGen/CGExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3905,9 +3905,11 @@ void CodeGenFunction::EmitTrapCheck(llvm::Value *Checked,

llvm::BasicBlock *&TrapBB = TrapBBs[CheckHandlerID];

if (!ClSanitizeDebugDeoptimization &&
CGM.getCodeGenOpts().OptimizationLevel && TrapBB &&
(!CurCodeDecl || !CurCodeDecl->hasAttr<OptimizeNoneAttr>())) {
bool NoMerge = ClSanitizeDebugDeoptimization ||
!CGM.getCodeGenOpts().OptimizationLevel ||
(CurCodeDecl && CurCodeDecl->hasAttr<OptimizeNoneAttr>());

if (TrapBB && !NoMerge) {
auto Call = TrapBB->begin();
assert(isa<llvm::CallInst>(Call) && "Expected call in trap BB");

Expand All @@ -3919,18 +3921,17 @@ void CodeGenFunction::EmitTrapCheck(llvm::Value *Checked,
Builder.CreateCondBr(Checked, Cont, TrapBB);
EmitBlock(TrapBB);

llvm::CallInst *TrapCall = Builder.CreateCall(
CGM.getIntrinsic(llvm::Intrinsic::ubsantrap),
llvm::ConstantInt::get(CGM.Int8Ty,
ClSanitizeDebugDeoptimization
? TrapBB->getParent()->size()
: static_cast<uint64_t>(CheckHandlerID)));
llvm::CallInst *TrapCall =
Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::ubsantrap),
llvm::ConstantInt::get(CGM.Int8Ty, CheckHandlerID));

if (!CGM.getCodeGenOpts().TrapFuncName.empty()) {
auto A = llvm::Attribute::get(getLLVMContext(), "trap-func-name",
CGM.getCodeGenOpts().TrapFuncName);
TrapCall->addFnAttr(A);
}
if (NoMerge)
TrapCall->addFnAttr(llvm::Attribute::NoMerge);
TrapCall->setDoesNotReturn();
TrapCall->setDoesNotThrow();
Builder.CreateUnreachable();
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/CodeGen/CGHLSLRuntime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,10 @@ llvm::Value *CGHLSLRuntime::emitInputSemantic(IRBuilder<> &B,
CGM.getIntrinsic(getThreadIdIntrinsic());
return buildVectorInput(B, ThreadIDIntrinsic, Ty);
}
if (D.hasAttr<HLSLSV_GroupIDAttr>()) {
llvm::Function *GroupIDIntrinsic = CGM.getIntrinsic(Intrinsic::dx_group_id);
return buildVectorInput(B, GroupIDIntrinsic, Ty);
}
assert(false && "Unhandled parameter attribute");
return nullptr;
}
Expand Down
1 change: 1 addition & 0 deletions clang/lib/CodeGen/CGHLSLRuntime.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ class CGHLSLRuntime {
GENERATE_HLSL_INTRINSIC_FUNCTION(UClamp, uclamp)

GENERATE_HLSL_INTRINSIC_FUNCTION(CreateHandleFromBinding, handle_fromBinding)
GENERATE_HLSL_INTRINSIC_FUNCTION(BufferUpdateCounter, bufferUpdateCounter)

//===----------------------------------------------------------------------===//
// End of reserved area for HLSL intrinsic getters.
Expand Down
18 changes: 12 additions & 6 deletions clang/lib/CodeGen/CGOpenMPRuntime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4666,7 +4666,7 @@ void CGOpenMPRuntime::emitTaskLoopCall(CodeGenFunction &CGF, SourceLocation Loc,
CGF.getContext().VoidPtrTy);
}
enum { NoSchedule = 0, Grainsize = 1, NumTasks = 2 };
llvm::Value *TaskArgs[] = {
llvm::SmallVector<llvm::Value *, 12> TaskArgs{
UpLoc,
ThreadID,
Result.NewTask,
Expand All @@ -4683,12 +4683,18 @@ void CGOpenMPRuntime::emitTaskLoopCall(CodeGenFunction &CGF, SourceLocation Loc,
Data.Schedule.getPointer()
? CGF.Builder.CreateIntCast(Data.Schedule.getPointer(), CGF.Int64Ty,
/*isSigned=*/false)
: llvm::ConstantInt::get(CGF.Int64Ty, /*V=*/0),
Result.TaskDupFn ? CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
Result.TaskDupFn, CGF.VoidPtrTy)
: llvm::ConstantPointerNull::get(CGF.VoidPtrTy)};
: llvm::ConstantInt::get(CGF.Int64Ty, /*V=*/0)};
if (Data.HasModifier)
TaskArgs.push_back(llvm::ConstantInt::get(CGF.Int32Ty, 1));

TaskArgs.push_back(Result.TaskDupFn
? CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(
Result.TaskDupFn, CGF.VoidPtrTy)
: llvm::ConstantPointerNull::get(CGF.VoidPtrTy));
CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction(
CGM.getModule(), OMPRTL___kmpc_taskloop),
CGM.getModule(), Data.HasModifier
? OMPRTL___kmpc_taskloop_5
: OMPRTL___kmpc_taskloop),
TaskArgs);
}

Expand Down
1 change: 1 addition & 0 deletions clang/lib/CodeGen/CGOpenMPRuntime.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ struct OMPTaskDataTy final {
bool IsReductionWithTaskMod = false;
bool IsWorksharingReduction = false;
bool HasNowaitClause = false;
bool HasModifier = false;
};

/// Class intended to support codegen of all kind of the reduction clauses.
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/CodeGen/CGStmtOpenMP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7831,10 +7831,14 @@ void CodeGenFunction::EmitOMPTaskLoopBasedDirective(const OMPLoopDirective &S) {
// grainsize clause
Data.Schedule.setInt(/*IntVal=*/false);
Data.Schedule.setPointer(EmitScalarExpr(Clause->getGrainsize()));
Data.HasModifier =
(Clause->getModifier() == OMPC_GRAINSIZE_strict) ? true : false;
} else if (const auto *Clause = S.getSingleClause<OMPNumTasksClause>()) {
// num_tasks clause
Data.Schedule.setInt(/*IntVal=*/true);
Data.Schedule.setPointer(EmitScalarExpr(Clause->getNumTasks()));
Data.HasModifier =
(Clause->getModifier() == OMPC_NUMTASKS_strict) ? true : false;
}

auto &&BodyGen = [CS, &S](CodeGenFunction &CGF, PrePostActionTy &) {
Expand Down
109 changes: 38 additions & 71 deletions clang/lib/CodeGen/CodeGenFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2828,23 +2828,17 @@ void CodeGenFunction::EmitKCFIOperandBundle(
Bundles.emplace_back("kcfi", CGM.CreateKCFITypeId(FP->desugar()));
}

llvm::Value *CodeGenFunction::FormAArch64ResolverCondition(
const MultiVersionResolverOption &RO) {
llvm::SmallVector<StringRef, 8> CondFeatures;
for (const StringRef &Feature : RO.Conditions.Features)
CondFeatures.push_back(Feature);
if (!CondFeatures.empty()) {
return EmitAArch64CpuSupports(CondFeatures);
}
return nullptr;
llvm::Value *
CodeGenFunction::FormAArch64ResolverCondition(const FMVResolverOption &RO) {
return RO.Features.empty() ? nullptr : EmitAArch64CpuSupports(RO.Features);
}

llvm::Value *CodeGenFunction::FormX86ResolverCondition(
const MultiVersionResolverOption &RO) {
llvm::Value *
CodeGenFunction::FormX86ResolverCondition(const FMVResolverOption &RO) {
llvm::Value *Condition = nullptr;

if (!RO.Conditions.Architecture.empty()) {
StringRef Arch = RO.Conditions.Architecture;
if (RO.Architecture) {
StringRef Arch = *RO.Architecture;
// If arch= specifies an x86-64 micro-architecture level, test the feature
// with __builtin_cpu_supports, otherwise use __builtin_cpu_is.
if (Arch.starts_with("x86-64"))
Expand All @@ -2853,8 +2847,8 @@ llvm::Value *CodeGenFunction::FormX86ResolverCondition(
Condition = EmitX86CpuIs(Arch);
}

if (!RO.Conditions.Features.empty()) {
llvm::Value *FeatureCond = EmitX86CpuSupports(RO.Conditions.Features);
if (!RO.Features.empty()) {
llvm::Value *FeatureCond = EmitX86CpuSupports(RO.Features);
Condition =
Condition ? Builder.CreateAnd(Condition, FeatureCond) : FeatureCond;
}
Expand Down Expand Up @@ -2884,7 +2878,7 @@ static void CreateMultiVersionResolverReturn(CodeGenModule &CGM,
}

void CodeGenFunction::EmitMultiVersionResolver(
llvm::Function *Resolver, ArrayRef<MultiVersionResolverOption> Options) {
llvm::Function *Resolver, ArrayRef<FMVResolverOption> Options) {

llvm::Triple::ArchType ArchType =
getContext().getTargetInfo().getTriple().getArch();
Expand All @@ -2907,26 +2901,8 @@ void CodeGenFunction::EmitMultiVersionResolver(
}
}

static unsigned getPriorityFromAttrString(StringRef AttrStr) {
SmallVector<StringRef, 8> Attrs;

AttrStr.split(Attrs, ';');

// Default Priority is zero.
unsigned Priority = 0;
for (auto Attr : Attrs) {
if (Attr.consume_front("priority=")) {
unsigned Result;
if (!Attr.getAsInteger(0, Result))
Priority = Result;
}
}

return Priority;
}

void CodeGenFunction::EmitRISCVMultiVersionResolver(
llvm::Function *Resolver, ArrayRef<MultiVersionResolverOption> Options) {
llvm::Function *Resolver, ArrayRef<FMVResolverOption> Options) {

if (getContext().getTargetInfo().getTriple().getOS() !=
llvm::Triple::OSType::Linux) {
Expand All @@ -2942,36 +2918,17 @@ void CodeGenFunction::EmitRISCVMultiVersionResolver(
bool HasDefault = false;
unsigned DefaultIndex = 0;

SmallVector<CodeGenFunction::MultiVersionResolverOption, 10> CurrOptions(
Options);

llvm::stable_sort(
CurrOptions, [](const CodeGenFunction::MultiVersionResolverOption &LHS,
const CodeGenFunction::MultiVersionResolverOption &RHS) {
return getPriorityFromAttrString(LHS.Conditions.Features[0]) >
getPriorityFromAttrString(RHS.Conditions.Features[0]);
});

// Check the each candidate function.
for (unsigned Index = 0; Index < CurrOptions.size(); Index++) {
for (unsigned Index = 0; Index < Options.size(); Index++) {

if (CurrOptions[Index].Conditions.Features[0].starts_with("default")) {
if (Options[Index].Features.empty()) {
HasDefault = true;
DefaultIndex = Index;
continue;
}

Builder.SetInsertPoint(CurBlock);

std::vector<std::string> TargetAttrFeats =
getContext()
.getTargetInfo()
.parseTargetAttr(CurrOptions[Index].Conditions.Features[0])
.Features;

if (TargetAttrFeats.empty())
continue;

// FeaturesCondition: The bitmask of the required extension has been
// enabled by the runtime object.
// (__riscv_feature_bits.features[i] & REQUIRED_BITMASK) ==
Expand All @@ -2994,20 +2951,32 @@ void CodeGenFunction::EmitRISCVMultiVersionResolver(
// Without checking the length first, we may access an incorrect memory
// address when using different versions.
llvm::SmallVector<StringRef, 8> CurrTargetAttrFeats;
llvm::SmallVector<std::string, 8> TargetAttrFeats;

for (auto &Feat : TargetAttrFeats) {
StringRef CurrFeat = Feat;
if (CurrFeat.starts_with('+'))
CurrTargetAttrFeats.push_back(CurrFeat.substr(1));
for (StringRef Feat : Options[Index].Features) {
std::vector<std::string> FeatStr =
getContext().getTargetInfo().parseTargetAttr(Feat).Features;

assert(FeatStr.size() == 1 && "Feature string not delimited");

std::string &CurrFeat = FeatStr.front();
if (CurrFeat[0] == '+')
TargetAttrFeats.push_back(CurrFeat.substr(1));
}

if (TargetAttrFeats.empty())
continue;

for (std::string &Feat : TargetAttrFeats)
CurrTargetAttrFeats.push_back(Feat);

Builder.SetInsertPoint(CurBlock);
llvm::Value *FeatsCondition = EmitRISCVCpuSupports(CurrTargetAttrFeats);

llvm::BasicBlock *RetBlock = createBasicBlock("resolver_return", Resolver);
CGBuilderTy RetBuilder(*this, RetBlock);
CreateMultiVersionResolverReturn(
CGM, Resolver, RetBuilder, CurrOptions[Index].Function, SupportsIFunc);
CreateMultiVersionResolverReturn(CGM, Resolver, RetBuilder,
Options[Index].Function, SupportsIFunc);
llvm::BasicBlock *ElseBlock = createBasicBlock("resolver_else", Resolver);

Builder.SetInsertPoint(CurBlock);
Expand All @@ -3019,9 +2988,8 @@ void CodeGenFunction::EmitRISCVMultiVersionResolver(
// Finally, emit the default one.
if (HasDefault) {
Builder.SetInsertPoint(CurBlock);
CreateMultiVersionResolverReturn(CGM, Resolver, Builder,
CurrOptions[DefaultIndex].Function,
SupportsIFunc);
CreateMultiVersionResolverReturn(
CGM, Resolver, Builder, Options[DefaultIndex].Function, SupportsIFunc);
return;
}

Expand All @@ -3035,17 +3003,16 @@ void CodeGenFunction::EmitRISCVMultiVersionResolver(
}

void CodeGenFunction::EmitAArch64MultiVersionResolver(
llvm::Function *Resolver, ArrayRef<MultiVersionResolverOption> Options) {
llvm::Function *Resolver, ArrayRef<FMVResolverOption> Options) {
assert(!Options.empty() && "No multiversion resolver options found");
assert(Options.back().Conditions.Features.size() == 0 &&
"Default case must be last");
assert(Options.back().Features.size() == 0 && "Default case must be last");
bool SupportsIFunc = getContext().getTargetInfo().supportsIFunc();
assert(SupportsIFunc &&
"Multiversion resolver requires target IFUNC support");
bool AArch64CpuInitialized = false;
llvm::BasicBlock *CurBlock = createBasicBlock("resolver_entry", Resolver);

for (const MultiVersionResolverOption &RO : Options) {
for (const FMVResolverOption &RO : Options) {
Builder.SetInsertPoint(CurBlock);
llvm::Value *Condition = FormAArch64ResolverCondition(RO);

Expand Down Expand Up @@ -3081,7 +3048,7 @@ void CodeGenFunction::EmitAArch64MultiVersionResolver(
}

void CodeGenFunction::EmitX86MultiVersionResolver(
llvm::Function *Resolver, ArrayRef<MultiVersionResolverOption> Options) {
llvm::Function *Resolver, ArrayRef<FMVResolverOption> Options) {

bool SupportsIFunc = getContext().getTargetInfo().supportsIFunc();

Expand All @@ -3090,7 +3057,7 @@ void CodeGenFunction::EmitX86MultiVersionResolver(
Builder.SetInsertPoint(CurBlock);
EmitX86CpuInit();

for (const MultiVersionResolverOption &RO : Options) {
for (const FMVResolverOption &RO : Options) {
Builder.SetInsertPoint(CurBlock);
llvm::Value *Condition = FormX86ResolverCondition(RO);

Expand Down
39 changes: 15 additions & 24 deletions clang/lib/CodeGen/CodeGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -5334,35 +5334,27 @@ class CodeGenFunction : public CodeGenTypeCache {

void EmitSanitizerStatReport(llvm::SanitizerStatKind SSK);

struct MultiVersionResolverOption {
struct FMVResolverOption {
llvm::Function *Function;
struct Conds {
StringRef Architecture;
llvm::SmallVector<StringRef, 8> Features;
llvm::SmallVector<StringRef, 8> Features;
std::optional<StringRef> Architecture;

Conds(StringRef Arch, ArrayRef<StringRef> Feats)
: Architecture(Arch), Features(Feats) {}
} Conditions;

MultiVersionResolverOption(llvm::Function *F, StringRef Arch,
ArrayRef<StringRef> Feats)
: Function(F), Conditions(Arch, Feats) {}
FMVResolverOption(llvm::Function *F, ArrayRef<StringRef> Feats,
std::optional<StringRef> Arch = std::nullopt)
: Function(F), Features(Feats), Architecture(Arch) {}
};

// Emits the body of a multiversion function's resolver. Assumes that the
// options are already sorted in the proper order, with the 'default' option
// last (if it exists).
void EmitMultiVersionResolver(llvm::Function *Resolver,
ArrayRef<MultiVersionResolverOption> Options);
void
EmitX86MultiVersionResolver(llvm::Function *Resolver,
ArrayRef<MultiVersionResolverOption> Options);
void
EmitAArch64MultiVersionResolver(llvm::Function *Resolver,
ArrayRef<MultiVersionResolverOption> Options);
void
EmitRISCVMultiVersionResolver(llvm::Function *Resolver,
ArrayRef<MultiVersionResolverOption> Options);
ArrayRef<FMVResolverOption> Options);
void EmitX86MultiVersionResolver(llvm::Function *Resolver,
ArrayRef<FMVResolverOption> Options);
void EmitAArch64MultiVersionResolver(llvm::Function *Resolver,
ArrayRef<FMVResolverOption> Options);
void EmitRISCVMultiVersionResolver(llvm::Function *Resolver,
ArrayRef<FMVResolverOption> Options);

private:
QualType getVarArgType(const Expr *Arg);
Expand All @@ -5381,10 +5373,9 @@ class CodeGenFunction : public CodeGenTypeCache {
llvm::Value *EmitX86CpuSupports(ArrayRef<StringRef> FeatureStrs);
llvm::Value *EmitX86CpuSupports(std::array<uint32_t, 4> FeatureMask);
llvm::Value *EmitX86CpuInit();
llvm::Value *FormX86ResolverCondition(const MultiVersionResolverOption &RO);
llvm::Value *FormX86ResolverCondition(const FMVResolverOption &RO);
llvm::Value *EmitAArch64CpuInit();
llvm::Value *
FormAArch64ResolverCondition(const MultiVersionResolverOption &RO);
llvm::Value *FormAArch64ResolverCondition(const FMVResolverOption &RO);
llvm::Value *EmitAArch64CpuSupports(const CallExpr *E);
llvm::Value *EmitAArch64CpuSupports(ArrayRef<StringRef> FeatureStrs);
};
Expand Down
107 changes: 47 additions & 60 deletions clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2047,6 +2047,15 @@ StringRef CodeGenModule::getMangledName(GlobalDecl GD) {
GD.getWithKernelReferenceKind(KernelReferenceKind::Kernel),
ND));

// This invariant should hold true in the future.
// Prior work:
// https://discourse.llvm.org/t/rfc-clang-diagnostic-for-demangling-failures/82835/8
// https://github.com/llvm/llvm-project/issues/111345
// assert((MangledName.startswith("_Z") || MangledName.startswith("?")) &&
// !GD->hasAttr<AsmLabelAttr>() &&
// llvm::demangle(MangledName) != MangledName &&
// "LLVM demangler must demangle clang-generated names");

auto Result = Manglings.insert(std::make_pair(MangledName, GD));
return MangledDeclNames[CanonicalGD] = Result.first->first();
}
Expand Down Expand Up @@ -4214,23 +4223,12 @@ void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD, llvm::GlobalValue *GV) {
static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old,
llvm::Function *NewFn);

static unsigned
TargetMVPriority(const TargetInfo &TI,
const CodeGenFunction::MultiVersionResolverOption &RO) {
unsigned Priority = 0;
unsigned NumFeatures = 0;
for (StringRef Feat : RO.Conditions.Features) {
Priority = std::max(Priority, TI.multiVersionSortPriority(Feat));
NumFeatures++;
}

if (!RO.Conditions.Architecture.empty())
Priority = std::max(
Priority, TI.multiVersionSortPriority(RO.Conditions.Architecture));

Priority += TI.multiVersionFeatureCost() * NumFeatures;

return Priority;
static unsigned getFMVPriority(const TargetInfo &TI,
const CodeGenFunction::FMVResolverOption &RO) {
llvm::SmallVector<StringRef, 8> Features{RO.Features};
if (RO.Architecture)
Features.push_back(*RO.Architecture);
return TI.getFMVPriority(Features);
}

// Multiversion functions should be at most 'WeakODRLinkage' so that a different
Expand Down Expand Up @@ -4276,28 +4274,25 @@ void CodeGenModule::emitMultiVersionFunctions() {
// target_version("default")) or target_clones() is present and defined
// in this TU. For other architectures it is always emitted.
bool ShouldEmitResolver = !getTarget().getTriple().isAArch64();
SmallVector<CodeGenFunction::MultiVersionResolverOption, 10> Options;
SmallVector<CodeGenFunction::FMVResolverOption, 10> Options;

getContext().forEachMultiversionedFunctionVersion(
FD, [&](const FunctionDecl *CurFD) {
llvm::SmallVector<StringRef, 8> Feats;
bool IsDefined = CurFD->doesThisDeclarationHaveABody();

if (const auto *TA = CurFD->getAttr<TargetAttr>()) {
TA->getAddedFeatures(Feats);
assert(getTarget().getTriple().isX86() && "Unsupported target");
TA->getX86AddedFeatures(Feats);
llvm::Function *Func = createFunction(CurFD);
Options.emplace_back(Func, TA->getArchitecture(), Feats);
Options.emplace_back(Func, Feats, TA->getX86Architecture());
} else if (const auto *TVA = CurFD->getAttr<TargetVersionAttr>()) {
if (TVA->isDefaultVersion() && IsDefined)
ShouldEmitResolver = true;
llvm::Function *Func = createFunction(CurFD);
if (getTarget().getTriple().isRISCV()) {
Feats.push_back(TVA->getName());
} else {
assert(getTarget().getTriple().isAArch64());
TVA->getFeatures(Feats);
}
Options.emplace_back(Func, /*Architecture*/ "", Feats);
char Delim = getTarget().getTriple().isAArch64() ? '+' : ',';
TVA->getFeatures(Feats, Delim);
Options.emplace_back(Func, Feats);
} else if (const auto *TC = CurFD->getAttr<TargetClonesAttr>()) {
if (IsDefined)
ShouldEmitResolver = true;
Expand All @@ -4306,21 +4301,15 @@ void CodeGenModule::emitMultiVersionFunctions() {
continue;

llvm::Function *Func = createFunction(CurFD, I);
StringRef Architecture;
Feats.clear();
if (getTarget().getTriple().isAArch64())
TC->getFeatures(Feats, I);
else if (getTarget().getTriple().isRISCV()) {
StringRef Version = TC->getFeatureStr(I);
Feats.push_back(Version);
if (getTarget().getTriple().isX86()) {
TC->getX86Feature(Feats, I);
Options.emplace_back(Func, Feats, TC->getX86Architecture(I));
} else {
StringRef Version = TC->getFeatureStr(I);
if (Version.starts_with("arch="))
Architecture = Version.drop_front(sizeof("arch=") - 1);
else if (Version != "default")
Feats.push_back(Version);
char Delim = getTarget().getTriple().isAArch64() ? '+' : ',';
TC->getFeatures(Feats, I, Delim);
Options.emplace_back(Func, Feats);
}
Options.emplace_back(Func, Architecture, Feats);
}
} else
llvm_unreachable("unexpected MultiVersionKind");
Expand Down Expand Up @@ -4359,9 +4348,9 @@ void CodeGenModule::emitMultiVersionFunctions() {

const TargetInfo &TI = getTarget();
llvm::stable_sort(
Options, [&TI](const CodeGenFunction::MultiVersionResolverOption &LHS,
const CodeGenFunction::MultiVersionResolverOption &RHS) {
return TargetMVPriority(TI, LHS) > TargetMVPriority(TI, RHS);
Options, [&TI](const CodeGenFunction::FMVResolverOption &LHS,
const CodeGenFunction::FMVResolverOption &RHS) {
return getFMVPriority(TI, LHS) > getFMVPriority(TI, RHS);
});
CodeGenFunction CGF(*this);
CGF.EmitMultiVersionResolver(ResolverFunc, Options);
Expand Down Expand Up @@ -4420,7 +4409,7 @@ void CodeGenModule::emitCPUDispatchDefinition(GlobalDecl GD) {
ResolverFunc->setComdat(
getModule().getOrInsertComdat(ResolverFunc->getName()));

SmallVector<CodeGenFunction::MultiVersionResolverOption, 10> Options;
SmallVector<CodeGenFunction::FMVResolverOption, 10> Options;
const TargetInfo &Target = getTarget();
unsigned Index = 0;
for (const IdentifierInfo *II : DD->cpus()) {
Expand Down Expand Up @@ -4454,25 +4443,23 @@ void CodeGenModule::emitCPUDispatchDefinition(GlobalDecl GD) {
llvm::erase_if(Features, [&Target](StringRef Feat) {
return !Target.validateCpuSupports(Feat);
});
Options.emplace_back(cast<llvm::Function>(Func), StringRef{}, Features);
Options.emplace_back(cast<llvm::Function>(Func), Features);
++Index;
}

llvm::stable_sort(
Options, [](const CodeGenFunction::MultiVersionResolverOption &LHS,
const CodeGenFunction::MultiVersionResolverOption &RHS) {
return llvm::X86::getCpuSupportsMask(LHS.Conditions.Features) >
llvm::X86::getCpuSupportsMask(RHS.Conditions.Features);
});
llvm::stable_sort(Options, [](const CodeGenFunction::FMVResolverOption &LHS,
const CodeGenFunction::FMVResolverOption &RHS) {
return llvm::X86::getCpuSupportsMask(LHS.Features) >
llvm::X86::getCpuSupportsMask(RHS.Features);
});

// If the list contains multiple 'default' versions, such as when it contains
// 'pentium' and 'generic', don't emit the call to the generic one (since we
// always run on at least a 'pentium'). We do this by deleting the 'least
// advanced' (read, lowest mangling letter).
while (Options.size() > 1 &&
llvm::all_of(llvm::X86::getCpuSupportsMask(
(Options.end() - 2)->Conditions.Features),
[](auto X) { return X == 0; })) {
while (Options.size() > 1 && llvm::all_of(llvm::X86::getCpuSupportsMask(
(Options.end() - 2)->Features),
[](auto X) { return X == 0; })) {
StringRef LHSName = (Options.end() - 2)->Function->getName();
StringRef RHSName = (Options.end() - 1)->Function->getName();
if (LHSName.compare(RHSName) < 0)
Expand Down Expand Up @@ -4553,15 +4540,17 @@ llvm::Constant *CodeGenModule::GetOrCreateMultiVersionResolver(GlobalDecl GD) {
ResolverName += ".resolver";
}

bool ShouldReturnIFunc =
getTarget().supportsIFunc() && !FD->isCPUSpecificMultiVersion();

// If the resolver has already been created, just return it. This lookup may
// yield a function declaration instead of a resolver on AArch64. That is
// because we didn't know whether a resolver will be generated when we first
// encountered a use of the symbol named after this resolver. Therefore,
// targets which support ifuncs should not return here unless we actually
// found an ifunc.
llvm::GlobalValue *ResolverGV = GetGlobalValue(ResolverName);
if (ResolverGV &&
(isa<llvm::GlobalIFunc>(ResolverGV) || !getTarget().supportsIFunc()))
if (ResolverGV && (isa<llvm::GlobalIFunc>(ResolverGV) || !ShouldReturnIFunc))
return ResolverGV;

const CGFunctionInfo &FI = getTypes().arrangeGlobalDeclaration(GD);
Expand All @@ -4574,7 +4563,7 @@ llvm::Constant *CodeGenModule::GetOrCreateMultiVersionResolver(GlobalDecl GD) {

// For cpu_specific, don't create an ifunc yet because we don't know if the
// cpu_dispatch will be emitted in this translation unit.
if (getTarget().supportsIFunc() && !FD->isCPUSpecificMultiVersion()) {
if (ShouldReturnIFunc) {
unsigned AS = getTypes().getTargetAddressSpace(FD->getType());
llvm::Type *ResolverType =
llvm::FunctionType::get(llvm::PointerType::get(DeclTy, AS), false);
Expand All @@ -4593,11 +4582,9 @@ llvm::Constant *CodeGenModule::GetOrCreateMultiVersionResolver(GlobalDecl GD) {

llvm::Constant *Resolver = GetOrCreateLLVMFunction(
ResolverName, DeclTy, GlobalDecl{}, /*ForVTable=*/false);
assert(isa<llvm::GlobalValue>(Resolver) &&
assert(isa<llvm::GlobalValue>(Resolver) && !ResolverGV &&
"Resolver should be created for the first time");
SetCommonAttributes(FD, cast<llvm::GlobalValue>(Resolver));
if (ResolverGV)
replaceDeclarationWith(ResolverGV, Resolver);
return Resolver;
}

Expand Down
18 changes: 18 additions & 0 deletions clang/lib/CodeGen/TargetInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,24 @@ class TargetCodeGenInfo {
const CallArgList &Args,
QualType ReturnType) const {}

/// Returns true if inlining the function call would produce incorrect code
/// for the current target and should be ignored (even with the always_inline
/// or flatten attributes).
///
/// Note: This probably should be handled in LLVM. However, the LLVM
/// `alwaysinline` attribute currently means the inliner will ignore
/// mismatched attributes (which sometimes can generate invalid code). So,
/// this hook allows targets to avoid adding the LLVM `alwaysinline` attribute
/// based on C/C++ attributes or other target-specific reasons.
///
/// See previous discussion here:
/// https://discourse.llvm.org/t/rfc-avoid-inlining-alwaysinline-functions-when-they-cannot-be-inlined/79528
virtual bool
wouldInliningViolateFunctionCallABI(const FunctionDecl *Caller,
const FunctionDecl *Callee) const {
return false;
}

/// Determines the size of struct _Unwind_Exception on this platform,
/// in 8-bit units. The Itanium ABI defines this as:
/// struct _Unwind_Exception {
Expand Down
Loading