15 changes: 10 additions & 5 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -10269,6 +10269,11 @@ def warn_depr_array_comparison : Warning<
"to compare array addresses, use unary '+' to decay operands to pointers">,
InGroup<DeprecatedArrayCompare>;

def warn_array_comparison : Warning<
"comparison between two arrays compare their addresses and will be deprecated in c++20; "
"to compare array addresses, use unary '+' to decay operands to pointers">,
InGroup<DiagGroup<"array-compare">>;

def warn_stringcompare : Warning<
"result of comparison against %select{a string literal|@encode}0 is "
"unspecified (use an explicit string comparison function instead)">,
Expand Down Expand Up @@ -12733,19 +12738,19 @@ def err_acc_size_expr_value
"OpenACC 'tile' clause size expression must be %select{an asterisk "
"or a constant expression|positive integer value, evaluated to %1}0">;
def err_acc_invalid_in_loop
: Error<"%select{OpenACC '%2' construct|while loop|do loop}0 cannot appear "
"in intervening code of a 'loop' with a '%1' clause">;
: Error<"%select{OpenACC '%3' construct|while loop|do loop}0 cannot appear "
"in intervening code of a '%1' with a '%2' clause">;
def note_acc_active_clause_here
: Note<"active '%0' clause defined here">;
def err_acc_clause_multiple_loops
: Error<"more than one for-loop in a loop associated with OpenACC 'loop' "
"construct with a '%select{collapse|tile}0' clause">;
: Error<"more than one for-loop in a loop associated with OpenACC '%0' "
"construct with a '%1' clause">;
def err_acc_insufficient_loops
: Error<"'%0' clause specifies a loop count greater than the number "
"of available loops">;
def err_acc_intervening_code
: Error<"inner loops must be tightly nested inside a '%0' clause on "
"a 'loop' construct">;
"a '%1' construct">;
def err_acc_gang_multiple_elt
: Error<"OpenACC 'gang' clause may have at most one %select{unnamed or "
"'num'|'dim'|'static'}0 argument">;
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Basic/Features.def
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,8 @@ FEATURE(c_atomic, LangOpts.C11)
FEATURE(c_generic_selections, LangOpts.C11)
FEATURE(c_static_assert, LangOpts.C11)
FEATURE(c_thread_local, LangOpts.C11 &&PP.getTargetInfo().isTLSSupported())
// C23 features
FEATURE(c_fixed_enum, LangOpts.C23)
// C++11 features
FEATURE(cxx_access_control_sfinae, LangOpts.CPlusPlus11)
FEATURE(cxx_alias_templates, LangOpts.CPlusPlus11)
Expand Down Expand Up @@ -269,6 +271,7 @@ EXTENSION(c_static_assert, true)
EXTENSION(c_thread_local, PP.getTargetInfo().isTLSSupported())
// C23 features supported by other languages as extensions
EXTENSION(c_attributes, true)
EXTENSION(c_fixed_enum, true)
// C++11 features supported by other languages as extensions.
EXTENSION(cxx_atomic, LangOpts.CPlusPlus)
EXTENSION(cxx_default_function_template_args, LangOpts.CPlusPlus)
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Basic/LangOptions.def
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ LANGOPT(PointerAuthInitFini, 1, 0, "sign function pointers in init/fini arrays")
LANGOPT(PointerAuthInitFiniAddressDiscrimination, 1, 0,
"incorporate address discrimination in authenticated function pointers in init/fini arrays")
LANGOPT(PointerAuthELFGOT, 1, 0, "authenticate pointers from GOT")
LANGOPT(AArch64JumpTableHardening, 1, 0, "use hardened lowering for jump-table dispatch")

LANGOPT(DoubleSquareBracketAttributes, 1, 0, "'[[]]' attributes extension for all language standard modes")
LANGOPT(ExperimentalLateParseAttributes, 1, 0, "experimental late parsing of attributes")
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Basic/PointerAuthOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,9 @@ struct PointerAuthOptions {
/// Do indirect goto label addresses need to be authenticated?
bool IndirectGotos = false;

/// Use hardened lowering for jump-table dispatch?
bool AArch64JumpTableHardening = false;

/// The ABI for C function pointers.
PointerAuthSchema FunctionPointers;

Expand Down
28 changes: 14 additions & 14 deletions clang/include/clang/Basic/arm_sve.td
Original file line number Diff line number Diff line change
Expand Up @@ -762,14 +762,14 @@ def SVCMPLS_WIDE_N : SInst<"svcmple_wide[_n_{d}]", "PPdj", "UcUsUi", MergeNone,
////////////////////////////////////////////////////////////////////////////////
// While comparisons

def SVWHILELE_S32 : SInst<"svwhilele_{d}[_{1}]", "Pkk", "PcPsPiPl", MergeNone, "aarch64_sve_whilele", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILELE_S64 : SInst<"svwhilele_{d}[_{1}]", "Pll", "PcPsPiPl", MergeNone, "aarch64_sve_whilele", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILELO_U32 : SInst<"svwhilelt_{d}[_{1}]", "Pmm", "PUcPUsPUiPUl", MergeNone, "aarch64_sve_whilelo", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILELO_U64 : SInst<"svwhilelt_{d}[_{1}]", "Pnn", "PUcPUsPUiPUl", MergeNone, "aarch64_sve_whilelo", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILELS_U32 : SInst<"svwhilele_{d}[_{1}]", "Pmm", "PUcPUsPUiPUl", MergeNone, "aarch64_sve_whilels", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILELS_U64 : SInst<"svwhilele_{d}[_{1}]", "Pnn", "PUcPUsPUiPUl", MergeNone, "aarch64_sve_whilels", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILELT_S32 : SInst<"svwhilelt_{d}[_{1}]", "Pkk", "PcPsPiPl", MergeNone, "aarch64_sve_whilelt", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILELT_S64 : SInst<"svwhilelt_{d}[_{1}]", "Pll", "PcPsPiPl", MergeNone, "aarch64_sve_whilelt", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILELE_S32 : SInst<"svwhilele_{d}[_{1}]", "Pkk", "PcPsPiPl", MergeNone, "aarch64_sve_whilele", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILELE_S64 : SInst<"svwhilele_{d}[_{1}]", "Pll", "PcPsPiPl", MergeNone, "aarch64_sve_whilele", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILELO_U32 : SInst<"svwhilelt_{d}[_{1}]", "Pmm", "PcPsPiPl", MergeNone, "aarch64_sve_whilelo", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILELO_U64 : SInst<"svwhilelt_{d}[_{1}]", "Pnn", "PcPsPiPl", MergeNone, "aarch64_sve_whilelo", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILELS_U32 : SInst<"svwhilele_{d}[_{1}]", "Pmm", "PcPsPiPl", MergeNone, "aarch64_sve_whilels", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILELS_U64 : SInst<"svwhilele_{d}[_{1}]", "Pnn", "PcPsPiPl", MergeNone, "aarch64_sve_whilels", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILELT_S32 : SInst<"svwhilelt_{d}[_{1}]", "Pkk", "PcPsPiPl", MergeNone, "aarch64_sve_whilelt", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILELT_S64 : SInst<"svwhilelt_{d}[_{1}]", "Pll", "PcPsPiPl", MergeNone, "aarch64_sve_whilelt", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;

////////////////////////////////////////////////////////////////////////////////
// Counting bit
Expand Down Expand Up @@ -1365,10 +1365,10 @@ def SVWHILEGE_S32 : SInst<"svwhilege_{d}[_{1}]", "Pkk", "PcPsPiPl", MergeNon
def SVWHILEGE_S64 : SInst<"svwhilege_{d}[_{1}]", "Pll", "PcPsPiPl", MergeNone, "aarch64_sve_whilege", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILEGT_S32 : SInst<"svwhilegt_{d}[_{1}]", "Pkk", "PcPsPiPl", MergeNone, "aarch64_sve_whilegt", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILEGT_S64 : SInst<"svwhilegt_{d}[_{1}]", "Pll", "PcPsPiPl", MergeNone, "aarch64_sve_whilegt", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILEHI_U32 : SInst<"svwhilegt_{d}[_{1}]", "Pmm", "PUcPUsPUiPUl", MergeNone, "aarch64_sve_whilehi", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILEHI_U64 : SInst<"svwhilegt_{d}[_{1}]", "Pnn", "PUcPUsPUiPUl", MergeNone, "aarch64_sve_whilehi", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILEHS_U32 : SInst<"svwhilege_{d}[_{1}]", "Pmm", "PUcPUsPUiPUl", MergeNone, "aarch64_sve_whilehs", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILEHS_U64 : SInst<"svwhilege_{d}[_{1}]", "Pnn", "PUcPUsPUiPUl", MergeNone, "aarch64_sve_whilehs", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILEHI_U32 : SInst<"svwhilegt_{d}[_{1}]", "Pmm", "PcPsPiPl", MergeNone, "aarch64_sve_whilehi", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILEHI_U64 : SInst<"svwhilegt_{d}[_{1}]", "Pnn", "PcPsPiPl", MergeNone, "aarch64_sve_whilehi", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILEHS_U32 : SInst<"svwhilege_{d}[_{1}]", "Pmm", "PcPsPiPl", MergeNone, "aarch64_sve_whilehs", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILEHS_U64 : SInst<"svwhilege_{d}[_{1}]", "Pnn", "PcPsPiPl", MergeNone, "aarch64_sve_whilehs", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
}

let SVETargetGuard = "sve2p1", SMETargetGuard = "sme2" in {
Expand Down Expand Up @@ -2326,7 +2326,7 @@ let SVETargetGuard = "sve2p1,bf16", SMETargetGuard = "sme2p1,bf16" in {
// Multi-vector convert to/from floating-point.
//
let SVETargetGuard = InvalidMode, SMETargetGuard = "sme2" in {
def SVCVT_F16_X2 : SInst<"svcvt_f16[_f32_x2]", "e2", "f", MergeNone, "aarch64_sve_fcvt_x2", [IsStreaming],[]>;
def SVCVT_F16_X2 : SInst<"svcvt_f16[_f32_x2]", "h2", "f", MergeNone, "aarch64_sve_fcvt_x2", [IsStreaming],[]>;
def SVCVT_BF16_X2 : SInst<"svcvt_bf16[_f32_x2]", "$2", "f", MergeNone, "aarch64_sve_bfcvt_x2", [IsOverloadNone, IsStreaming],[]>;

def SVCVT_F32_U32_X2 : SInst<"svcvt_{d}[_u32_x2]", "2.d2.u", "f", MergeNone, "aarch64_sve_ucvtf_x2", [IsStreaming, IsOverloadWhileOrMultiVecCvt], []>;
Expand All @@ -2348,7 +2348,7 @@ let SVETargetGuard = InvalidMode, SMETargetGuard = "sme-f16f16" in {
// Multi-vector floating-point convert from single-precision to interleaved half-precision/BFloat16
//
let SVETargetGuard = InvalidMode, SMETargetGuard = "sme2" in {
def SVCVTN_F16_X2 : SInst<"svcvtn_f16[_f32_x2]", "e2", "f", MergeNone, "aarch64_sve_fcvtn_x2", [IsStreaming],[]>;
def SVCVTN_F16_X2 : SInst<"svcvtn_f16[_f32_x2]", "h2", "f", MergeNone, "aarch64_sve_fcvtn_x2", [IsStreaming],[]>;
def SVCVTN_BF16_X2 : SInst<"svcvtn_bf16[_f32_x2]", "$2", "f", MergeNone, "aarch64_sve_bfcvtn_x2", [IsOverloadNone, IsStreaming],[]>;
}

Expand Down
20 changes: 14 additions & 6 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -1786,12 +1786,12 @@ defm debug_info_for_profiling : BoolFOption<"debug-info-for-profiling",
PosFlag<SetTrue, [], [ClangOption, CC1Option],
"Emit extra debug info to make sample profile more accurate">,
NegFlag<SetFalse>>;
def fprofile_generate_cold_function_coverage : Flag<["-"], "fprofile-generate-cold-function-coverage">,
def fprofile_generate_cold_function_coverage : Flag<["-"], "fprofile-generate-cold-function-coverage">,
Group<f_Group>, Visibility<[ClangOption, CLOption]>,
HelpText<"Generate instrumented code to collect coverage info for cold functions into default.profraw file (overridden by '=' form of option or LLVM_PROFILE_FILE env var)">;
def fprofile_generate_cold_function_coverage_EQ : Joined<["-"], "fprofile-generate-cold-function-coverage=">,
def fprofile_generate_cold_function_coverage_EQ : Joined<["-"], "fprofile-generate-cold-function-coverage=">,
Group<f_Group>, Visibility<[ClangOption, CLOption]>, MetaVarName<"<directory>">,
HelpText<"Generate instrumented code to collect coverage info for cold functions into <directory>/default.profraw (overridden by LLVM_PROFILE_FILE env var)">;
HelpText<"Generate instrumented code to collect coverage info for cold functions into <directory>/default.profraw (overridden by LLVM_PROFILE_FILE env var)">;
def fprofile_instr_generate : Flag<["-"], "fprofile-instr-generate">,
Group<f_Group>, Visibility<[ClangOption, CLOption]>,
HelpText<"Generate instrumented code to collect execution counts into default.profraw file (overridden by '=' form of option or LLVM_PROFILE_FILE env var)">;
Expand Down Expand Up @@ -4353,6 +4353,7 @@ defm ptrauth_init_fini : OptInCC1FFlag<"ptrauth-init-fini", "Enable signing of f
defm ptrauth_init_fini_address_discrimination : OptInCC1FFlag<"ptrauth-init-fini-address-discrimination",
"Enable address discrimination of function pointers in init/fini arrays">;
defm ptrauth_elf_got : OptInCC1FFlag<"ptrauth-elf-got", "Enable authentication of pointers from GOT (ELF only)">;
defm aarch64_jump_table_hardening: OptInCC1FFlag<"aarch64-jump-table-hardening", "Use hardened lowering for jump-table dispatch">;
}

def fenable_matrix : Flag<["-"], "fenable-matrix">, Group<f_Group>,
Expand Down Expand Up @@ -5092,6 +5093,10 @@ def matomics : Flag<["-"], "matomics">, Group<m_wasm_Features_Group>;
def mno_atomics : Flag<["-"], "mno-atomics">, Group<m_wasm_Features_Group>;
def mbulk_memory : Flag<["-"], "mbulk-memory">, Group<m_wasm_Features_Group>;
def mno_bulk_memory : Flag<["-"], "mno-bulk-memory">, Group<m_wasm_Features_Group>;
def mbulk_memory_opt : Flag<["-"], "mbulk-memory-opt">, Group<m_wasm_Features_Group>;
def mno_bulk_memory_opt : Flag<["-"], "mno-bulk-memory-opt">, Group<m_wasm_Features_Group>;
def mcall_indirect_overlong : Flag<["-"], "mcall-indirect-overlong">, Group<m_wasm_Features_Group>;
def mno_call_indirect_overlong : Flag<["-"], "mno-call-indirect-overlong">, Group<m_wasm_Features_Group>;
def mexception_handing : Flag<["-"], "mexception-handling">, Group<m_wasm_Features_Group>;
def mno_exception_handing : Flag<["-"], "mno-exception-handling">, Group<m_wasm_Features_Group>;
def mextended_const : Flag<["-"], "mextended-const">, Group<m_wasm_Features_Group>;
Expand Down Expand Up @@ -7383,9 +7388,12 @@ def fuse_register_sized_bitfield_access: Flag<["-"], "fuse-register-sized-bitfie
def relaxed_aliasing : Flag<["-"], "relaxed-aliasing">,
HelpText<"Turn off Type Based Alias Analysis">,
MarshallingInfoFlag<CodeGenOpts<"RelaxedAliasing">>;
def pointer_tbaa: Flag<["-"], "pointer-tbaa">,
HelpText<"Turn on Type Based Alias Analysis for pointer accesses">,
MarshallingInfoFlag<CodeGenOpts<"PointerTBAA">>;
defm pointer_tbaa: BoolOption<"", "pointer-tbaa", CodeGenOpts<"PointerTBAA">,
DefaultTrue,
PosFlag<SetTrue, [], [ClangOption], "Enable">,
NegFlag<SetFalse, [], [ClangOption], "Disable">,
BothFlags<[], [ClangOption], " that single precision floating-point divide and sqrt used in ">>
;
def no_struct_path_tbaa : Flag<["-"], "no-struct-path-tbaa">,
HelpText<"Turn off struct-path aware Type Based Alias Analysis">,
MarshallingInfoNegativeFlag<CodeGenOpts<"StructPathTBAA">>;
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
8 changes: 8 additions & 0 deletions clang/include/clang/Sema/SemaOpenACC.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@ class SemaOpenACC : public SemaBase {
/// which allows us to diagnose if the value of 'N' is too large for the
/// current number of 'for' loops.
bool CollapseDepthSatisfied = true;

/// Records the kind of the directive that this clause is attached to, which
/// allows us to use it in diagnostics.
OpenACCDirectiveKind DirectiveKind = OpenACCDirectiveKind::Invalid;
} CollapseInfo;

/// The 'tile' clause requires a bit of additional checking as well, so like
Expand All @@ -103,6 +107,10 @@ class SemaOpenACC : public SemaBase {
/// which allows us to diagnose if the number of arguments is too large for
/// the current number of 'for' loops.
bool TileDepthSatisfied = true;

/// Records the kind of the directive that this clause is attached to, which
/// allows us to use it in diagnostics.
OpenACCDirectiveKind DirectiveKind = OpenACCDirectiveKind::Invalid;
} TileInfo;

/// A list of the active reduction clauses, which allows us to check that all
Expand Down
12 changes: 4 additions & 8 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 @@ -599,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
32 changes: 6 additions & 26 deletions clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
Original file line number Diff line number Diff line change
Expand Up @@ -429,47 +429,27 @@ class BranchNodeBuilder: public NodeBuilder {
const CFGBlock *DstT;
const CFGBlock *DstF;

bool InFeasibleTrue;
bool InFeasibleFalse;

void anchor() override;

public:
BranchNodeBuilder(ExplodedNode *SrcNode, ExplodedNodeSet &DstSet,
const NodeBuilderContext &C,
const CFGBlock *dstT, const CFGBlock *dstF)
: NodeBuilder(SrcNode, DstSet, C), DstT(dstT), DstF(dstF),
InFeasibleTrue(!DstT), InFeasibleFalse(!DstF) {
const NodeBuilderContext &C, const CFGBlock *DT,
const CFGBlock *DF)
: NodeBuilder(SrcNode, DstSet, C), DstT(DT), DstF(DF) {
// The branch node builder does not generate autotransitions.
// If there are no successors it means that both branches are infeasible.
takeNodes(SrcNode);
}

BranchNodeBuilder(const ExplodedNodeSet &SrcSet, ExplodedNodeSet &DstSet,
const NodeBuilderContext &C,
const CFGBlock *dstT, const CFGBlock *dstF)
: NodeBuilder(SrcSet, DstSet, C), DstT(dstT), DstF(dstF),
InFeasibleTrue(!DstT), InFeasibleFalse(!DstF) {
const NodeBuilderContext &C, const CFGBlock *DT,
const CFGBlock *DF)
: NodeBuilder(SrcSet, DstSet, C), DstT(DT), DstF(DF) {
takeNodes(SrcSet);
}

ExplodedNode *generateNode(ProgramStateRef State, bool branch,
ExplodedNode *Pred);

const CFGBlock *getTargetBlock(bool branch) const {
return branch ? DstT : DstF;
}

void markInfeasible(bool branch) {
if (branch)
InFeasibleTrue = true;
else
InFeasibleFalse = true;
}

bool isFeasible(bool branch) {
return branch ? !InFeasibleTrue : !InFeasibleFalse;
}
};

class IndirectGotoNodeBuilder {
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
95 changes: 95 additions & 0 deletions clang/lib/AST/ByteCode/BitcastBuffer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
//===-------------------- Bitcastbuffer.cpp ---------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "BitcastBuffer.h"

using namespace clang;
using namespace clang::interp;

/// Returns the value of the bit in the given sequence of bytes.
static inline bool bitof(const std::byte *B, Bits BitIndex) {
return (B[BitIndex.roundToBytes()] &
(std::byte{1} << BitIndex.getOffsetInByte())) != std::byte{0};
}

void BitcastBuffer::pushData(const std::byte *In, Bits BitOffset, Bits BitWidth,
Endian TargetEndianness) {
for (unsigned It = 0; It != BitWidth.getQuantity(); ++It) {
bool BitValue = bitof(In, Bits(It));
if (!BitValue)
continue;

Bits DstBit;
if (TargetEndianness == Endian::Little)
DstBit = BitOffset + Bits(It);
else
DstBit = size() - BitOffset - BitWidth + Bits(It);

size_t DstByte = DstBit.roundToBytes();
Data[DstByte] |= std::byte{1} << DstBit.getOffsetInByte();
}
}

std::unique_ptr<std::byte[]>
BitcastBuffer::copyBits(Bits BitOffset, Bits BitWidth, Bits FullBitWidth,
Endian TargetEndianness) const {
assert(BitWidth.getQuantity() <= FullBitWidth.getQuantity());
assert(FullBitWidth.isFullByte());
auto Out = std::make_unique<std::byte[]>(FullBitWidth.roundToBytes());

for (unsigned It = 0; It != BitWidth.getQuantity(); ++It) {
Bits BitIndex;
if (TargetEndianness == Endian::Little)
BitIndex = BitOffset + Bits(It);
else
BitIndex = size() - BitWidth - BitOffset + Bits(It);

bool BitValue = bitof(Data.get(), BitIndex);
if (!BitValue)
continue;

Bits DstBit = Bits(It);
size_t DstByte = DstBit.roundToBytes();
Out[DstByte] |= std::byte{1} << DstBit.getOffsetInByte();
}

return Out;
}

#if 0
template<typename T>
static std::string hex(T t) {
std::stringstream stream;
stream << std::hex << (int)t;
return std::string(stream.str());
}


void BitcastBuffer::dump(bool AsHex = true) const {
llvm::errs() << "LSB\n ";
unsigned LineLength = 0;
for (unsigned I = 0; I != (FinalBitSize / 8); ++I) {
std::byte B = Data[I];
if (AsHex) {
std::stringstream stream;
stream << std::hex << (int)B;
llvm::errs() << stream.str();
LineLength += stream.str().size() + 1;
} else {
llvm::errs() << std::bitset<8>((int)B).to_string();
LineLength += 8 + 1;
// llvm::errs() << (int)B;
}
llvm::errs() << ' ';
}
llvm::errs() << '\n';

for (unsigned I = 0; I != LineLength; ++I)
llvm::errs() << ' ';
llvm::errs() << "MSB\n";
}
#endif
89 changes: 89 additions & 0 deletions clang/lib/AST/ByteCode/BitcastBuffer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
//===--------------------- BitcastBuffer.h ----------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_AST_INTERP_BITCAST_BUFFER_H
#define LLVM_CLANG_AST_INTERP_BITCAST_BUFFER_H

#include <cassert>
#include <cstddef>
#include <memory>

namespace clang {
namespace interp {

enum class Endian { Little, Big };

/// A quantity in bits.
struct Bits {
size_t N = 0;
Bits() = default;
static Bits zero() { return Bits(0); }
explicit Bits(size_t Quantity) : N(Quantity) {}
size_t getQuantity() const { return N; }
size_t roundToBytes() const { return N / 8; }
size_t getOffsetInByte() const { return N % 8; }
bool isFullByte() const { return N % 8 == 0; }
bool nonZero() const { return N != 0; }
bool isZero() const { return N == 0; }

Bits operator-(Bits Other) { return Bits(N - Other.N); }
Bits operator+(Bits Other) { return Bits(N + Other.N); }
Bits operator+=(size_t O) {
N += O;
return *this;
}

bool operator>=(Bits Other) { return N >= Other.N; }
};

/// A quantity in bytes.
struct Bytes {
size_t N;
explicit Bytes(size_t Quantity) : N(Quantity) {}
size_t getQuantity() const { return N; }
Bits toBits() const { return Bits(N * 8); }
};

/// Track what bits have been initialized to known values and which ones
/// have indeterminate value.
struct BitcastBuffer {
Bits FinalBitSize;
std::unique_ptr<std::byte[]> Data;

BitcastBuffer(Bits FinalBitSize) : FinalBitSize(FinalBitSize) {
assert(FinalBitSize.isFullByte());
unsigned ByteSize = FinalBitSize.roundToBytes();
Data = std::make_unique<std::byte[]>(ByteSize);
}

/// Returns the buffer size in bits.
Bits size() const { return FinalBitSize; }

/// Returns \c true if all bits in the buffer have been initialized.
bool allInitialized() const {
// FIXME: Implement.
return true;
}

/// Push \p BitWidth bits at \p BitOffset from \p In into the buffer.
/// \p TargetEndianness is the endianness of the target we're compiling for.
/// \p In must hold at least \p BitWidth many bits.
void pushData(const std::byte *In, Bits BitOffset, Bits BitWidth,
Endian TargetEndianness);

/// Copy \p BitWidth bits at offset \p BitOffset from the buffer.
/// \p TargetEndianness is the endianness of the target we're compiling for.
///
/// The returned output holds exactly (\p FullBitWidth / 8) bytes.
std::unique_ptr<std::byte[]> copyBits(Bits BitOffset, Bits BitWidth,
Bits FullBitWidth,
Endian TargetEndianness) const;
};

} // namespace interp
} // namespace clang
#endif
4 changes: 1 addition & 3 deletions clang/lib/AST/ByteCode/Boolean.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,7 @@ class Boolean final {
Boolean truncate(unsigned TruncBits) const { return *this; }

static Boolean bitcastFromMemory(const std::byte *Buff, unsigned BitWidth) {
// Boolean width is currently always 8 for all supported targets. If this
// changes we need to get the bool width from the target info.
assert(BitWidth == 8);
// Just load the first byte.
bool Val = static_cast<bool>(*Buff);
return Boolean(Val);
}
Expand Down
40 changes: 26 additions & 14 deletions clang/lib/AST/ByteCode/Compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,9 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) {
std::nullopt, true, false,
/*IsMutable=*/false, nullptr);
}
return this->emitNull(classifyPrim(CE->getType()), Desc, CE);

uint64_t Val = Ctx.getASTContext().getTargetNullPointerValue(CE->getType());
return this->emitNull(classifyPrim(CE->getType()), Val, Desc, CE);
}

case CK_PointerToIntegral: {
Expand Down Expand Up @@ -448,8 +450,8 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) {

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

std::optional<PrimType> ToT = classify(CE->getType());
Expand Down Expand Up @@ -1000,7 +1002,10 @@ bool Compiler<Emitter>::VisitPointerArithBinOp(const BinaryOperator *E) {
if (!visitAsPointer(RHS, *RT) || !visitAsPointer(LHS, *LT))
return false;

return this->emitSubPtr(classifyPrim(E->getType()), E);
PrimType IntT = classifyPrim(E->getType());
if (!this->emitSubPtr(IntT, E))
return false;
return DiscardResult ? this->emitPop(IntT, E) : true;
}

PrimType OffsetType;
Expand Down Expand Up @@ -3814,7 +3819,7 @@ template <class Emitter> bool Compiler<Emitter>::visitBool(const Expr *E) {

// Convert pointers to bool.
if (T == PT_Ptr || T == PT_FnPtr) {
if (!this->emitNull(*T, nullptr, E))
if (!this->emitNull(*T, 0, nullptr, E))
return false;
return this->emitNE(*T, E);
}
Expand Down Expand Up @@ -3854,11 +3859,12 @@ bool Compiler<Emitter>::visitZeroInitializer(PrimType T, QualType QT,
case PT_IntAPS:
return this->emitZeroIntAPS(Ctx.getBitWidth(QT), E);
case PT_Ptr:
return this->emitNullPtr(nullptr, E);
return this->emitNullPtr(Ctx.getASTContext().getTargetNullPointerValue(QT),
nullptr, E);
case PT_FnPtr:
return this->emitNullFnPtr(nullptr, E);
return this->emitNullFnPtr(0, nullptr, E);
case PT_MemberPtr:
return this->emitNullMemberPtr(nullptr, E);
return this->emitNullMemberPtr(0, nullptr, E);
case PT_Float:
return this->emitConstFloat(APFloat::getZero(Ctx.getFloatSemantics(QT)), E);
case PT_FixedPoint: {
Expand Down Expand Up @@ -4418,7 +4424,7 @@ bool Compiler<Emitter>::visitAPValue(const APValue &Val, PrimType ValType,

if (Val.isLValue()) {
if (Val.isNullPointer())
return this->emitNull(ValType, nullptr, E);
return this->emitNull(ValType, 0, nullptr, E);
APValue::LValueBase Base = Val.getLValueBase();
if (const Expr *BaseExpr = Base.dyn_cast<const Expr *>())
return this->visit(BaseExpr);
Expand All @@ -4428,7 +4434,7 @@ bool Compiler<Emitter>::visitAPValue(const APValue &Val, PrimType ValType,
} else if (Val.isMemberPointer()) {
if (const ValueDecl *MemberDecl = Val.getMemberPointerDecl())
return this->emitGetMemberPtr(MemberDecl, E);
return this->emitNullMemberPtr(nullptr, E);
return this->emitNullMemberPtr(0, nullptr, E);
}

return false;
Expand Down Expand Up @@ -4780,7 +4786,8 @@ bool Compiler<Emitter>::VisitCXXNullPtrLiteralExpr(
if (DiscardResult)
return true;

return this->emitNullPtr(nullptr, E);
uint64_t Val = Ctx.getASTContext().getTargetNullPointerValue(E->getType());
return this->emitNullPtr(Val, nullptr, E);
}

template <class Emitter>
Expand Down Expand Up @@ -5330,7 +5337,7 @@ bool Compiler<Emitter>::emitLambdaStaticInvokerBody(const CXXMethodDecl *MD) {
// one here, and we don't need one either because the lambda cannot have
// any captures, as verified above. Emit a null pointer. This is then
// special-cased when interpreting to not emit any misleading diagnostics.
if (!this->emitNullPtr(nullptr, MD))
if (!this->emitNullPtr(0, nullptr, MD))
return false;

// Forward all arguments from the static invoker to the lambda call operator.
Expand Down Expand Up @@ -5911,6 +5918,9 @@ bool Compiler<Emitter>::VisitVectorUnaryOperator(const UnaryOperator *E) {
return this->discard(SubExpr);

auto UnaryOp = E->getOpcode();
if (UnaryOp == UO_Extension)
return this->delegate(SubExpr);

if (UnaryOp != UO_Plus && UnaryOp != UO_Minus && UnaryOp != UO_LNot &&
UnaryOp != UO_Not && UnaryOp != UO_AddrOf)
return this->emitInvalid(E);
Expand Down Expand Up @@ -6477,7 +6487,7 @@ bool Compiler<Emitter>::emitBuiltinBitCast(const CastExpr *E) {
if (!this->discard(SubExpr))
return false;

return this->emitNullPtr(nullptr, E);
return this->emitNullPtr(0, nullptr, E);
}

if (FromType->isNullPtrType() && ToT) {
Expand All @@ -6502,7 +6512,7 @@ bool Compiler<Emitter>::emitBuiltinBitCast(const CastExpr *E) {
// 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()) {
if (SubExpr->isGLValue() || FromType->isVectorType()) {
if (!this->visit(SubExpr))
return false;
} else if (std::optional<PrimType> FromT = classify(SubExpr)) {
Expand All @@ -6514,6 +6524,8 @@ bool Compiler<Emitter>::emitBuiltinBitCast(const CastExpr *E) {
return false;
if (!this->emitGetPtrLocal(TempOffset, E))
return false;
} else {
return false;
}

if (!ToT || ToT == PT_Ptr) {
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
5 changes: 4 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 Expand Up @@ -181,6 +183,7 @@ template <unsigned Bits, bool Signed> class Integral final {
}

Integral truncate(unsigned TruncBits) const {
assert(TruncBits >= 1);
if (TruncBits >= Bits)
return *this;
const ReprT BitMask = (ReprT(1) << ReprT(TruncBits)) - 1;
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
25 changes: 10 additions & 15 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 Expand Up @@ -2439,9 +2432,11 @@ static inline bool ZeroIntAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
}

template <PrimType Name, class T = typename PrimConv<Name>::T>
inline bool Null(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
// Note: Desc can be null.
S.Stk.push<T>(0, Desc);
inline bool Null(InterpState &S, CodePtr OpPC, uint64_t Value,
const Descriptor *Desc) {
// FIXME(perf): This is a somewhat often-used function and the value of a
// null pointer is almost always 0.
S.Stk.push<T>(Value, Desc);
return true;
}

Expand Down
199 changes: 188 additions & 11 deletions clang/lib/AST/ByteCode/InterpBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,20 +89,23 @@ 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)); });
}
}

template <typename T>
static void pushInteger(InterpState &S, T Val, QualType QT) {
if constexpr (std::is_same_v<T, APInt>)
pushInteger(S, APSInt(Val, !std::is_signed_v<T>), QT);
else if constexpr (std::is_same_v<T, APSInt>)
pushInteger(S, Val, QT);
else
pushInteger(S,
APSInt(APInt(sizeof(T) * 8, static_cast<uint64_t>(Val),
Expand All @@ -116,14 +119,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,12 +140,25 @@ 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");
}
#undef RET_CASE
}

static void diagnoseNonConstexprBuiltin(InterpState &S, CodePtr OpPC,
unsigned ID) {
auto Loc = S.Current->getSource(OpPC);
if (S.getLangOpts().CPlusPlus11)
S.CCEDiag(Loc, diag::note_constexpr_invalid_function)
<< /*isConstexpr=*/0 << /*isConstructor=*/0
<< ("'" + S.getASTContext().BuiltinInfo.getName(ID) + "'").str();
else
S.CCEDiag(Loc, diag::note_invalid_subexpr_in_const_expr);
}

static bool interp__builtin_is_constant_evaluated(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame,
const CallExpr *Call) {
Expand Down Expand Up @@ -176,10 +192,14 @@ static bool interp__builtin_is_constant_evaluated(InterpState &S, CodePtr OpPC,

static bool interp__builtin_strcmp(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame,
const CallExpr *Call) {
const Function *Func, const CallExpr *Call) {
unsigned ID = Func->getBuiltinID();
const Pointer &A = getParam<Pointer>(Frame, 0);
const Pointer &B = getParam<Pointer>(Frame, 1);

if (ID == Builtin::BIstrcmp)
diagnoseNonConstexprBuiltin(S, OpPC, ID);

if (!CheckLive(S, OpPC, A, AK_Read) || !CheckLive(S, OpPC, B, AK_Read))
return false;

Expand Down Expand Up @@ -219,9 +239,13 @@ static bool interp__builtin_strcmp(InterpState &S, CodePtr OpPC,

static bool interp__builtin_strlen(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame,
const CallExpr *Call) {
const Function *Func, const CallExpr *Call) {
unsigned ID = Func->getBuiltinID();
const Pointer &StrPtr = getParam<Pointer>(Frame, 0);

if (ID == Builtin::BIstrlen)
diagnoseNonConstexprBuiltin(S, OpPC, ID);

if (!CheckArray(S, OpPC, StrPtr))
return false;

Expand Down Expand Up @@ -1684,10 +1708,139 @@ 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 if (ID == Builtin::BI__builtin_reduce_or) {
(void)T::bitOr(Result, Elem, BitWidth, &Result);
} else if (ID == Builtin::BI__builtin_reduce_xor) {
(void)T::bitXor(Result, Elem, BitWidth, &Result);
} else {
llvm_unreachable("Unhandled vector reduce builtin");
}
}
pushInteger(S, Result.toAPSInt(), Call->getType());
});

return true;
}

/// Can be called with an integer or vector as the first and only parameter.
static bool interp__builtin_elementwise_popcount(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame,
const Function *Func,
const CallExpr *Call) {
assert(Call->getNumArgs() == 1);
if (Call->getArg(0)->getType()->isIntegerType()) {
PrimType ArgT = *S.getContext().classify(Call->getArg(0)->getType());
APSInt Val = peekToAPSInt(S.Stk, ArgT);
pushInteger(S, Val.popcount(), Call->getType());
return true;
}
// Otherwise, the argument must be a vector.
assert(Call->getArg(0)->getType()->isVectorType());
const Pointer &Arg = S.Stk.peek<Pointer>();
assert(Arg.getFieldDesc()->isPrimitiveArray());
const Pointer &Dst = S.Stk.peek<Pointer>(primSize(PT_Ptr) * 2);
assert(Dst.getFieldDesc()->isPrimitiveArray());
assert(Arg.getFieldDesc()->getNumElems() ==
Dst.getFieldDesc()->getNumElems());

QualType ElemType = Arg.getFieldDesc()->getElemQualType();
PrimType ElemT = *S.getContext().classify(ElemType);
unsigned NumElems = Arg.getNumElems();

// FIXME: Reading from uninitialized vector elements?
for (unsigned I = 0; I != NumElems; ++I) {
INT_TYPE_SWITCH_NO_BOOL(ElemT, {
Dst.atIndex(I).deref<T>() =
T::from(Arg.atIndex(I).deref<T>().toAPSInt().popcount());
Dst.atIndex(I).initialize();
});
}

return true;
}
static bool interp__builtin_memcpy(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame,
const Function *Func, const CallExpr *Call) {
assert(Call->getNumArgs() == 3);
unsigned ID = Func->getBuiltinID();
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 (ID == Builtin::BImemcpy || ID == Builtin::BImemmove)
diagnoseNonConstexprBuiltin(S, OpPC, ID);

bool Move = (ID == Builtin::BI__builtin_memmove || ID == Builtin::BImemmove);

// 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 (SrcPtr.isZero() || DestPtr.isZero()) {
Pointer DiagPtr = (SrcPtr.isZero() ? SrcPtr : DestPtr);
S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_memcpy_null)
<< /*IsMove=*/Move << /*IsWchar=*/false << !SrcPtr.isZero()
<< DiagPtr.toDiagnosticString(S.getASTContext());
return false;
}

// As a last resort, reject dummy pointers.
if (DestPtr.isDummy() || SrcPtr.isDummy())
return false;

if (!DoBitCastPtr(S, OpPC, SrcPtr, DestPtr, Size.getZExtValue()))
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 All @@ -1700,11 +1853,13 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
case Builtin::BI__assume:
break;
case Builtin::BI__builtin_strcmp:
if (!interp__builtin_strcmp(S, OpPC, Frame, Call))
case Builtin::BIstrcmp:
if (!interp__builtin_strcmp(S, OpPC, Frame, F, Call))
return false;
break;
case Builtin::BI__builtin_strlen:
if (!interp__builtin_strlen(S, OpPC, Frame, Call))
case Builtin::BIstrlen:
if (!interp__builtin_strlen(S, OpPC, Frame, F, Call))
return false;
break;
case Builtin::BI__builtin_nan:
Expand Down Expand Up @@ -2130,6 +2285,28 @@ 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:
case Builtin::BI__builtin_reduce_or:
case Builtin::BI__builtin_reduce_xor:
if (!interp__builtin_vector_reduce(S, OpPC, Frame, F, Call))
return false;
break;

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

case Builtin::BI__builtin_memcpy:
case Builtin::BImemcpy:
case Builtin::BI__builtin_memmove:
case Builtin::BImemmove:
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 +2315,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
298 changes: 129 additions & 169 deletions clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions clang/lib/AST/ByteCode/InterpBuiltinBitCast.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ bool DoBitCast(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
std::byte *Buff, size_t BuffSize, bool &HasIndeterminateBits);
bool DoBitCastPtr(InterpState &S, CodePtr OpPC, const Pointer &FromPtr,
Pointer &ToPtr);
bool DoBitCastPtr(InterpState &S, CodePtr OpPC, const Pointer &FromPtr,
Pointer &ToPtr, size_t Size);

} // namespace interp
} // namespace clang
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/ByteCode/Opcodes.td
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ def ZeroIntAPS : Opcode {
// [] -> [Pointer]
def Null : Opcode {
let Types = [PtrTypeClass];
let Args = [ArgDesc];
let Args = [ArgUint64, ArgDesc];
let HasGroup = 1;
}

Expand Down
1 change: 1 addition & 0 deletions clang/lib/AST/ByteCode/Record.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class Record final {
unsigned Offset;
const Descriptor *Desc;
bool isBitField() const { return Decl->isBitField(); }
bool isUnnamedBitField() const { return Decl->isUnnamedBitField(); }
};

/// Describes a base class.
Expand Down
1 change: 1 addition & 0 deletions clang/lib/AST/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ add_clang_library(clangAST
ExternalASTSource.cpp
FormatString.cpp
InheritViz.cpp
ByteCode/BitcastBuffer.cpp
ByteCode/ByteCodeEmitter.cpp
ByteCode/Compiler.cpp
ByteCode/Context.cpp
Expand Down
18 changes: 12 additions & 6 deletions clang/lib/AST/CXXInheritance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ bool CXXRecordDecl::forallBases(ForallBasesCallback BaseMatches) const {
return false;

CXXRecordDecl *Base =
cast_or_null<CXXRecordDecl>(Ty->getDecl()->getDefinition());
cast_if_present<CXXRecordDecl>(Ty->getDecl()->getDefinition());
if (!Base ||
(Base->isDependentContext() &&
!Base->isCurrentInstantiation(Record))) {
Expand Down Expand Up @@ -169,13 +169,21 @@ bool CXXBasePaths::lookupInBases(ASTContext &Context,
QualType BaseType =
Context.getCanonicalType(BaseSpec.getType()).getUnqualifiedType();

bool isCurrentInstantiation = isa<InjectedClassNameType>(BaseType);
if (!isCurrentInstantiation) {
if (auto *BaseRecord = cast_if_present<CXXRecordDecl>(
BaseSpec.getType()->getAsRecordDecl()))
isCurrentInstantiation = BaseRecord->isDependentContext() &&
BaseRecord->isCurrentInstantiation(Record);
}
// C++ [temp.dep]p3:
// In the definition of a class template or a member of a class template,
// if a base class of the class template depends on a template-parameter,
// the base class scope is not examined during unqualified name lookup
// either at the point of definition of the class template or member or
// during an instantiation of the class tem- plate or member.
if (!LookupInDependent && BaseType->isDependentType())
if (!LookupInDependent &&
(BaseType->isDependentType() && !isCurrentInstantiation))
continue;

// Determine whether we need to visit this base class at all,
Expand Down Expand Up @@ -243,9 +251,8 @@ bool CXXBasePaths::lookupInBases(ASTContext &Context,
return FoundPath;
}
} else if (VisitBase) {
CXXRecordDecl *BaseRecord;
CXXRecordDecl *BaseRecord = nullptr;
if (LookupInDependent) {
BaseRecord = nullptr;
const TemplateSpecializationType *TST =
BaseSpec.getType()->getAs<TemplateSpecializationType>();
if (!TST) {
Expand All @@ -264,8 +271,7 @@ bool CXXBasePaths::lookupInBases(ASTContext &Context,
BaseRecord = nullptr;
}
} else {
BaseRecord = cast<CXXRecordDecl>(
BaseSpec.getType()->castAs<RecordType>()->getDecl());
BaseRecord = cast<CXXRecordDecl>(BaseSpec.getType()->getAsRecordDecl());
}
if (BaseRecord &&
lookupInBases(Context, BaseRecord, BaseMatches, LookupInDependent)) {
Expand Down
2 changes: 0 additions & 2 deletions clang/lib/AST/DeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2602,8 +2602,6 @@ bool CXXMethodDecl::isMoveAssignmentOperator() const {

void CXXMethodDecl::addOverriddenMethod(const CXXMethodDecl *MD) {
assert(MD->isCanonicalDecl() && "Method is not canonical!");
assert(!MD->getParent()->isDependentContext() &&
"Can't add an overridden method to a class template!");
assert(MD->isVirtual() && "Method is not virtual!");

getASTContext().addOverriddenMethod(this, MD);
Expand Down
21 changes: 16 additions & 5 deletions clang/lib/AST/ExprConstant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11310,7 +11310,8 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) {
switch (E->getBuiltinCallee()) {
default:
return false;
case Builtin::BI__builtin_elementwise_popcount: {
case Builtin::BI__builtin_elementwise_popcount:
case Builtin::BI__builtin_elementwise_bitreverse: {
APValue Source;
if (!EvaluateAsRValue(Info, E->getArg(0), Source))
return false;
Expand All @@ -11322,9 +11323,18 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) {

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())));
switch (E->getBuiltinCallee()) {
case Builtin::BI__builtin_elementwise_popcount:
ResultElements.push_back(APValue(
APSInt(APInt(Info.Ctx.getIntWidth(DestEltTy), Elt.popcount()),
DestEltTy->isUnsignedIntegerOrEnumerationType())));
break;
case Builtin::BI__builtin_elementwise_bitreverse:
ResultElements.push_back(
APValue(APSInt(Elt.reverseBits(),
DestEltTy->isUnsignedIntegerOrEnumerationType())));
break;
}
}

return Success(APValue(ResultElements.data(), ResultElements.size()), E);
Expand Down Expand Up @@ -12833,7 +12843,8 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
case Builtin::BI__builtin_bitreverse8:
case Builtin::BI__builtin_bitreverse16:
case Builtin::BI__builtin_bitreverse32:
case Builtin::BI__builtin_bitreverse64: {
case Builtin::BI__builtin_bitreverse64:
case Builtin::BI__builtin_elementwise_bitreverse: {
APSInt Val;
if (!EvaluateInteger(E->getArg(0), Val, Info))
return false;
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
11 changes: 10 additions & 1 deletion clang/lib/AST/MicrosoftMangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1014,6 +1014,7 @@ void MicrosoftCXXNameMangler::mangleFloat(llvm::APFloat Number) {
case APFloat::S_x87DoubleExtended: Out << 'X'; break;
case APFloat::S_IEEEquad: Out << 'Y'; break;
case APFloat::S_PPCDoubleDouble: Out << 'Z'; break;
case APFloat::S_PPCDoubleDoubleLegacy:
case APFloat::S_Float8E5M2:
case APFloat::S_Float8E4M3:
case APFloat::S_Float8E4M3FN:
Expand Down Expand Up @@ -3372,7 +3373,15 @@ void MicrosoftCXXNameMangler::mangleType(const MemberPointerType *T,

void MicrosoftCXXNameMangler::mangleType(const TemplateTypeParmType *T,
Qualifiers, SourceRange Range) {
Error(Range.getBegin(), "template type parameter type") << Range;
Out << '?';

llvm::SmallString<64> Name;
Name += "<TTPT_";
Name += llvm::utostr(T->getDepth());
Name += "_";
Name += llvm::utostr(T->getIndex());
Name += ">";
mangleSourceName(Name);
}

void MicrosoftCXXNameMangler::mangleType(const SubstTemplateTypeParmPackType *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
10 changes: 9 additions & 1 deletion clang/lib/AST/Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,12 @@ void ConstantArrayType::Profile(llvm::FoldingSetNodeID &ID,
SizeExpr->Profile(ID, Context, true);
}

QualType ArrayParameterType::getConstantArrayType(const ASTContext &Ctx) const {
return Ctx.getConstantArrayType(getElementType(), getSize(), getSizeExpr(),
getSizeModifier(),
getIndexTypeQualifiers().getAsOpaqueValue());
}

DependentSizedArrayType::DependentSizedArrayType(QualType et, QualType can,
Expr *e, ArraySizeModifier sm,
unsigned tq,
Expand Down Expand Up @@ -4723,7 +4729,9 @@ LinkageInfo LinkageComputer::computeTypeLinkageInfo(const Type *T) {
case Type::Pipe:
return computeTypeLinkageInfo(cast<PipeType>(T)->getElementType());
case Type::HLSLAttributedResource:
llvm_unreachable("not yet implemented");
return computeTypeLinkageInfo(cast<HLSLAttributedResourceType>(T)
->getContainedType()
->getCanonicalTypeInternal());
}

llvm_unreachable("unhandled type class");
Expand Down
32 changes: 25 additions & 7 deletions clang/lib/ASTMatchers/ASTMatchersInternal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "clang/Basic/LLVM.h"
#include "clang/Lex/Lexer.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
Expand Down Expand Up @@ -697,27 +698,42 @@ static bool isTokenAtLoc(const SourceManager &SM, const LangOptions &LangOpts,
return !Invalid && Text == TokenText;
}

std::optional<SourceLocation>
getExpansionLocOfMacro(StringRef MacroName, SourceLocation Loc,
const ASTContext &Context) {
static std::optional<SourceLocation> getExpansionLocOfMacroRecursive(
StringRef MacroName, SourceLocation Loc, const ASTContext &Context,
llvm::DenseSet<SourceLocation> &CheckedLocations) {
auto &SM = Context.getSourceManager();
const LangOptions &LangOpts = Context.getLangOpts();
while (Loc.isMacroID()) {
if (CheckedLocations.count(Loc))
return std::nullopt;
CheckedLocations.insert(Loc);
SrcMgr::ExpansionInfo Expansion =
SM.getSLocEntry(SM.getFileID(Loc)).getExpansion();
if (Expansion.isMacroArgExpansion())
if (Expansion.isMacroArgExpansion()) {
// Check macro argument for an expansion of the given macro. For example,
// `F(G(3))`, where `MacroName` is `G`.
if (std::optional<SourceLocation> ArgLoc = getExpansionLocOfMacro(
MacroName, Expansion.getSpellingLoc(), Context))
if (std::optional<SourceLocation> ArgLoc =
getExpansionLocOfMacroRecursive(MacroName,
Expansion.getSpellingLoc(),
Context, CheckedLocations)) {
return ArgLoc;
}
}
Loc = Expansion.getExpansionLocStart();
if (isTokenAtLoc(SM, LangOpts, MacroName, Loc))
return Loc;
}
return std::nullopt;
}

std::optional<SourceLocation>
getExpansionLocOfMacro(StringRef MacroName, SourceLocation Loc,
const ASTContext &Context) {
llvm::DenseSet<SourceLocation> CheckedLocations;
return getExpansionLocOfMacroRecursive(MacroName, Loc, Context,
CheckedLocations);
}

std::shared_ptr<llvm::Regex> createAndVerifyRegex(StringRef Regex,
llvm::Regex::RegexFlags Flags,
StringRef MatcherID) {
Expand Down Expand Up @@ -799,6 +815,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 Expand Up @@ -1097,7 +1114,8 @@ AST_TYPELOC_TRAVERSE_MATCHER_DEF(hasValueType,
AST_TYPELOC_TRAVERSE_MATCHER_DEF(
pointee,
AST_POLYMORPHIC_SUPPORTED_TYPES(BlockPointerType, MemberPointerType,
PointerType, ReferenceType));
PointerType, ReferenceType,
ObjCObjectPointerType));

const internal::VariadicDynCastAllOfMatcher<Stmt, OMPExecutableDirective>
ompExecutableDirective;
Expand Down
1 change: 1 addition & 0 deletions clang/lib/ASTMatchers/Dynamic/Registry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,7 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(equalsBoundNode);
REGISTER_MATCHER(equalsIntegralValue);
REGISTER_MATCHER(explicitCastExpr);
REGISTER_MATCHER(exportDecl);
REGISTER_MATCHER(expr);
REGISTER_MATCHER(exprWithCleanups);
REGISTER_MATCHER(fieldDecl);
Expand Down
29 changes: 8 additions & 21 deletions clang/lib/Analysis/ExprMutationAnalyzer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,34 +55,21 @@ static bool canExprResolveTo(const Expr *Source, const Expr *Target) {
// This is matched by `IgnoreDerivedToBase(canResolveToExpr(InnerMatcher))`
// below.
const auto ConditionalOperatorM = [Target](const Expr *E) {
if (const auto *OP = dyn_cast<ConditionalOperator>(E)) {
if (const auto *TE = OP->getTrueExpr()->IgnoreParens())
if (canExprResolveTo(TE, Target))
return true;
if (const auto *FE = OP->getFalseExpr()->IgnoreParens())
if (canExprResolveTo(FE, Target))
return true;
}
return false;
};

const auto ElvisOperator = [Target](const Expr *E) {
if (const auto *OP = dyn_cast<BinaryConditionalOperator>(E)) {
if (const auto *TE = OP->getTrueExpr()->IgnoreParens())
if (canExprResolveTo(TE, Target))
return true;
if (const auto *FE = OP->getFalseExpr()->IgnoreParens())
if (canExprResolveTo(FE, Target))
return true;
if (const auto *CO = dyn_cast<AbstractConditionalOperator>(E)) {
const auto *TE = CO->getTrueExpr()->IgnoreParens();
if (TE && canExprResolveTo(TE, Target))
return true;
const auto *FE = CO->getFalseExpr()->IgnoreParens();
if (FE && canExprResolveTo(FE, Target))
return true;
}
return false;
};

const Expr *SourceExprP = Source->IgnoreParens();
return IgnoreDerivedToBase(SourceExprP,
[&](const Expr *E) {
return E == Target || ConditionalOperatorM(E) ||
ElvisOperator(E);
return E == Target || ConditionalOperatorM(E);
}) ||
EvalCommaExpr(SourceExprP, [&](const Expr *E) {
return IgnoreDerivedToBase(
Expand Down
6 changes: 3 additions & 3 deletions clang/lib/Basic/Targets/AArch64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -447,6 +447,9 @@ void AArch64TargetInfo::getTargetDefines(const LangOptions &Opts,
Builder.defineMacro("__ARM_FP16_FORMAT_IEEE", "1");
Builder.defineMacro("__ARM_FP16_ARGS", "1");

// Clang supports arm_neon_sve_bridge.h
Builder.defineMacro("__ARM_NEON_SVE_BRIDGE", "1");

if (Opts.UnsafeFPMath)
Builder.defineMacro("__ARM_FP_FAST", "1");

Expand All @@ -464,9 +467,6 @@ void AArch64TargetInfo::getTargetDefines(const LangOptions &Opts,
if (FPU & SveMode)
Builder.defineMacro("__ARM_FEATURE_SVE", "1");

if ((FPU & NeonMode) && (FPU & SveMode))
Builder.defineMacro("__ARM_NEON_SVE_BRIDGE", "1");

if (HasSVE2)
Builder.defineMacro("__ARM_FEATURE_SVE2", "1");

Expand Down
49 changes: 48 additions & 1 deletion clang/lib/Basic/Targets/WebAssembly.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ static constexpr Builtin::Info BuiltinInfo[] = {
};

static constexpr llvm::StringLiteral ValidCPUNames[] = {
{"mvp"}, {"bleeding-edge"}, {"generic"}};
{"mvp"}, {"bleeding-edge"}, {"generic"}, {"lime"}};

StringRef WebAssemblyTargetInfo::getABI() const { return ABI; }

Expand All @@ -47,6 +47,8 @@ bool WebAssemblyTargetInfo::hasFeature(StringRef Feature) const {
return llvm::StringSwitch<bool>(Feature)
.Case("atomics", HasAtomics)
.Case("bulk-memory", HasBulkMemory)
.Case("bulk-memory-opt", HasBulkMemoryOpt)
.Case("call-indirect-overlong", HasCallIndirectOverlong)
.Case("exception-handling", HasExceptionHandling)
.Case("extended-const", HasExtendedConst)
.Case("fp16", HasFP16)
Expand Down Expand Up @@ -79,6 +81,8 @@ void WebAssemblyTargetInfo::getTargetDefines(const LangOptions &Opts,
Builder.defineMacro("__wasm_atomics__");
if (HasBulkMemory)
Builder.defineMacro("__wasm_bulk_memory__");
if (HasBulkMemoryOpt)
Builder.defineMacro("__wasm_bulk_memory_opt__");
if (HasExceptionHandling)
Builder.defineMacro("__wasm_exception_handling__");
if (HasExtendedConst)
Expand Down Expand Up @@ -155,12 +159,25 @@ bool WebAssemblyTargetInfo::initFeatureMap(
const std::vector<std::string> &FeaturesVec) const {
auto addGenericFeatures = [&]() {
Features["bulk-memory"] = true;
Features["bulk-memory-opt"] = true;
Features["call-indirect-overlong"] = true;
Features["multivalue"] = true;
Features["mutable-globals"] = true;
Features["nontrapping-fptoint"] = true;
Features["reference-types"] = true;
Features["sign-ext"] = true;
};
auto addLime1Features = [&]() {
// Lime1:
// <https://github.com/WebAssembly/tool-conventions/blob/main/Lime.md#lime1>
Features["bulk-memory-opt"] = true;
Features["call-indirect-overlong"] = true;
Features["extended-const"] = true;
Features["multivalue"] = true;
Features["mutable-globals"] = true;
Features["nontrapping-fptoint"] = true;
Features["sign-ext"] = true;
};
auto addBleedingEdgeFeatures = [&]() {
addGenericFeatures();
Features["atomics"] = true;
Expand All @@ -174,6 +191,8 @@ bool WebAssemblyTargetInfo::initFeatureMap(
};
if (CPU == "generic") {
addGenericFeatures();
} else if (CPU == "lime1") {
addLime1Features();
} else if (CPU == "bleeding-edge") {
addBleedingEdgeFeatures();
}
Expand All @@ -200,6 +219,22 @@ bool WebAssemblyTargetInfo::handleTargetFeatures(
HasBulkMemory = false;
continue;
}
if (Feature == "+bulk-memory-opt") {
HasBulkMemoryOpt = true;
continue;
}
if (Feature == "-bulk-memory-opt") {
HasBulkMemoryOpt = false;
continue;
}
if (Feature == "+call-indirect-overlong") {
HasCallIndirectOverlong = true;
continue;
}
if (Feature == "-call-indirect-overlong") {
HasCallIndirectOverlong = false;
continue;
}
if (Feature == "+exception-handling") {
HasExceptionHandling = true;
continue;
Expand Down Expand Up @@ -310,6 +345,18 @@ bool WebAssemblyTargetInfo::handleTargetFeatures(
<< Feature << "-target-feature";
return false;
}

// bulk-memory-opt is a subset of bulk-memory.
if (HasBulkMemory) {
HasBulkMemoryOpt = true;
}

// The reference-types feature included the change to `call_indirect`
// encodings to support overlong immediates.
if (HasReferenceTypes) {
HasCallIndirectOverlong = true;
}

return true;
}

Expand Down
42 changes: 22 additions & 20 deletions clang/lib/Basic/Targets/WebAssembly.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,26 +22,26 @@ namespace clang {
namespace targets {

static const unsigned WebAssemblyAddrSpaceMap[] = {
0, // Default
0, // opencl_global
0, // opencl_local
0, // opencl_constant
0, // opencl_private
0, // opencl_generic
0, // opencl_global_device
0, // opencl_global_host
0, // cuda_device
0, // cuda_constant
0, // cuda_shared
0, // sycl_global
0, // sycl_global_device
0, // sycl_global_host
0, // sycl_local
0, // sycl_private
0, // ptr32_sptr
0, // ptr32_uptr
0, // ptr64
0, // hlsl_groupshared
0, // Default
0, // opencl_global
0, // opencl_local
0, // opencl_constant
0, // opencl_private
0, // opencl_generic
0, // opencl_global_device
0, // opencl_global_host
0, // cuda_device
0, // cuda_constant
0, // cuda_shared
0, // sycl_global
0, // sycl_global_device
0, // sycl_global_host
0, // sycl_local
0, // sycl_private
0, // ptr32_sptr
0, // ptr32_uptr
0, // ptr64
0, // hlsl_groupshared
20, // wasm_funcref
};

Expand All @@ -55,6 +55,8 @@ class LLVM_LIBRARY_VISIBILITY WebAssemblyTargetInfo : public TargetInfo {

bool HasAtomics = false;
bool HasBulkMemory = false;
bool HasBulkMemoryOpt = false;
bool HasCallIndirectOverlong = false;
bool HasExceptionHandling = false;
bool HasExtendedConst = false;
bool HasFP16 = false;
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Basic/Targets/X86.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1162,6 +1162,7 @@ bool X86TargetInfo::isValidFeatureName(StringRef Name) const {
.Case("pconfig", true)
.Case("pku", true)
.Case("popcnt", true)
.Case("prefer-256-bit", true)
.Case("prefetchi", true)
.Case("prfchw", true)
.Case("ptwrite", true)
Expand Down
3 changes: 0 additions & 3 deletions clang/lib/CIR/FrontendAction/CIRGenAction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,6 @@ class CIRGenConsumer : public clang::ASTConsumer {
MlirModule->print(*OutputStream, Flags);
}
break;
default:
llvm_unreachable("NYI: CIRGenAction other than EmitCIR");
break;
}
}
};
Expand Down
186 changes: 135 additions & 51 deletions clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,19 @@ static Value *handleAsDoubleBuiltin(CodeGenFunction &CGF, const CallExpr *E) {
return CGF.Builder.CreateBitCast(BitVec, ResultType);
}

/// Helper for the read/write/add/inc X18 builtins: read the X18 register and
/// return it as an i8 pointer.
Value *readX18AsPtr(CodeGenFunction &CGF) {
LLVMContext &Context = CGF.CGM.getLLVMContext();
llvm::Metadata *Ops[] = {llvm::MDString::get(Context, "x18")};
llvm::MDNode *RegName = llvm::MDNode::get(Context, Ops);
llvm::Value *Metadata = llvm::MetadataAsValue::get(Context, RegName);
llvm::Function *F =
CGF.CGM.getIntrinsic(llvm::Intrinsic::read_register, {CGF.Int64Ty});
llvm::Value *X18 = CGF.Builder.CreateCall(F, Metadata);
return CGF.Builder.CreateIntToPtr(X18, CGF.Int8PtrTy);
}

/// getBuiltinLibFunction - Given a builtin id for a function like
/// "__builtin_fabsf", return a Function* for "fabsf".
llvm::Constant *CodeGenModule::getBuiltinLibFunction(const FunctionDecl *FD,
Expand Down Expand Up @@ -509,8 +522,15 @@ Value *EmitAtomicCmpXchgForMSIntrin(CodeGenFunction &CGF, const CallExpr *E,

Address DestAddr = CheckAtomicAlignment(CGF, E);

auto *Comparand = CGF.EmitScalarExpr(E->getArg(2));
auto *Exchange = CGF.EmitScalarExpr(E->getArg(1));
auto *RTy = Exchange->getType();

auto *Comparand = CGF.EmitScalarExpr(E->getArg(2));

if (RTy->isPointerTy()) {
Exchange = CGF.Builder.CreatePtrToInt(Exchange, CGF.IntPtrTy);
Comparand = CGF.Builder.CreatePtrToInt(Comparand, CGF.IntPtrTy);
}

// For Release ordering, the failure ordering should be Monotonic.
auto FailureOrdering = SuccessOrdering == AtomicOrdering::Release ?
Expand All @@ -521,10 +541,16 @@ Value *EmitAtomicCmpXchgForMSIntrin(CodeGenFunction &CGF, const CallExpr *E,
// blocks the few atomics optimizations that LLVM has. If we want to optimize
// _Interlocked* operations in the future, we will have to remove the volatile
// marker.
auto *Result = CGF.Builder.CreateAtomicCmpXchg(
auto *CmpXchg = CGF.Builder.CreateAtomicCmpXchg(
DestAddr, Comparand, Exchange, SuccessOrdering, FailureOrdering);
Result->setVolatile(true);
return CGF.Builder.CreateExtractValue(Result, 0);
CmpXchg->setVolatile(true);

auto *Result = CGF.Builder.CreateExtractValue(CmpXchg, 0);
if (RTy->isPointerTy()) {
Result = CGF.Builder.CreateIntToPtr(Result, RTy);
}

return Result;
}

// 64-bit Microsoft platforms support 128 bit cmpxchg operations. They are
Expand Down Expand Up @@ -1607,6 +1633,7 @@ enum class CodeGenFunction::MSVCIntrin {
_BitScanForward,
_BitScanReverse,
_InterlockedAnd,
_InterlockedCompareExchange,
_InterlockedDecrement,
_InterlockedExchange,
_InterlockedExchangeAdd,
Expand Down Expand Up @@ -1692,26 +1719,31 @@ translateArmToMsvcIntrin(unsigned BuiltinID) {
case clang::ARM::BI_InterlockedExchange16_acq:
case clang::ARM::BI_InterlockedExchange_acq:
case clang::ARM::BI_InterlockedExchange64_acq:
case clang::ARM::BI_InterlockedExchangePointer_acq:
return MSVCIntrin::_InterlockedExchange_acq;
case clang::ARM::BI_InterlockedExchange8_rel:
case clang::ARM::BI_InterlockedExchange16_rel:
case clang::ARM::BI_InterlockedExchange_rel:
case clang::ARM::BI_InterlockedExchange64_rel:
case clang::ARM::BI_InterlockedExchangePointer_rel:
return MSVCIntrin::_InterlockedExchange_rel;
case clang::ARM::BI_InterlockedExchange8_nf:
case clang::ARM::BI_InterlockedExchange16_nf:
case clang::ARM::BI_InterlockedExchange_nf:
case clang::ARM::BI_InterlockedExchange64_nf:
case clang::ARM::BI_InterlockedExchangePointer_nf:
return MSVCIntrin::_InterlockedExchange_nf;
case clang::ARM::BI_InterlockedCompareExchange8_acq:
case clang::ARM::BI_InterlockedCompareExchange16_acq:
case clang::ARM::BI_InterlockedCompareExchange_acq:
case clang::ARM::BI_InterlockedCompareExchange64_acq:
case clang::ARM::BI_InterlockedCompareExchangePointer_acq:
return MSVCIntrin::_InterlockedCompareExchange_acq;
case clang::ARM::BI_InterlockedCompareExchange8_rel:
case clang::ARM::BI_InterlockedCompareExchange16_rel:
case clang::ARM::BI_InterlockedCompareExchange_rel:
case clang::ARM::BI_InterlockedCompareExchange64_rel:
case clang::ARM::BI_InterlockedCompareExchangePointer_rel:
return MSVCIntrin::_InterlockedCompareExchange_rel;
case clang::ARM::BI_InterlockedCompareExchange8_nf:
case clang::ARM::BI_InterlockedCompareExchange16_nf:
Expand Down Expand Up @@ -1838,26 +1870,31 @@ translateAarch64ToMsvcIntrin(unsigned BuiltinID) {
case clang::AArch64::BI_InterlockedExchange16_acq:
case clang::AArch64::BI_InterlockedExchange_acq:
case clang::AArch64::BI_InterlockedExchange64_acq:
case clang::AArch64::BI_InterlockedExchangePointer_acq:
return MSVCIntrin::_InterlockedExchange_acq;
case clang::AArch64::BI_InterlockedExchange8_rel:
case clang::AArch64::BI_InterlockedExchange16_rel:
case clang::AArch64::BI_InterlockedExchange_rel:
case clang::AArch64::BI_InterlockedExchange64_rel:
case clang::AArch64::BI_InterlockedExchangePointer_rel:
return MSVCIntrin::_InterlockedExchange_rel;
case clang::AArch64::BI_InterlockedExchange8_nf:
case clang::AArch64::BI_InterlockedExchange16_nf:
case clang::AArch64::BI_InterlockedExchange_nf:
case clang::AArch64::BI_InterlockedExchange64_nf:
case clang::AArch64::BI_InterlockedExchangePointer_nf:
return MSVCIntrin::_InterlockedExchange_nf;
case clang::AArch64::BI_InterlockedCompareExchange8_acq:
case clang::AArch64::BI_InterlockedCompareExchange16_acq:
case clang::AArch64::BI_InterlockedCompareExchange_acq:
case clang::AArch64::BI_InterlockedCompareExchange64_acq:
case clang::AArch64::BI_InterlockedCompareExchangePointer_acq:
return MSVCIntrin::_InterlockedCompareExchange_acq;
case clang::AArch64::BI_InterlockedCompareExchange8_rel:
case clang::AArch64::BI_InterlockedCompareExchange16_rel:
case clang::AArch64::BI_InterlockedCompareExchange_rel:
case clang::AArch64::BI_InterlockedCompareExchange64_rel:
case clang::AArch64::BI_InterlockedCompareExchangePointer_rel:
return MSVCIntrin::_InterlockedCompareExchange_rel;
case clang::AArch64::BI_InterlockedCompareExchange8_nf:
case clang::AArch64::BI_InterlockedCompareExchange16_nf:
Expand Down Expand Up @@ -2060,6 +2097,8 @@ Value *CodeGenFunction::EmitMSVCBuiltinExpr(MSVCIntrin BuiltinID,
case MSVCIntrin::_InterlockedExchange_nf:
return MakeBinaryAtomicValue(*this, AtomicRMWInst::Xchg, E,
AtomicOrdering::Monotonic);
case MSVCIntrin::_InterlockedCompareExchange:
return EmitAtomicCmpXchgForMSIntrin(*this, E);
case MSVCIntrin::_InterlockedCompareExchange_acq:
return EmitAtomicCmpXchgForMSIntrin(*this, E, AtomicOrdering::Acquire);
case MSVCIntrin::_InterlockedCompareExchange_rel:
Expand Down Expand Up @@ -5707,32 +5746,11 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
return RValue::get(
EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedExchange, E));
case Builtin::BI_InterlockedCompareExchangePointer:
case Builtin::BI_InterlockedCompareExchangePointer_nf: {
llvm::Type *RTy;
llvm::IntegerType *IntType = IntegerType::get(
getLLVMContext(), getContext().getTypeSize(E->getType()));

Address DestAddr = CheckAtomicAlignment(*this, E);

llvm::Value *Exchange = EmitScalarExpr(E->getArg(1));
RTy = Exchange->getType();
Exchange = Builder.CreatePtrToInt(Exchange, IntType);

llvm::Value *Comparand =
Builder.CreatePtrToInt(EmitScalarExpr(E->getArg(2)), IntType);

auto Ordering =
BuiltinID == Builtin::BI_InterlockedCompareExchangePointer_nf ?
AtomicOrdering::Monotonic : AtomicOrdering::SequentiallyConsistent;

auto Result = Builder.CreateAtomicCmpXchg(DestAddr, Comparand, Exchange,
Ordering, Ordering);
Result->setVolatile(true);

return RValue::get(Builder.CreateIntToPtr(Builder.CreateExtractValue(Result,
0),
RTy));
}
return RValue::get(
EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedCompareExchange, E));
case Builtin::BI_InterlockedCompareExchangePointer_nf:
return RValue::get(
EmitMSVCBuiltinExpr(MSVCIntrin::_InterlockedCompareExchange_nf, E));
case Builtin::BI_InterlockedCompareExchange8:
case Builtin::BI_InterlockedCompareExchange16:
case Builtin::BI_InterlockedCompareExchange:
Expand Down Expand Up @@ -11836,47 +11854,93 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
BuiltinID == AArch64::BI__writex18word ||
BuiltinID == AArch64::BI__writex18dword ||
BuiltinID == AArch64::BI__writex18qword) {
// Process the args first
Value *OffsetArg = EmitScalarExpr(E->getArg(0));
Value *DataArg = EmitScalarExpr(E->getArg(1));

// Read x18 as i8*
LLVMContext &Context = CGM.getLLVMContext();
llvm::Metadata *Ops[] = {llvm::MDString::get(Context, "x18")};
llvm::MDNode *RegName = llvm::MDNode::get(Context, Ops);
llvm::Value *Metadata = llvm::MetadataAsValue::get(Context, RegName);
llvm::Function *F =
CGM.getIntrinsic(llvm::Intrinsic::read_register, {Int64Ty});
llvm::Value *X18 = Builder.CreateCall(F, Metadata);
X18 = Builder.CreateIntToPtr(X18, Int8PtrTy);
llvm::Value *X18 = readX18AsPtr(*this);

// Store val at x18 + offset
Value *Offset = Builder.CreateZExt(EmitScalarExpr(E->getArg(0)), Int64Ty);
Value *Offset = Builder.CreateZExt(OffsetArg, Int64Ty);
Value *Ptr = Builder.CreateGEP(Int8Ty, X18, Offset);
Value *Val = EmitScalarExpr(E->getArg(1));
StoreInst *Store = Builder.CreateAlignedStore(Val, Ptr, CharUnits::One());
StoreInst *Store =
Builder.CreateAlignedStore(DataArg, Ptr, CharUnits::One());
return Store;
}

if (BuiltinID == AArch64::BI__readx18byte ||
BuiltinID == AArch64::BI__readx18word ||
BuiltinID == AArch64::BI__readx18dword ||
BuiltinID == AArch64::BI__readx18qword) {
llvm::Type *IntTy = ConvertType(E->getType());
// Process the args first
Value *OffsetArg = EmitScalarExpr(E->getArg(0));

// Read x18 as i8*
LLVMContext &Context = CGM.getLLVMContext();
llvm::Metadata *Ops[] = {llvm::MDString::get(Context, "x18")};
llvm::MDNode *RegName = llvm::MDNode::get(Context, Ops);
llvm::Value *Metadata = llvm::MetadataAsValue::get(Context, RegName);
llvm::Function *F =
CGM.getIntrinsic(llvm::Intrinsic::read_register, {Int64Ty});
llvm::Value *X18 = Builder.CreateCall(F, Metadata);
X18 = Builder.CreateIntToPtr(X18, Int8PtrTy);
llvm::Value *X18 = readX18AsPtr(*this);

// Load x18 + offset
Value *Offset = Builder.CreateZExt(EmitScalarExpr(E->getArg(0)), Int64Ty);
Value *Offset = Builder.CreateZExt(OffsetArg, Int64Ty);
Value *Ptr = Builder.CreateGEP(Int8Ty, X18, Offset);
llvm::Type *IntTy = ConvertType(E->getType());
LoadInst *Load = Builder.CreateAlignedLoad(IntTy, Ptr, CharUnits::One());
return Load;
}

if (BuiltinID == AArch64::BI__addx18byte ||
BuiltinID == AArch64::BI__addx18word ||
BuiltinID == AArch64::BI__addx18dword ||
BuiltinID == AArch64::BI__addx18qword ||
BuiltinID == AArch64::BI__incx18byte ||
BuiltinID == AArch64::BI__incx18word ||
BuiltinID == AArch64::BI__incx18dword ||
BuiltinID == AArch64::BI__incx18qword) {
llvm::Type *IntTy;
bool isIncrement;
switch (BuiltinID) {
case AArch64::BI__incx18byte:
IntTy = Int8Ty;
isIncrement = true;
break;
case AArch64::BI__incx18word:
IntTy = Int16Ty;
isIncrement = true;
break;
case AArch64::BI__incx18dword:
IntTy = Int32Ty;
isIncrement = true;
break;
case AArch64::BI__incx18qword:
IntTy = Int64Ty;
isIncrement = true;
break;
default:
IntTy = ConvertType(E->getArg(1)->getType());
isIncrement = false;
break;
}
// Process the args first
Value *OffsetArg = EmitScalarExpr(E->getArg(0));
Value *ValToAdd =
isIncrement ? ConstantInt::get(IntTy, 1) : EmitScalarExpr(E->getArg(1));

// Read x18 as i8*
llvm::Value *X18 = readX18AsPtr(*this);

// Load x18 + offset
Value *Offset = Builder.CreateZExt(OffsetArg, Int64Ty);
Value *Ptr = Builder.CreateGEP(Int8Ty, X18, Offset);
LoadInst *Load = Builder.CreateAlignedLoad(IntTy, Ptr, CharUnits::One());

// Add values
Value *AddResult = Builder.CreateAdd(Load, ValToAdd);

// Store val at x18 + offset
StoreInst *Store =
Builder.CreateAlignedStore(AddResult, Ptr, CharUnits::One());
return Store;
}

if (BuiltinID == AArch64::BI_CopyDoubleFromInt64 ||
BuiltinID == AArch64::BI_CopyFloatFromInt32 ||
BuiltinID == AArch64::BI_CopyInt32FromFloat ||
Expand Down Expand Up @@ -19060,6 +19124,16 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
return nullptr;

switch (BuiltinID) {
case Builtin::BI__builtin_hlsl_resource_getpointer: {
Value *HandleOp = EmitScalarExpr(E->getArg(0));
Value *IndexOp = EmitScalarExpr(E->getArg(1));

// TODO: Map to an hlsl_device address space.
llvm::Type *RetTy = llvm::PointerType::getUnqual(getLLVMContext());

return Builder.CreateIntrinsic(RetTy, Intrinsic::dx_resource_getpointer,
ArrayRef<Value *>{HandleOp, IndexOp});
}
case Builtin::BI__builtin_hlsl_all: {
Value *Op0 = EmitScalarExpr(E->getArg(0));
return Builder.CreateIntrinsic(
Expand Down Expand Up @@ -19446,6 +19520,12 @@ case Builtin::BI__builtin_hlsl_elementwise_isinf: {
assert(E->getArg(0)->getType()->hasFloatingRepresentation() &&
"clip operands types mismatch");
return handleHlslClip(E, this);
case Builtin::BI__builtin_hlsl_group_memory_barrier_with_group_sync: {
Intrinsic::ID ID =
CGM.getHLSLRuntime().getGroupMemoryBarrierWithGroupSyncIntrinsic();
return EmitRuntimeCall(
Intrinsic::getOrInsertDeclaration(&CGM.getModule(), ID));
}
}
return nullptr;
}
Expand Down Expand Up @@ -19726,6 +19806,8 @@ Value *CodeGenFunction::EmitAMDGPUBuiltinExpr(unsigned BuiltinID,
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_v4f16:
case AMDGPU::BI__builtin_amdgcn_ds_read_tr16_b64_v4bf16:
case AMDGPU::BI__builtin_amdgcn_ds_read_tr16_b64_v4i16: {
Intrinsic::ID IID;
switch (BuiltinID) {
Expand All @@ -19751,6 +19833,8 @@ Value *CodeGenFunction::EmitAMDGPUBuiltinExpr(unsigned BuiltinID,
IID = Intrinsic::amdgcn_ds_read_tr6_b96;
break;
case AMDGPU::BI__builtin_amdgcn_ds_read_tr16_b64_v4i16:
case AMDGPU::BI__builtin_amdgcn_ds_read_tr16_b64_v4f16:
case AMDGPU::BI__builtin_amdgcn_ds_read_tr16_b64_v4bf16:
IID = Intrinsic::amdgcn_ds_read_tr16_b64;
break;
}
Expand Down
20 changes: 15 additions & 5 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 @@ -4725,15 +4725,17 @@ void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E,
return emitWritebackArg(*this, args, CRE);
}

assert(type->isReferenceType() == E->isGLValue() &&
"reference binding to unmaterialized r-value!");

// Add writeback for HLSLOutParamExpr.
// Needs to be before the assert below because HLSLOutArgExpr is an LValue
// and is not a reference.
if (const HLSLOutArgExpr *OE = dyn_cast<HLSLOutArgExpr>(E)) {
EmitHLSLOutArgExpr(OE, args, type);
return;
}

assert(type->isReferenceType() == E->isGLValue() &&
"reference binding to unmaterialized r-value!");

if (E->isGLValue()) {
assert(E->getObjectKind() == OK_Ordinary);
return args.add(EmitReferenceBindingToExpr(E), type);
Expand Down Expand Up @@ -5322,6 +5324,14 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
IRCallArgs[FirstIRArg] = Val;
break;
}
} else if (I->getType()->isArrayParameterType()) {
// Don't produce a temporary for ArrayParameterType arguments.
// ArrayParameterType arguments are only created from
// HLSL_ArrayRValue casts and HLSLOutArgExpr expressions, both
// of which create temporaries already. This allows us to just use the
// scalar for the decayed array pointer as the argument directly.
IRCallArgs[FirstIRArg] = I->getKnownRValue().getScalarVal();
break;
}

// For non-aggregate args and aggregate args meeting conditions above
Expand Down
7 changes: 5 additions & 2 deletions clang/lib/CodeGen/CGExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5827,9 +5827,12 @@ LValue CodeGenFunction::EmitBinaryOperatorLValue(const BinaryOperator *E) {
// This function implements trivial copy assignment for HLSL's
// assignable constant arrays.
LValue CodeGenFunction::EmitHLSLArrayAssignLValue(const BinaryOperator *E) {
LValue TrivialAssignmentRHS = EmitLValue(E->getRHS());
// Don't emit an LValue for the RHS because it might not be an LValue
LValue LHS = EmitLValue(E->getLHS());
EmitAggregateAssign(LHS, TrivialAssignmentRHS, E->getLHS()->getType());
// In C the RHS of an assignment operator is an RValue.
// EmitAggregateAssign takes anan LValue for the RHS. Instead we can call
// EmitInitializationToLValue to emit an RValue into an LValue.
EmitInitializationToLValue(E->getRHS(), LHS);
return LHS;
}

Expand Down
2 changes: 2 additions & 0 deletions clang/lib/CodeGen/CGHLSLRuntime.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ class CGHLSLRuntime {

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

//===----------------------------------------------------------------------===//
// End of reserved area for HLSL intrinsic getters.
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/CodeGen/CGLoopInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -811,7 +811,7 @@ void LoopInfoStack::push(BasicBlock *Header, clang::ASTContext &Ctx,
// Identify loop attribute 'code_align' from Attrs.
// For attribute code_align:
// n - 'llvm.loop.align i32 n' metadata will be emitted.
if (const auto *CodeAlign = getSpecificAttr<const CodeAlignAttr>(Attrs)) {
if (const auto *CodeAlign = getSpecificAttr<CodeAlignAttr>(Attrs)) {
const auto *CE = cast<ConstantExpr>(CodeAlign->getAlignment());
llvm::APSInt ArgVal = CE->getResultAsAPSInt();
setCodeAlign(ArgVal.getSExtValue());
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/CodeGen/CodeGenFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -899,6 +899,8 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
Fn->addFnAttr("ptrauth-auth-traps");
if (CodeGenOpts.PointerAuth.IndirectGotos)
Fn->addFnAttr("ptrauth-indirect-gotos");
if (CodeGenOpts.PointerAuth.AArch64JumpTableHardening)
Fn->addFnAttr("aarch64-jump-table-hardening");

// Apply xray attributes to the function (as a string, for now)
bool AlwaysXRayAttr = false;
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -602,7 +602,8 @@ static bool checkAliasedGlobal(
// mangled name.
for (const auto &[Decl, Name] : MangledDeclNames) {
if (const auto *ND = dyn_cast<NamedDecl>(Decl.getDecl())) {
if (ND->getName() == GV->getName()) {
IdentifierInfo *II = ND->getIdentifier();
if (II && II->getName() == GV->getName()) {
Diags.Report(Location, diag::note_alias_mangled_name_alternative)
<< Name
<< FixItHint::CreateReplacement(
Expand Down
45 changes: 16 additions & 29 deletions clang/lib/Driver/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -998,14 +998,12 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C,
//
}

static void appendOneArg(InputArgList &Args, const Arg *Opt,
const Arg *BaseArg) {
static void appendOneArg(InputArgList &Args, const Arg *Opt) {
// The args for config files or /clang: flags belong to different InputArgList
// objects than Args. This copies an Arg from one of those other InputArgLists
// to the ownership of Args.
unsigned Index = Args.MakeIndex(Opt->getSpelling());
Arg *Copy = new llvm::opt::Arg(Opt->getOption(), Args.getArgString(Index),
Index, BaseArg);
Arg *Copy = new Arg(Opt->getOption(), Args.getArgString(Index), Index);
Copy->getValues() = Opt->getValues();
if (Opt->isClaimed())
Copy->claim();
Expand Down Expand Up @@ -1052,7 +1050,7 @@ bool Driver::readConfigFile(StringRef FileName,
llvm::SmallString<128> CfgFileName(FileName);
llvm::sys::path::native(CfgFileName);
bool ContainErrors;
std::unique_ptr<InputArgList> NewOptions = std::make_unique<InputArgList>(
auto NewOptions = std::make_unique<InputArgList>(
ParseArgStrings(NewCfgArgs, /*UseDriverMode=*/true, ContainErrors));
if (ContainErrors)
return true;
Expand All @@ -1066,12 +1064,8 @@ bool Driver::readConfigFile(StringRef FileName,
CfgOptions = std::move(NewOptions);
else {
// If this is a subsequent config file, append options to the previous one.
for (auto *Opt : *NewOptions) {
const Arg *BaseArg = &Opt->getBaseArg();
if (BaseArg == Opt)
BaseArg = nullptr;
appendOneArg(*CfgOptions, Opt, BaseArg);
}
for (auto *Opt : *NewOptions)
appendOneArg(*CfgOptions, Opt);
}
ConfigFiles.push_back(std::string(CfgFileName));
return false;
Expand Down Expand Up @@ -1256,14 +1250,9 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
: std::move(*CLOptions));

if (HasConfigFile)
for (auto *Opt : *CLOptions) {
if (Opt->getOption().matches(options::OPT_config))
continue;
const Arg *BaseArg = &Opt->getBaseArg();
if (BaseArg == Opt)
BaseArg = nullptr;
appendOneArg(Args, Opt, BaseArg);
}
for (auto *Opt : *CLOptions)
if (!Opt->getOption().matches(options::OPT_config))
appendOneArg(Args, Opt);

// In CL mode, look for any pass-through arguments
if (IsCLMode() && !ContainsError) {
Expand All @@ -1281,9 +1270,8 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) {
ContainsError));

if (!ContainsError)
for (auto *Opt : *CLModePassThroughOptions) {
appendOneArg(Args, Opt, nullptr);
}
for (auto *Opt : *CLModePassThroughOptions)
appendOneArg(Args, Opt);
}
}

Expand Down Expand Up @@ -4063,17 +4051,18 @@ void Driver::handleArguments(Compilation &C, DerivedArgList &Args,
YcArg = YuArg = nullptr;
}

unsigned LastPLSize = 0;
bool LinkOnly = phases::Link == FinalPhase && Inputs.size() > 0;
for (auto &I : Inputs) {
types::ID InputType = I.first;
const Arg *InputArg = I.second;

auto PL = types::getCompilationPhases(InputType);
LastPLSize = PL.size();

phases::ID InitialPhase = PL[0];
LinkOnly = LinkOnly && phases::Link == InitialPhase && PL.size() == 1;

// If the first step comes after the final phase we are doing as part of
// this compilation, warn the user about it.
phases::ID InitialPhase = PL[0];
if (InitialPhase > FinalPhase) {
if (InputArg->isClaimed())
continue;
Expand Down Expand Up @@ -4128,10 +4117,8 @@ void Driver::handleArguments(Compilation &C, DerivedArgList &Args,
}
}

// If we are linking, claim any options which are obviously only used for
// compilation.
// FIXME: Understand why the last Phase List length is used here.
if (FinalPhase == phases::Link && LastPLSize == 1) {
// Claim any options which are obviously only used for compilation.
if (LinkOnly) {
Args.ClaimAllArgs(options::OPT_CompileOnly_Group);
Args.ClaimAllArgs(options::OPT_cl_compile_Group);
}
Expand Down
Loading