diff --git a/.github/workflows/libcxx-build-and-test.yaml b/.github/workflows/libcxx-build-and-test.yaml index b5e60781e0006..184fed2268e81 100644 --- a/.github/workflows/libcxx-build-and-test.yaml +++ b/.github/workflows/libcxx-build-and-test.yaml @@ -193,17 +193,24 @@ jobs: **/crash_diagnostics/* macos: - runs-on: macos-14 needs: [ stage1 ] strategy: - fail-fast: true + fail-fast: false matrix: - config: [ - generic-cxx03, - generic-cxx23, - generic-modules, - apple-configuration - ] + include: + - config: generic-cxx03 + os: macos-latest + - config: generic-cxx23 + os: macos-latest + - config: generic-modules + os: macos-latest + - config: apple-configuration + os: macos-latest + - config: apple-system + os: macos-13 + - config: apple-system-hardened + os: macos-13 + runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 - uses: maxim-lobanov/setup-xcode@v1 diff --git a/.github/workflows/release-binaries.yml b/.github/workflows/release-binaries.yml index 925912df6843e..f24e25879b96b 100644 --- a/.github/workflows/release-binaries.yml +++ b/.github/workflows/release-binaries.yml @@ -420,6 +420,14 @@ jobs: attestations: write # For artifact attestations steps: + - name: Checkout Release Scripts + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + sparse-checkout: | + llvm/utils/release/github-upload-release.py + llvm/utils/git/requirements.txt + sparse-checkout-cone-mode: false + - name: 'Download artifact' uses: actions/download-artifact@6b208ae046db98c579e8a3aa621ab581ff575935 # v4.1.1 with: @@ -442,14 +450,6 @@ jobs: name: ${{ needs.prepare.outputs.release-binary-filename }}-attestation path: ${{ needs.prepare.outputs.release-binary-filename }}.jsonl - - name: Checkout Release Scripts - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - sparse-checkout: | - llvm/utils/release/github-upload-release.py - llvm/utils/git/requirements.txt - sparse-checkout-cone-mode: false - - name: Install Python Requirements run: | pip install --require-hashes -r ./llvm/utils/git/requirements.txt diff --git a/.github/workflows/release-documentation.yml b/.github/workflows/release-documentation.yml index 70e5f08b6f72e..922c5093f1357 100644 --- a/.github/workflows/release-documentation.yml +++ b/.github/workflows/release-documentation.yml @@ -72,17 +72,20 @@ jobs: ref: main fetch-depth: 0 path: www-releases + persist-credentials: false - name: Upload Release Notes if: env.upload env: - WWW_RELEASES_TOKEN: ${{ secrets.WWW_RELEASES_TOKEN }} + GH_TOKEN: ${{ secrets.WWW_RELEASES_TOKEN }} run: | - mkdir -p ../www-releases/${{ inputs.release-version }} - mv ./docs-build/html-export/* ../www-releases/${{ inputs.release-version }} - cd ../www-releases + mkdir -p www-releases/${{ inputs.release-version }} + mv ./docs-build/html-export/* www-releases/${{ inputs.release-version }} + cd www-releases + git checkout -b ${{ inputs.release-version }} git add ${{ inputs.release-version }} git config user.email "llvmbot@llvm.org" git config user.name "llvmbot" git commit -a -m "Add ${{ inputs.release-version }} documentation" - git push "https://$WWW_RELEASES_TOKEN@github.com/${{ github.repository_owner }}/www-releases" main:main + git push --force "https://$GH_TOKEN@github.com/llvmbot/www-releases.git" HEAD:refs/heads/${{ inputs.release-version }} + gh pr create -f -B main -H ${{ inputs.release-version }} -R llvmbot/www-releases diff --git a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp index 689eb92a3d8d1..642f025359b1d 100644 --- a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp @@ -78,6 +78,7 @@ #include "SuspiciousStringviewDataUsageCheck.h" #include "SwappedArgumentsCheck.h" #include "SwitchMissingDefaultCaseCheck.h" +#include "TaggedUnionMemberCountCheck.h" #include "TerminatingContinueCheck.h" #include "ThrowKeywordMissingCheck.h" #include "TooSmallLoopVariableCheck.h" @@ -229,6 +230,8 @@ class BugproneModule : public ClangTidyModule { "bugprone-suspicious-stringview-data-usage"); CheckFactories.registerCheck( "bugprone-swapped-arguments"); + CheckFactories.registerCheck( + "bugprone-tagged-union-member-count"); CheckFactories.registerCheck( "bugprone-terminating-continue"); CheckFactories.registerCheck( diff --git a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt index cb0d8ae98bac5..9f7ecb9623c53 100644 --- a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt @@ -73,6 +73,7 @@ add_clang_library(clangTidyBugproneModule SuspiciousSemicolonCheck.cpp SuspiciousStringCompareCheck.cpp SwappedArgumentsCheck.cpp + TaggedUnionMemberCountCheck.cpp TerminatingContinueCheck.cpp ThrowKeywordMissingCheck.cpp TooSmallLoopVariableCheck.cpp diff --git a/clang-tools-extra/clang-tidy/bugprone/TaggedUnionMemberCountCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/TaggedUnionMemberCountCheck.cpp new file mode 100644 index 0000000000000..db99ef3786e5f --- /dev/null +++ b/clang-tools-extra/clang-tidy/bugprone/TaggedUnionMemberCountCheck.cpp @@ -0,0 +1,199 @@ +//===--- TaggedUnionMemberCountCheck.cpp - clang-tidy ---------------------===// +// +// 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 "TaggedUnionMemberCountCheck.h" +#include "../utils/OptionsUtils.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallSet.h" + +using namespace clang::ast_matchers; + +namespace clang::tidy::bugprone { + +static constexpr llvm::StringLiteral StrictModeOptionName = "StrictMode"; +static constexpr llvm::StringLiteral EnableCountingEnumHeuristicOptionName = + "EnableCountingEnumHeuristic"; +static constexpr llvm::StringLiteral CountingEnumPrefixesOptionName = + "CountingEnumPrefixes"; +static constexpr llvm::StringLiteral CountingEnumSuffixesOptionName = + "CountingEnumSuffixes"; + +static constexpr bool StrictModeOptionDefaultValue = false; +static constexpr bool EnableCountingEnumHeuristicOptionDefaultValue = true; +static constexpr llvm::StringLiteral CountingEnumPrefixesOptionDefaultValue = + ""; +static constexpr llvm::StringLiteral CountingEnumSuffixesOptionDefaultValue = + "count"; + +static constexpr llvm::StringLiteral RootMatchBindName = "root"; +static constexpr llvm::StringLiteral UnionMatchBindName = "union"; +static constexpr llvm::StringLiteral TagMatchBindName = "tags"; + +namespace { + +AST_MATCHER_P2(RecordDecl, fieldCountOfKindIsOne, + ast_matchers::internal::Matcher, InnerMatcher, + StringRef, BindName) { + // BoundNodesTreeBuilder resets itself when a match occurs. + // So to avoid losing previously saved binds, a temporary instance + // is used for matching. + // + // For precedence, see commit: 5b07de1a5faf4a22ae6fd982b877c5e7e3a76559 + clang::ast_matchers::internal::BoundNodesTreeBuilder TempBuilder; + + const FieldDecl *FirstMatch = nullptr; + for (const FieldDecl *Field : Node.fields()) { + if (InnerMatcher.matches(*Field, Finder, &TempBuilder)) { + if (FirstMatch) { + return false; + } else { + FirstMatch = Field; + } + } + } + + if (FirstMatch) { + Builder->setBinding(BindName, clang::DynTypedNode::create(*FirstMatch)); + return true; + } + return false; +} + +} // namespace + +TaggedUnionMemberCountCheck::TaggedUnionMemberCountCheck( + StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context), + StrictMode( + Options.get(StrictModeOptionName, StrictModeOptionDefaultValue)), + EnableCountingEnumHeuristic( + Options.get(EnableCountingEnumHeuristicOptionName, + EnableCountingEnumHeuristicOptionDefaultValue)), + CountingEnumPrefixes(utils::options::parseStringList( + Options.get(CountingEnumPrefixesOptionName, + CountingEnumPrefixesOptionDefaultValue))), + CountingEnumSuffixes(utils::options::parseStringList( + Options.get(CountingEnumSuffixesOptionName, + CountingEnumSuffixesOptionDefaultValue))) { + if (!EnableCountingEnumHeuristic) { + if (Options.get(CountingEnumPrefixesOptionName)) + configurationDiag("%0: Counting enum heuristic is disabled but " + "%1 is set") + << Name << CountingEnumPrefixesOptionName; + if (Options.get(CountingEnumSuffixesOptionName)) + configurationDiag("%0: Counting enum heuristic is disabled but " + "%1 is set") + << Name << CountingEnumSuffixesOptionName; + } +} + +void TaggedUnionMemberCountCheck::storeOptions( + ClangTidyOptions::OptionMap &Opts) { + Options.store(Opts, StrictModeOptionName, StrictMode); + Options.store(Opts, EnableCountingEnumHeuristicOptionName, + EnableCountingEnumHeuristic); + Options.store(Opts, CountingEnumPrefixesOptionName, + utils::options::serializeStringList(CountingEnumPrefixes)); + Options.store(Opts, CountingEnumSuffixesOptionName, + utils::options::serializeStringList(CountingEnumSuffixes)); +} + +void TaggedUnionMemberCountCheck::registerMatchers(MatchFinder *Finder) { + + auto UnionField = fieldDecl(hasType(qualType( + hasCanonicalType(recordType(hasDeclaration(recordDecl(isUnion()))))))); + + auto EnumField = fieldDecl(hasType( + qualType(hasCanonicalType(enumType(hasDeclaration(enumDecl())))))); + + auto hasOneUnionField = fieldCountOfKindIsOne(UnionField, UnionMatchBindName); + auto hasOneEnumField = fieldCountOfKindIsOne(EnumField, TagMatchBindName); + + Finder->addMatcher(recordDecl(anyOf(isStruct(), isClass()), hasOneUnionField, + hasOneEnumField, unless(isImplicit())) + .bind(RootMatchBindName), + this); +} + +bool TaggedUnionMemberCountCheck::isCountingEnumLikeName(StringRef Name) const { + if (llvm::any_of(CountingEnumPrefixes, [Name](StringRef Prefix) -> bool { + return Name.starts_with_insensitive(Prefix); + })) + return true; + if (llvm::any_of(CountingEnumSuffixes, [Name](StringRef Suffix) -> bool { + return Name.ends_with_insensitive(Suffix); + })) + return true; + return false; +} + +std::pair +TaggedUnionMemberCountCheck::getNumberOfEnumValues(const EnumDecl *ED) { + llvm::SmallSet EnumValues; + + const EnumConstantDecl *LastEnumConstant = nullptr; + for (const EnumConstantDecl *Enumerator : ED->enumerators()) { + EnumValues.insert(Enumerator->getInitVal()); + LastEnumConstant = Enumerator; + } + + if (EnableCountingEnumHeuristic && LastEnumConstant && + isCountingEnumLikeName(LastEnumConstant->getName()) && + (LastEnumConstant->getInitVal() == (EnumValues.size() - 1))) { + return {EnumValues.size() - 1, LastEnumConstant}; + } + + return {EnumValues.size(), nullptr}; +} + +void TaggedUnionMemberCountCheck::check( + const MatchFinder::MatchResult &Result) { + const auto *Root = Result.Nodes.getNodeAs(RootMatchBindName); + const auto *UnionField = + Result.Nodes.getNodeAs(UnionMatchBindName); + const auto *TagField = Result.Nodes.getNodeAs(TagMatchBindName); + + assert(Root && "Root is missing!"); + assert(UnionField && "UnionField is missing!"); + assert(TagField && "TagField is missing!"); + if (!Root || !UnionField || !TagField) + return; + + const auto *UnionDef = + UnionField->getType().getCanonicalType().getTypePtr()->getAsRecordDecl(); + const auto *EnumDef = llvm::dyn_cast( + TagField->getType().getCanonicalType().getTypePtr()->getAsTagDecl()); + + assert(UnionDef && "UnionDef is missing!"); + assert(EnumDef && "EnumDef is missing!"); + if (!UnionDef || !EnumDef) + return; + + const std::size_t UnionMemberCount = llvm::range_size(UnionDef->fields()); + auto [TagCount, CountingEnumConstantDecl] = getNumberOfEnumValues(EnumDef); + + if (UnionMemberCount > TagCount) { + diag(Root->getLocation(), + "tagged union has more data members (%0) than tags (%1)!") + << UnionMemberCount << TagCount; + } else if (StrictMode && UnionMemberCount < TagCount) { + diag(Root->getLocation(), + "tagged union has fewer data members (%0) than tags (%1)!") + << UnionMemberCount << TagCount; + } + + if (CountingEnumConstantDecl) { + diag(CountingEnumConstantDecl->getLocation(), + "assuming that this constant is just an auxiliary value and not " + "used for indicating a valid union data member", + DiagnosticIDs::Note); + } +} + +} // namespace clang::tidy::bugprone diff --git a/clang-tools-extra/clang-tidy/bugprone/TaggedUnionMemberCountCheck.h b/clang-tools-extra/clang-tidy/bugprone/TaggedUnionMemberCountCheck.h new file mode 100644 index 0000000000000..8b9d677d00b40 --- /dev/null +++ b/clang-tools-extra/clang-tidy/bugprone/TaggedUnionMemberCountCheck.h @@ -0,0 +1,41 @@ +//===--- TaggedUnionMemberCountCheck.h - clang-tidy -------------*- 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_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_TAGGEDUNIONMEMBERCOUNTCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_TAGGEDUNIONMEMBERCOUNTCHECK_H + +#include "../ClangTidyCheck.h" + +namespace clang::tidy::bugprone { + +/// Gives warnings for tagged unions, where the number of tags is +/// different from the number of data members inside the union. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone/tagged-union-member-count.html +class TaggedUnionMemberCountCheck : public ClangTidyCheck { +public: + TaggedUnionMemberCountCheck(StringRef Name, ClangTidyContext *Context); + void storeOptions(ClangTidyOptions::OptionMap &Opts) override; + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; + +private: + const bool StrictMode; + const bool EnableCountingEnumHeuristic; + const std::vector CountingEnumPrefixes; + const std::vector CountingEnumSuffixes; + + std::pair + getNumberOfEnumValues(const EnumDecl *ED); + bool isCountingEnumLikeName(StringRef Name) const; +}; + +} // namespace clang::tidy::bugprone + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_TAGGEDUNIONMEMBERCOUNTCHECK_H diff --git a/clang-tools-extra/clang-tidy/misc/UnusedUsingDeclsCheck.cpp b/clang-tools-extra/clang-tidy/misc/UnusedUsingDeclsCheck.cpp index 90b317527ee41..1ff61bae46b1e 100644 --- a/clang-tools-extra/clang-tidy/misc/UnusedUsingDeclsCheck.cpp +++ b/clang-tools-extra/clang-tidy/misc/UnusedUsingDeclsCheck.cpp @@ -25,6 +25,13 @@ AST_MATCHER_P(DeducedTemplateSpecializationType, refsToTemplatedDecl, return false; } +AST_MATCHER_P(Type, asTagDecl, clang::ast_matchers::internal::Matcher, + DeclMatcher) { + if (const TagDecl *ND = Node.getAsTagDecl()) + return DeclMatcher.matches(*ND, Finder, Builder); + return false; +} + } // namespace // A function that helps to tell whether a TargetDecl in a UsingDecl will be @@ -61,7 +68,8 @@ void UnusedUsingDeclsCheck::registerMatchers(MatchFinder *Finder) { Finder->addMatcher(userDefinedLiteral().bind("used"), this); Finder->addMatcher( loc(elaboratedType(unless(hasQualifier(nestedNameSpecifier())), - hasUnqualifiedDesugaredType(type().bind("usedType")))), + hasUnqualifiedDesugaredType( + type(asTagDecl(tagDecl().bind("used")))))), this); // Cases where we can identify the UsingShadowDecl directly, rather than // just its target. @@ -139,12 +147,6 @@ void UnusedUsingDeclsCheck::check(const MatchFinder::MatchResult &Result) { return; } - if (const auto *T = Result.Nodes.getNodeAs("usedType")) { - if (const auto *ND = T->getAsTagDecl()) - RemoveNamedDecl(ND); - return; - } - if (const auto *UsedShadow = Result.Nodes.getNodeAs("usedShadow")) { removeFromFoundDecls(UsedShadow->getTargetDecl()); diff --git a/clang-tools-extra/clangd/index/SymbolCollector.cpp b/clang-tools-extra/clangd/index/SymbolCollector.cpp index a76894cf0855f..d1d744a21cfd5 100644 --- a/clang-tools-extra/clangd/index/SymbolCollector.cpp +++ b/clang-tools-extra/clangd/index/SymbolCollector.cpp @@ -41,6 +41,7 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" @@ -75,18 +76,62 @@ bool isPrivateProtoDecl(const NamedDecl &ND) { if (ND.getIdentifier() == nullptr) return false; auto Name = ND.getIdentifier()->getName(); - if (!Name.contains('_')) - return false; - // Nested proto entities (e.g. Message::Nested) have top-level decls - // that shouldn't be used (Message_Nested). Ignore them completely. - // The nested entities are dangling type aliases, we may want to reconsider - // including them in the future. - // For enum constants, SOME_ENUM_CONSTANT is not private and should be - // indexed. Outer_INNER is private. This heuristic relies on naming style, it - // will include OUTER_INNER and exclude some_enum_constant. - // FIXME: the heuristic relies on naming style (i.e. no underscore in - // user-defined names) and can be improved. - return (ND.getKind() != Decl::EnumConstant) || llvm::any_of(Name, islower); + // There are some internal helpers like _internal_set_foo(); + if (Name.contains("_internal_")) + return true; + + // https://protobuf.dev/reference/cpp/cpp-generated/#nested-types + // Nested entities (messages/enums) has two names, one at the top-level scope, + // with a mangled name created by prepending all the outer types. These names + // are almost never preferred by the developers, so exclude them from index. + // e.g. + // message Foo { + // message Bar {} + // enum E { A } + // } + // + // yields: + // class Foo_Bar {}; + // enum Foo_E { Foo_E_A }; + // class Foo { + // using Bar = Foo_Bar; + // static constexpr Foo_E A = Foo_E_A; + // }; + + // We get rid of Foo_Bar and Foo_E by discarding any top-level entries with + // `_` in the name. This relies on original message/enum not having `_` in the + // name. Hence might go wrong in certain cases. + if (ND.getDeclContext()->isNamespace()) { + // Strip off some known public suffix helpers for enums, rest of the helpers + // are generated inside record decls so we don't care. + // https://protobuf.dev/reference/cpp/cpp-generated/#enum + Name.consume_back("_descriptor"); + Name.consume_back("_IsValid"); + Name.consume_back("_Name"); + Name.consume_back("_Parse"); + Name.consume_back("_MIN"); + Name.consume_back("_MAX"); + Name.consume_back("_ARRAYSIZE"); + return Name.contains('_'); + } + + // EnumConstantDecls need some special attention, despite being nested in a + // TagDecl, they might still have mangled names. We filter those by checking + // if it has parent's name as a prefix. + // This might go wrong if a nested entity has a name that starts with parent's + // name, e.g: enum Foo { Foo_X }. + if (llvm::isa(&ND)) { + auto *DC = llvm::cast(ND.getDeclContext()); + if (!DC || !DC->getIdentifier()) + return false; + auto CtxName = DC->getIdentifier()->getName(); + return !CtxName.empty() && Name.consume_front(CtxName) && + Name.consume_front("_"); + } + + // Now we're only left with fields/methods without an `_internal_` in the + // name, they're intended for public use. + return false; } // We only collect #include paths for symbols that are suitable for global code diff --git a/clang-tools-extra/clangd/unittests/SymbolCollectorTests.cpp b/clang-tools-extra/clangd/unittests/SymbolCollectorTests.cpp index 0666be95b6b9e..e8088cb37fa51 100644 --- a/clang-tools-extra/clangd/unittests/SymbolCollectorTests.cpp +++ b/clang-tools-extra/clangd/unittests/SymbolCollectorTests.cpp @@ -201,19 +201,63 @@ TEST_F(ShouldCollectSymbolTest, NoPrivateProtoSymbol) { build( R"(// Generated by the protocol buffer compiler. DO NOT EDIT! namespace nx { - class Top_Level {}; - class TopLevel {}; - enum Kind { - KIND_OK, - Kind_Not_Ok, + enum Outer_Enum : int { + Outer_Enum_KIND1, + Outer_Enum_Kind_2, }; + bool Outer_Enum_IsValid(int); + + class Outer_Inner {}; + class Outer { + using Inner = Outer_Inner; + using Enum = Outer_Enum; + static constexpr Enum KIND1 = Outer_Enum_KIND1; + static constexpr Enum Kind_2 = Outer_Enum_Kind_2; + static bool Enum_IsValid(int); + int &x(); + void set_x(); + void _internal_set_x(); + + int &Outer_y(); + }; + enum Foo { + FOO_VAL1, + Foo_VAL2, + }; + bool Foo_IsValid(int); })"); - EXPECT_TRUE(shouldCollect("nx::TopLevel")); - EXPECT_TRUE(shouldCollect("nx::Kind::KIND_OK")); - EXPECT_TRUE(shouldCollect("nx::Kind")); - EXPECT_FALSE(shouldCollect("nx::Top_Level")); - EXPECT_FALSE(shouldCollect("nx::Kind::Kind_Not_Ok")); + // Make sure all the mangled names for Outer::Enum is discarded. + EXPECT_FALSE(shouldCollect("nx::Outer_Enum")); + EXPECT_FALSE(shouldCollect("nx::Outer_Enum_KIND1")); + EXPECT_FALSE(shouldCollect("nx::Outer_Enum_Kind_2")); + EXPECT_FALSE(shouldCollect("nx::Outer_Enum_IsValid")); + // But nested aliases are preserved. + EXPECT_TRUE(shouldCollect("nx::Outer::Enum")); + EXPECT_TRUE(shouldCollect("nx::Outer::KIND1")); + EXPECT_TRUE(shouldCollect("nx::Outer::Kind_2")); + EXPECT_TRUE(shouldCollect("nx::Outer::Enum_IsValid")); + + // Check for Outer::Inner. + EXPECT_FALSE(shouldCollect("nx::Outer_Inner")); + EXPECT_TRUE(shouldCollect("nx::Outer")); + EXPECT_TRUE(shouldCollect("nx::Outer::Inner")); + + // Make sure field related information is preserved, unless it's explicitly + // marked with `_internal_`. + EXPECT_TRUE(shouldCollect("nx::Outer::x")); + EXPECT_TRUE(shouldCollect("nx::Outer::set_x")); + EXPECT_FALSE(shouldCollect("nx::Outer::_internal_set_x")); + EXPECT_TRUE(shouldCollect("nx::Outer::Outer_y")); + + // Handling of a top-level enum + EXPECT_TRUE(shouldCollect("nx::Foo::FOO_VAL1")); + EXPECT_TRUE(shouldCollect("nx::FOO_VAL1")); + EXPECT_TRUE(shouldCollect("nx::Foo_IsValid")); + // Our heuristic goes wrong here, if the user has a nested name that starts + // with parent's name. + EXPECT_FALSE(shouldCollect("nx::Foo::Foo_VAL2")); + EXPECT_FALSE(shouldCollect("nx::Foo_VAL2")); } TEST_F(ShouldCollectSymbolTest, DoubleCheckProtoHeaderComment) { diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 7d37a4b03222c..e34e296b5a096 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -103,6 +103,12 @@ Improvements to clang-tidy New checks ^^^^^^^^^^ +- New :doc:`bugprone-tagged-union-member-count + ` check. + + Gives warnings for tagged unions, where the number of tags is + different from the number of data members inside the union. + New check aliases ^^^^^^^^^^^^^^^^^ diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/tagged-union-member-count.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/tagged-union-member-count.rst new file mode 100644 index 0000000000000..2f1036c10345e --- /dev/null +++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/tagged-union-member-count.rst @@ -0,0 +1,280 @@ +.. title:: clang-tidy - bugprone-tagged-union-member-count + +bugprone-tagged-union-member-count +================================== + +Gives warnings for tagged unions, where the number of tags is +different from the number of data members inside the union. + +A struct or a class is considered to be a tagged union if it has +exactly one union data member and exactly one enum data member and +any number of other data members that are neither unions or enums. + +Example: + +.. code-block:: c++ + + enum Tags { + Tag1, + Tag2, + }; + + struct TaggedUnion { // warning: tagged union has more data members (3) than tags (2) + enum Tags Kind; + union { + int I; + float F; + char *Str; + } Data; + }; + +How enum constants are counted +------------------------------ + +The main complicating factor when counting the number of enum constants is that +some of them might be auxiliary values that purposefully don't have a corresponding union +data member and are used for something else. For example the last enum constant +sometimes explicitly "points to" the last declared valid enum constant or +tracks how many enum constants have been declared. + +For an illustration: + +.. code-block:: c++ + + enum TagWithLast { + Tag1 = 0, + Tag2 = 1, + Tag3 = 2, + LastTag = 2 + }; + + enum TagWithCounter { + Tag1, // is 0 + Tag2, // is 1 + Tag3, // is 2 + TagCount, // is 3 + }; + +The check counts the number of distinct values among the enum constants and not the enum +constants themselves. This way the enum constants that are essentially just aliases of other +enum constants are not included in the final count. + +Handling of counting enum constants (ones like :code:`TagCount` in the previous code example) +is done by decreasing the number of enum values by one if the name of the last enum constant +starts with a prefix or ends with a suffix specified in :option:`CountingEnumPrefixes`, +:option:`CountingEnumSuffixes` and it's value is one less than the total number of distinct +values in the enum. + +When the final count is adjusted based on this heuristic then a diagnostic note is emitted +that shows which enum constant matched the criteria. + +The heuristic can be disabled entirely (:option:`EnableCountingEnumHeuristic`) or +configured to follow your naming convention (:option:`CountingEnumPrefixes`, :option:`CountingEnumSuffixes`). +The strings specified in :option:`CountingEnumPrefixes`, :option:`CountingEnumSuffixes` are matched +case insensitively. + +Example counts: + +.. code-block:: c++ + + // Enum count is 3, because the value 2 is counted only once + enum TagWithLast { + Tag1 = 0, + Tag2 = 1, + Tag3 = 2, + LastTag = 2 + }; + + // Enum count is 3, because TagCount is heuristically excluded + enum TagWithCounter { + Tag1, // is 0 + Tag2, // is 1 + Tag3, // is 2 + TagCount, // is 3 + }; + + +Options +------- + +.. option:: EnableCountingEnumHeuristic + +This option enables or disables the counting enum heuristic. +It uses the prefixes and suffixes specified in the options +:option:`CountingEnumPrefixes`, :option:`CountingEnumSuffixes` to find counting enum constants by +using them for prefix and suffix matching. + +This option is enabled by default. + +When :option:`EnableCountingEnumHeuristic` is `false`: + +.. code-block:: c++ + + enum TagWithCounter { + Tag1, + Tag2, + Tag3, + TagCount, + }; + + struct TaggedUnion { + TagWithCounter Kind; + union { + int A; + long B; + char *Str; + float F; + } Data; + }; + +When :option:`EnableCountingEnumHeuristic` is `true`: + +.. code-block:: c++ + + enum TagWithCounter { + Tag1, + Tag2, + Tag3, + TagCount, + }; + + struct TaggedUnion { // warning: tagged union has more data members (4) than tags (3) + TagWithCounter Kind; + union { + int A; + long B; + char *Str; + float F; + } Data; + }; + +.. option:: CountingEnumPrefixes + +See :option:`CountingEnumSuffixes` below. + +.. option:: CountingEnumSuffixes + +CountingEnumPrefixes and CountingEnumSuffixes are lists of semicolon +separated strings that are used to search for possible counting enum constants. +These strings are matched case insensitively as prefixes and suffixes +respectively on the names of the enum constants. +If :option:`EnableCountingEnumHeuristic` is `false` then these options do nothing. + +The default value of :option:`CountingEnumSuffixes` is `count` and of +:option:`CountingEnumPrefixes` is the empty string. + +When :option:`EnableCountingEnumHeuristic` is `true` and :option:`CountingEnumSuffixes` +is `count;size`: + +.. code-block:: c++ + + enum TagWithCounterCount { + Tag1, + Tag2, + Tag3, + TagCount, + }; + + struct TaggedUnionCount { // warning: tagged union has more data members (4) than tags (3) + TagWithCounterCount Kind; + union { + int A; + long B; + char *Str; + float F; + } Data; + }; + + enum TagWithCounterSize { + Tag11, + Tag22, + Tag33, + TagSize, + }; + + struct TaggedUnionSize { // warning: tagged union has more data members (4) than tags (3) + TagWithCounterSize Kind; + union { + int A; + long B; + char *Str; + float F; + } Data; + }; + +When :option:`EnableCountingEnumHeuristic` is `true` and :option:`CountingEnumPrefixes` is `maxsize;last_` + +.. code-block:: c++ + + enum TagWithCounterLast { + Tag1, + Tag2, + Tag3, + last_tag, + }; + + struct TaggedUnionLast { // warning: tagged union has more data members (4) than tags (3) + TagWithCounterLast tag; + union { + int I; + short S; + char *C; + float F; + } Data; + }; + + enum TagWithCounterMaxSize { + Tag1, + Tag2, + Tag3, + MaxSizeTag, + }; + + struct TaggedUnionMaxSize { // warning: tagged union has more data members (4) than tags (3) + TagWithCounterMaxSize tag; + union { + int I; + short S; + char *C; + float F; + } Data; + }; + +.. option:: StrictMode + +When enabled, the check will also give a warning, when the number of tags +is greater than the number of union data members. + +This option is disabled by default. + +When :option:`StrictMode` is `false`: + +.. code-block:: c++ + + struct TaggedUnion { + enum { + Tag1, + Tag2, + Tag3, + } Tags; + union { + int I; + float F; + } Data; + }; + +When :option:`StrictMode` is `true`: + +.. code-block:: c++ + + struct TaggedUnion { // warning: tagged union has fewer data members (2) than tags (3) + enum { + Tag1, + Tag2, + Tag3, + } Tags; + union { + int I; + float F; + } Data; + }; diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst index 1909d7b8d8e24..e3dfabba8fad1 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/list.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst @@ -145,6 +145,7 @@ Clang-Tidy Checks :doc:`bugprone-suspicious-stringview-data-usage `, :doc:`bugprone-swapped-arguments `, "Yes" :doc:`bugprone-switch-missing-default-case `, + :doc:`bugprone-tagged-union-member-count `, :doc:`bugprone-terminating-continue `, "Yes" :doc:`bugprone-throw-keyword-missing `, :doc:`bugprone-too-small-loop-variable `, diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/tagged-union-member-count-counting-enum-heuristic-bad-config.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/tagged-union-member-count-counting-enum-heuristic-bad-config.cpp new file mode 100644 index 0000000000000..73bfb7acbc464 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/tagged-union-member-count-counting-enum-heuristic-bad-config.cpp @@ -0,0 +1,11 @@ +// RUN: %check_clang_tidy %s bugprone-tagged-union-member-count %t \ +// RUN: -config='{CheckOptions: { \ +// RUN: bugprone-tagged-union-member-count.EnableCountingEnumHeuristic: false, \ +// RUN: bugprone-tagged-union-member-count.CountingEnumSuffixes: "count", \ +// RUN: bugprone-tagged-union-member-count.CountingEnumPrefixes: "last", \ +// RUN: }}' + +// Warn when the heuristic is disabled and a suffix or a prefix is set explicitly. + +// CHECK-MESSAGES: warning: bugprone-tagged-union-member-count: Counting enum heuristic is disabled but CountingEnumPrefixes is set +// CHECK-MESSAGES: warning: bugprone-tagged-union-member-count: Counting enum heuristic is disabled but CountingEnumSuffixes is set diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/tagged-union-member-count-counting-enum-heuristic-is-disabled.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/tagged-union-member-count-counting-enum-heuristic-is-disabled.cpp new file mode 100644 index 0000000000000..dca52170a749a --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/tagged-union-member-count-counting-enum-heuristic-is-disabled.cpp @@ -0,0 +1,65 @@ +// RUN: %check_clang_tidy -std=c++98-or-later %s bugprone-tagged-union-member-count %t \ +// RUN: -config='{CheckOptions: { \ +// RUN: bugprone-tagged-union-member-count.StrictMode: true, \ +// RUN: bugprone-tagged-union-member-count.EnableCountingEnumHeuristic: false, \ +// RUN: }}' -- + +// CHECK-MESSAGES: :[[@LINE+1]]:8: warning: tagged union has fewer data members (3) than tags (4) +struct IncorrectBecauseHeuristicIsDisabledPrefixCase { + enum { + tags11, + tags22, + tags33, + lasttag, + } Tags; + union { + char A; + short B; + int C; + } Data; +}; + +struct CorrectBecauseHeuristicIsDisabledPrefixCase { // No warnings expected + enum { + tags1, + tags2, + tags3, + lasttags, + } Tags; + union { + char A; + short B; + int C; + long D; + } Data; +}; + +// CHECK-MESSAGES: :[[@LINE+1]]:8: warning: tagged union has fewer data members (3) than tags (4) +struct IncorrectBecauseHeuristicIsDisabledSuffixCase { + enum { + tags11, + tags22, + tags33, + tags_count, + } Tags; + union { + char A; + short B; + int C; + } Data; +}; + +struct CorrectBecauseHeuristicIsDisabledSuffixCase { // No warnings expected + enum { + tags1, + tags2, + tags3, + tags_count, + } Tags; + union { + char A; + short B; + int C; + long D; + } Data; +}; diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/tagged-union-member-count-counting-enum-heuristic-is-enabled.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/tagged-union-member-count-counting-enum-heuristic-is-enabled.cpp new file mode 100644 index 0000000000000..96aef122e85ef --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/tagged-union-member-count-counting-enum-heuristic-is-enabled.cpp @@ -0,0 +1,156 @@ +// RUN: %check_clang_tidy -std=c++98-or-later %s bugprone-tagged-union-member-count %t \ +// RUN: -config='{CheckOptions: { \ +// RUN: bugprone-tagged-union-member-count.StrictMode: false, \ +// RUN: bugprone-tagged-union-member-count.EnableCountingEnumHeuristic: true, \ +// RUN: bugprone-tagged-union-member-count.CountingEnumSuffixes: "count", \ +// RUN: bugprone-tagged-union-member-count.CountingEnumPrefixes: "last", \ +// RUN: }}' -- + +// CHECK-MESSAGES: :[[@LINE+1]]:8: warning: tagged union has more data members (3) than tags (2) +struct IncorrectBecauseHeuristicIsEnabledPrefixCase { + enum { + tags1, + tags2, + lasttag, + } Tags; + union { + char A; + short B; + int C; + } Data; +}; + +struct CorrectBecauseHeuristicIsEnabledPrefixCase { // No warnings expected + enum { + tags1, + tags2, + tags3, + lasttag, + } Tags; + union { + int A; + int B; + int C; + } Data; +}; + +// CHECK-MESSAGES: :[[@LINE+1]]:8: warning: tagged union has more data members (3) than tags (2) +struct IncorrectBecauseHeuristicIsEnabledSuffixCase { + enum { + tags1, + tags2, + tags_count, + } Tags; + union { + char A; + short B; + int C; + } Data; +}; + +struct CorrectBecauseHeuristicIsEnabledSuffixCase { // No warnings expected + enum { + tags1, + tags2, + tags3, + tags_count, + } Tags; + union { + int A; + int B; + int C; + } Data; +}; + +union Union4 { + short *Shorts; + double *Doubles; + int *Ints; + float *Floats; +}; + +// CHECK-MESSAGES: :[[@LINE+1]]:8: warning: tagged union has more data members (4) than tags (3) +struct CountingEnumCaseInsensitivityTest1 { + enum { + node_type_loop, + node_type_branch, + node_type_function, + node_type_count, + } Kind; + union Union4 Data; +}; + +// CHECK-MESSAGES: :[[@LINE+1]]:8: warning: tagged union has more data members (4) than tags (3) +struct CountingEnumCaseInsensitivityTest2 { + enum { + NODE_TYPE_LOOP, + NODE_TYPE_BRANCH, + NODE_TYPE_FUNCTION, + NODE_TYPE_COUNT, + } Kind; + union Union4 Data; +}; + +// CHECK-MESSAGES: :[[@LINE+1]]:8: warning: tagged union has more data members (4) than tags (3) +struct TagWhereCountingEnumIsAliased { + enum { + tag_alias_counter1 = 1, + tag_alias_counter2 = 2, + tag_alias_counter3 = 3, + tag_alias_other_count = 3, + } Kind; + union { + char C; + short S; + int I; + long L; + } Data; +}; + +// CHECK-MESSAGES: :[[@LINE+1]]:8: warning: tagged union has more data members (4) than tags (2) +struct TagWithCountingEnumButOtherValueIsAliased { + enum { + tag_alias_other1 = 1, + tag_alias_other2 = 1, + tag_alias_other3 = 3, + tag_alias_other_count = 2, + } Kind; + union { + char C; + short S; + int I; + long L; + } Data; +}; + +// CHECK-MESSAGES: :[[@LINE+1]]:8: warning: tagged union has more data members (4) than tags (3) +struct TagWhereCounterIsTheSmallest { + enum { + tag_large1 = 1000, + tag_large2 = 1001, + tag_large3 = 1002, + tag_large_count = 3, + } Kind; + union { + char C; + short S; + int I; + long L; + } Data; +}; + +// No warnings expected, only the last enum constant can be a counting enum constant +struct TagWhereCounterLikeNameIsNotLast { + enum { + kind_count, + kind2, + last_kind1, + kind3, + } Kind; + union { + char C; + short S; + int I; + long L; + } Data; +}; diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/tagged-union-member-count-counting-enum-prefixes-and-suffixes.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/tagged-union-member-count-counting-enum-prefixes-and-suffixes.cpp new file mode 100644 index 0000000000000..c0e33ac6f6f36 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/tagged-union-member-count-counting-enum-prefixes-and-suffixes.cpp @@ -0,0 +1,52 @@ +// RUN: %check_clang_tidy -std=c++98-or-later %s bugprone-tagged-union-member-count %t \ +// RUN: -config='{CheckOptions: { \ +// RUN: bugprone-tagged-union-member-count.StrictMode: false, \ +// RUN: bugprone-tagged-union-member-count.EnableCountingEnumHeuristic: true, \ +// RUN: bugprone-tagged-union-member-count.CountingEnumSuffixes: "count", \ +// RUN: bugprone-tagged-union-member-count.CountingEnumPrefixes: "last", \ +// RUN: }}' -- + +union Union3 { + short *Shorts; + int *Ints; + float *Floats; +}; + +union Union4 { + short *Shorts; + double *Doubles; + int *Ints; + float *Floats; +}; + +// The heuristic only considers the last enum constant +// CHECK-MESSAGES: :[[@LINE+1]]:8: warning: tagged union has more data members (4) than tags (3) +struct TaggedUnionPrefixAndSuffixMatch { + enum { + tags1, + tags2, + tagscount, + lasttags + } Kind; + Union4 Data; +}; + +// CHECK-MESSAGES: :[[@LINE+1]]:8: warning: tagged union has more data members (3) than tags (2) +struct TaggedUnionOnlyPrefixMatch { + enum { + prefixtag1, + prefixtag2, + lastprefixtag + } Kind; + Union3 Data; +}; + +// CHECK-MESSAGES: :[[@LINE+1]]:8: warning: tagged union has more data members (3) than tags (2) +struct TaggedUnionOnlySuffixMatch { + enum { + suffixtag1, + suffixtag2, + suffixtagcount + } Kind; + Union3 Data; +}; diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/tagged-union-member-count-counting-enum-prefixes.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/tagged-union-member-count-counting-enum-prefixes.cpp new file mode 100644 index 0000000000000..c287b1953a333 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/tagged-union-member-count-counting-enum-prefixes.cpp @@ -0,0 +1,35 @@ +// RUN: %check_clang_tidy -std=c++98-or-later %s bugprone-tagged-union-member-count %t \ +// RUN: -config='{CheckOptions: { \ +// RUN: bugprone-tagged-union-member-count.StrictMode: false, \ +// RUN: bugprone-tagged-union-member-count.EnableCountingEnumHeuristic: true, \ +// RUN: bugprone-tagged-union-member-count.CountingEnumPrefixes: "maxsize;last", \ +// RUN: }}' -- + +union Union4 { + short *Shorts; + double *Doubles; + int *Ints; + float *Floats; +}; + +// CHECK-MESSAGES: :[[@LINE+1]]:8: warning: tagged union has more data members (4) than tags (3) +struct TaggedUnionWithMaxsizeAsCounterPrefix { + enum { + twc1, + twc2, + twc3, + maxsizetwc, + } Kind; + Union4 Data; +}; + +// CHECK-MESSAGES: :[[@LINE+1]]:8: warning: tagged union has more data members (4) than tags (3) +struct TaggedUnionWithLastAsCounterPrefix { + enum { + twc11, + twc22, + twc33, + lasttwc, + } Kind; + Union4 Data; +}; diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/tagged-union-member-count-counting-enum-suffixes.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/tagged-union-member-count-counting-enum-suffixes.cpp new file mode 100644 index 0000000000000..f248f2efaa5ad --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/tagged-union-member-count-counting-enum-suffixes.cpp @@ -0,0 +1,35 @@ +// RUN: %check_clang_tidy -std=c++98-or-later %s bugprone-tagged-union-member-count %t \ +// RUN: -config='{CheckOptions: { \ +// RUN: bugprone-tagged-union-member-count.StrictMode: false, \ +// RUN: bugprone-tagged-union-member-count.EnableCountingEnumHeuristic: true, \ +// RUN: bugprone-tagged-union-member-count.CountingEnumSuffixes: "count;size", \ +// RUN: }}' -- + +typedef union Union4 { + short *Shorts; + double *Doubles; + int *Ints; + float *Floats; +} union4; + +// CHECK-MESSAGES: :[[@LINE+1]]:8: warning: tagged union has more data members (4) than tags (3) +struct TaggedUnionWithCounterCountSuffix { + enum { + twc1, + twc2, + twc3, + twc_count, + } Kind; + union Union4 Data; +}; + +// CHECK-MESSAGES: :[[@LINE+1]]:8: warning: tagged union has more data members (4) than tags (3) +struct TaggedUnionWithCounterSizeSuffix { + enum { + twc11, + twc22, + twc33, + twc_size, + } Kind; + union Union4 Data; +}; diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/tagged-union-member-count-strictmode-is-disabled.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/tagged-union-member-count-strictmode-is-disabled.cpp new file mode 100644 index 0000000000000..c39683c3c40f6 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/tagged-union-member-count-strictmode-is-disabled.cpp @@ -0,0 +1,27 @@ +// RUN: %check_clang_tidy -std=c++98-or-later %s bugprone-tagged-union-member-count %t \ +// RUN: -config='{CheckOptions: { \ +// RUN: bugprone-tagged-union-member-count.StrictMode: false, \ +// RUN: }}' -- + +// CHECK-MESSAGES: :[[@LINE+1]]:8: warning: tagged union has more data members (2) than tags (1) +struct Incorrect { + enum { + tags1, + } Tags; + union { + char A; + short B; + } Data; +}; + +struct CorrectBecauseStrictModeIsDisabled { // No warnings expected + enum { + tags1, + tags2, + tags3, + } Tags; + union { + char A; + short B; + } Data; +}; diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/tagged-union-member-count-strictmode-is-enabled.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/tagged-union-member-count-strictmode-is-enabled.cpp new file mode 100644 index 0000000000000..10d376d791968 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/tagged-union-member-count-strictmode-is-enabled.cpp @@ -0,0 +1,30 @@ +// RUN: %check_clang_tidy -std=c++98-or-later %s bugprone-tagged-union-member-count %t \ +// RUN: -config='{CheckOptions: { \ +// RUN: bugprone-tagged-union-member-count.StrictMode: true, \ +// RUN: }}' -- + +// CHECK-MESSAGES: :[[@LINE+1]]:8: warning: tagged union has fewer data members (2) than tags (3) +struct IncorrectBecauseStrictmodeIsEnabled { + enum { + tags1, + tags2, + tags3, + } Tags; + union { + char A; + short B; + } Data; +}; + +struct Correct { // No warnings expected + enum { + tags1, + tags2, + tags3, + } Tags; + union { + char A; + short B; + int C; + } Data; +}; diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/tagged-union-member-count.c b/clang-tools-extra/test/clang-tidy/checkers/bugprone/tagged-union-member-count.c new file mode 100644 index 0000000000000..60c93c553baca --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/tagged-union-member-count.c @@ -0,0 +1,149 @@ +// RUN: %check_clang_tidy %s bugprone-tagged-union-member-count %t + +typedef enum Tags3 { + tags3_1, + tags3_2, + tags3_3, +} Tags3; + +typedef enum Tags4 { + tags4_1, + tags4_2, + tags4_3, + tags4_4, +} Tags4; + +typedef union Union3 { + short *Shorts; + int *Ints; + float *Floats; +} Union3; + +typedef union Union4 { + short *Shorts; + double *Doubles; + int *Ints; + float *Floats; +} Union4; + +// It is not obvious which enum is the tag for the union. +struct maybeTaggedUnion1 { // No warnings expected. + enum Tags3 TagA; + enum Tags4 TagB; + union Union4 Data; +}; + +// It is not obvious which union does the tag belong to. +struct maybeTaggedUnion2 { // No warnings expected. + enum Tags3 Tag; + union Union3 DataB; + union Union3 DataA; +}; + +// It is not obvious which union does the tag belong to. +struct maybeTaggedUnion3 { // No warnings expected. + enum Tags3 Tag; + union { + int I1; + int I2; + int I3; + }; + union { + float F1; + float F2; + float F3; + }; +}; + +// No warnings expected, because LastATag is just an alias +struct TaggedUnionWithAliasedEnumConstant { + enum { + ATag1, + ATag2, + ATag3, + LastATag = ATag3, + } Tag; + union { + float F; + int *Ints; + char Key[8]; + } Data; +}; + +// CHECK-MESSAGES: :[[@LINE+1]]:8: warning: tagged union has more data members (4) than tags (3) +struct TaggedUnionStructWithPredefinedTagAndPredefinedUnion { + enum Tags3 Tag; + union Union4 Data; +}; + +// CHECK-MESSAGES: :[[@LINE+1]]:8: warning: tagged union has more data members (4) than tags (3) +struct TaggedUnionStructWithPredefinedTagAndInlineUnion { + enum Tags3 Tag; + union { + int *Ints; + char Characters[13]; + struct { + double Re; + double Im; + } Complex; + long L; + } Data; +}; + +// CHECK-MESSAGES: :[[@LINE+1]]:8: warning: tagged union has more data members (4) than tags (3) +struct TaggedUnionStructWithInlineTagAndPredefinedUnion { + enum { + TaggedUnion7tag1, + TaggedUnion7tag2, + TaggedUnion7tag3, + } Tag; + union Union4 Data; +}; + +// CHECK-MESSAGES: :[[@LINE+1]]:8: warning: tagged union has more data members (4) than tags (3) +struct TaggedUnionStructWithInlineTagAndInlineUnion { + enum { + TaggedUnion8tag1, + TaggedUnion8tag2, + TaggedUnion8tag3, + } Tag; + union { + int *Ints; + char Characters[13]; + struct { + double Re; + double Im; + } Complex; + long L; + } Data; +}; + +// CHECK-MESSAGES: :[[@LINE+1]]:8: warning: tagged union has more data members (4) than tags (3) +struct TaggedUnionStructNesting { + enum Tags3 Tag; + union { + float F; + int I; + long L; + // CHECK-MESSAGES: :[[@LINE+1]]:12: warning: tagged union has more data members (4) than tags (3) + struct innerdecl { + enum Tags3 Tag; + union Union4 Data; + } Inner; + } Data; +}; + +// CHECK-MESSAGES: :[[@LINE+1]]:8: warning: tagged union has more data members (4) than tags (3) +struct TaggedUnionStructWithTypedefedTagAndTypedefedUnion { + Tags3 Tag; + Union4 Data; +}; + +#define DECLARE_TAGGED_UNION_STRUCT(Tag, Union, Name)\ +struct Name {\ + Tag Kind;\ + Union Data;\ +} + +// CHECK-MESSAGES: :[[@LINE+1]]:44: warning: tagged union has more data members (4) than tags (3) +DECLARE_TAGGED_UNION_STRUCT(Tags3, Union4, TaggedUnionStructFromMacro); diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/tagged-union-member-count.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/tagged-union-member-count.cpp new file mode 100644 index 0000000000000..25827e8c8de0c --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/tagged-union-member-count.cpp @@ -0,0 +1,310 @@ +// RUN: %check_clang_tidy -std=c++98-or-later %s bugprone-tagged-union-member-count %t +// Test check with C++ features + +typedef enum Tags3 { + tags3_1, + tags3_2, + tags3_3, +} Tags3; + +typedef enum Tags4 { + tags4_1, + tags4_2, + tags4_3, + tags4_4, +} Tags4; + +enum class Classtags3 { + classtags3_1, + classtags3_2, + classtags3_3, +}; + +enum class Typedtags3 : unsigned int { + typedtags3_1, + typedtags3_2, + typedtags3_3, +}; + +typedef union Union3 { + short *Shorts; + int *Ints; + float *Floats; +} Union3; + +typedef union Union4 { + short *Shorts; + double *Doubles; + int *Ints; + float *Floats; +} Union4; + +// It is not obvious which enum is the tag for the union. +class MaybeTaggedUnion1 { // No warnings expected. + enum Tags3 TagA; + enum Tags4 TagB; + union Union4 Data; +}; + +// It is not obvious which union does the tag belong to. +class MaybeTaggedUnion2 { // No warnings expected. + enum Tags3 Tag; + union Union3 DataB; + union Union3 DataA; +}; + +// It is not obvious which union does the tag belong to. +class MaybeTaggedUnion3 { // No warnings expected. + enum Tags3 Tag; + union { + int I1; + int I2; + int I3; + }; + union { + float F1; + float F2; + float F3; + }; +}; + +// CHECK-MESSAGES: :[[@LINE+1]]:7: warning: tagged union has more data members (4) than tags (3) +class TaggedUnionClassPredefinedTagAndPredefinedUnion { + enum Tags3 Tag; + union Union4 Data; +}; + +// CHECK-MESSAGES: :[[@LINE+1]]:7: warning: tagged union has more data members (4) than tags (3) +class TaggedUnionClassPredefinedTagAndInlineUnion { + enum Tags3 Tag; + union { + int *Ints; + char Characters[13]; + class { + double Re; + double Im; + } Complex; + long L; + } Data; +}; + +// CHECK-MESSAGES: :[[@LINE+1]]:7: warning: tagged union has more data members (4) than tags (3) +class TaggedUnionClassInlineTagAndPredefinedUnion { + enum { + tag1, + tag2, + tag3, + } Tag; + union Union4 Data; +}; + +// CHECK-MESSAGES: :[[@LINE+1]]:7: warning: tagged union has more data members (4) than tags (3) +class TaggedUnionClassInlineTagAndInlineUnion { + enum { + tag1, + tag2, + tag3, + } Tag; + union { + int *Ints; + char Characters[13]; + class { + double Re; + double Im; + } Complex; + long L; + } Data; +}; + +// CHECK-MESSAGES: :[[@LINE+1]]:7: warning: tagged union has more data members (4) than tags (3) +class TaggedUnionClassWithNestedTaggedUnionClass { + enum Tags3 Tag; + union { + float F; + int I; + long L; + // CHECK-MESSAGES: :[[@LINE+1]]:11: warning: tagged union has more data members (4) than tags (3) + class Innerdecl { + enum Tags3 Tag; + union Union4 Data; + } Inner; + } Data; +}; + +// CHECK-MESSAGES: :[[@LINE+1]]:7: warning: tagged union has more data members (4) than tags (3) +class TaggedUnionClassWithTypedefedTag { + Tags3 Tag; + Union4 Data; +}; + +// CHECK-MESSAGES: :[[@LINE+1]]:8: warning: tagged union has more data members (4) than tags (3) +struct TaggedUnionStructWithEnumClass { + enum Classtags3 Tag; + Union4 Data; +}; + +// CHECK-MESSAGES: :[[@LINE+1]]:7: warning: tagged union has more data members (4) than tags (3) +class TaggedUnionClasswithEnumClass { + enum Classtags3 Tag; + Union4 Data; +}; + +// CHECK-MESSAGES: :[[@LINE+1]]:8: warning: tagged union has more data members (4) than tags (3) +struct TaggedUnionStructWithTypedEnum { + Typedtags3 Tag; + Union4 Data; +}; + +// CHECK-MESSAGES: :[[@LINE+1]]:7: warning: tagged union has more data members (4) than tags (3) +class TaggedUnionClassWithTypedEnum { + Typedtags3 Tag; + Union4 Data; +}; + +// CHECK-MESSAGES: :[[@LINE+1]]:8: warning: tagged union has more data members (4) than tags (3) +struct AnonymousTaggedUnionStruct { + Tags3 Tag; + union { + char A; + short B; + int C; + long D; + }; +}; + +// CHECK-MESSAGES: :[[@LINE+1]]:7: warning: tagged union has more data members (4) than tags (3) +class TaggedUnionClassWithAnonymousUnion { + Tags3 Tag; + union { + char A; + short B; + int C; + long D; + }; +}; + +namespace testnamespace { + +enum Tags3 { + tags3_1, + tags3_2, + tags3_3, +}; + +union Union4 { + short *Shorts; + double *Doubles; + int *Ints; + float *Floats; +}; + +// CHECK-MESSAGES: :[[@LINE+1]]:8: warning: tagged union has more data members (4) than tags (3) +struct TaggedUnionStructInNamespace { + Tags3 Tags; + Union4 Data; +}; + +// CHECK-MESSAGES: :[[@LINE+1]]:7: warning: tagged union has more data members (4) than tags (3) +class TaggedUnionClassInNamespace { + Tags3 Tags; + Union4 Data; +}; + +} // namespace testnamespace + +// CHECK-MESSAGES: :[[@LINE+1]]:8: warning: tagged union has more data members (4) than tags (3) +struct TaggedUnionStructWithNamespacedTagAndUnion { + testnamespace::Tags3 Tags; + testnamespace::Union4 Data; +}; + +// CHECK-MESSAGES: :[[@LINE+1]]:7: warning: tagged union has more data members (4) than tags (3) +class TaggedUnionClassWithNamespacedTagAndUnion { + testnamespace::Tags3 Tags; + testnamespace::Union4 Data; +}; + +// CHECK-MESSAGES: :[[@LINE+2]]:8: warning: tagged union has more data members (4) than tags (3) +template +struct TemplatedStructWithNamespacedTagAndUnion { + Tag Kind; + Union Data; +}; + +TemplatedStructWithNamespacedTagAndUnion TemplatedStruct3; + +// CHECK-MESSAGES: :[[@LINE+2]]:7: warning: tagged union has more data members (4) than tags (3) +template +class TemplatedClassWithNamespacedTagAndUnion { + Tag Kind; + Union Data; +}; + +TemplatedClassWithNamespacedTagAndUnion TemplatedClass3; + +// CHECK-MESSAGES: :[[@LINE+2]]:8: warning: tagged union has more data members (4) than tags (3) +template +struct TemplatedStruct { + Tag Kind; + Union Data; +}; + +TemplatedStruct TemplatedStruct1; // No warning expected +TemplatedStruct TemplatedStruct2; + +// CHECK-MESSAGES: :[[@LINE+2]]:7: warning: tagged union has more data members (4) than tags (3) +template +class TemplatedClass { + Tag Kind; + Union Data; +}; + +TemplatedClass TemplatedClass1; // No warning expected +TemplatedClass TemplatedClass2; + +// CHECK-MESSAGES: :[[@LINE+2]]:8: warning: tagged union has more data members (4) than tags (3) +template +struct TemplatedStructButTaggedUnionPartIsNotTemplated { + Tags3 Kind; + Union4 Data; + T SomethingElse; +}; + +// CHECK-MESSAGES: :[[@LINE+2]]:7: warning: tagged union has more data members (4) than tags (3) +template +class TemplatedClassButTaggedUnionPartIsNotTemplated { + Tags3 Kind; + Union4 Data; + T SomethingElse; +}; + +#define DECLARE_TAGGED_UNION_STRUCT(Tag, Union, Name)\ +struct Name {\ + Tag Kind;\ + Union Data;\ +} + +// CHECK-MESSAGES: :[[@LINE+1]]:44: warning: tagged union has more data members (4) than tags (3) +DECLARE_TAGGED_UNION_STRUCT(Tags3, Union4, TaggedUnionStructFromMacro); + +#define DECLARE_TAGGED_UNION_CLASS(Tag, Union, Name)\ +class Name {\ + Tag Kind;\ + Union Data;\ +} + +// CHECK-MESSAGES: :[[@LINE+1]]:43: warning: tagged union has more data members (4) than tags (3) +DECLARE_TAGGED_UNION_CLASS(Tags3, Union4, TaggedUnionClassFromMacro); + +// Lambdas implicitly compile down to an unnamed CXXRecordDecl and if they have captures, +// then those become unnamed fields. +void DoNotMatchLambdas() { + enum { + A + } e; + union { + long A; + char B; + } u; + auto L = [e, u] () {}; +} diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/tagged-union-member-count.m b/clang-tools-extra/test/clang-tidy/checkers/bugprone/tagged-union-member-count.m new file mode 100644 index 0000000000000..60c93c553baca --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/tagged-union-member-count.m @@ -0,0 +1,149 @@ +// RUN: %check_clang_tidy %s bugprone-tagged-union-member-count %t + +typedef enum Tags3 { + tags3_1, + tags3_2, + tags3_3, +} Tags3; + +typedef enum Tags4 { + tags4_1, + tags4_2, + tags4_3, + tags4_4, +} Tags4; + +typedef union Union3 { + short *Shorts; + int *Ints; + float *Floats; +} Union3; + +typedef union Union4 { + short *Shorts; + double *Doubles; + int *Ints; + float *Floats; +} Union4; + +// It is not obvious which enum is the tag for the union. +struct maybeTaggedUnion1 { // No warnings expected. + enum Tags3 TagA; + enum Tags4 TagB; + union Union4 Data; +}; + +// It is not obvious which union does the tag belong to. +struct maybeTaggedUnion2 { // No warnings expected. + enum Tags3 Tag; + union Union3 DataB; + union Union3 DataA; +}; + +// It is not obvious which union does the tag belong to. +struct maybeTaggedUnion3 { // No warnings expected. + enum Tags3 Tag; + union { + int I1; + int I2; + int I3; + }; + union { + float F1; + float F2; + float F3; + }; +}; + +// No warnings expected, because LastATag is just an alias +struct TaggedUnionWithAliasedEnumConstant { + enum { + ATag1, + ATag2, + ATag3, + LastATag = ATag3, + } Tag; + union { + float F; + int *Ints; + char Key[8]; + } Data; +}; + +// CHECK-MESSAGES: :[[@LINE+1]]:8: warning: tagged union has more data members (4) than tags (3) +struct TaggedUnionStructWithPredefinedTagAndPredefinedUnion { + enum Tags3 Tag; + union Union4 Data; +}; + +// CHECK-MESSAGES: :[[@LINE+1]]:8: warning: tagged union has more data members (4) than tags (3) +struct TaggedUnionStructWithPredefinedTagAndInlineUnion { + enum Tags3 Tag; + union { + int *Ints; + char Characters[13]; + struct { + double Re; + double Im; + } Complex; + long L; + } Data; +}; + +// CHECK-MESSAGES: :[[@LINE+1]]:8: warning: tagged union has more data members (4) than tags (3) +struct TaggedUnionStructWithInlineTagAndPredefinedUnion { + enum { + TaggedUnion7tag1, + TaggedUnion7tag2, + TaggedUnion7tag3, + } Tag; + union Union4 Data; +}; + +// CHECK-MESSAGES: :[[@LINE+1]]:8: warning: tagged union has more data members (4) than tags (3) +struct TaggedUnionStructWithInlineTagAndInlineUnion { + enum { + TaggedUnion8tag1, + TaggedUnion8tag2, + TaggedUnion8tag3, + } Tag; + union { + int *Ints; + char Characters[13]; + struct { + double Re; + double Im; + } Complex; + long L; + } Data; +}; + +// CHECK-MESSAGES: :[[@LINE+1]]:8: warning: tagged union has more data members (4) than tags (3) +struct TaggedUnionStructNesting { + enum Tags3 Tag; + union { + float F; + int I; + long L; + // CHECK-MESSAGES: :[[@LINE+1]]:12: warning: tagged union has more data members (4) than tags (3) + struct innerdecl { + enum Tags3 Tag; + union Union4 Data; + } Inner; + } Data; +}; + +// CHECK-MESSAGES: :[[@LINE+1]]:8: warning: tagged union has more data members (4) than tags (3) +struct TaggedUnionStructWithTypedefedTagAndTypedefedUnion { + Tags3 Tag; + Union4 Data; +}; + +#define DECLARE_TAGGED_UNION_STRUCT(Tag, Union, Name)\ +struct Name {\ + Tag Kind;\ + Union Data;\ +} + +// CHECK-MESSAGES: :[[@LINE+1]]:44: warning: tagged union has more data members (4) than tags (3) +DECLARE_TAGGED_UNION_STRUCT(Tags3, Union4, TaggedUnionStructFromMacro); diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/tagged-union-member-count.mm b/clang-tools-extra/test/clang-tidy/checkers/bugprone/tagged-union-member-count.mm new file mode 100644 index 0000000000000..8b308555281c5 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/tagged-union-member-count.mm @@ -0,0 +1,309 @@ +// RUN: %check_clang_tidy %s bugprone-tagged-union-member-count %t + +typedef enum Tags3 { + tags3_1, + tags3_2, + tags3_3, +} Tags3; + +typedef enum Tags4 { + tags4_1, + tags4_2, + tags4_3, + tags4_4, +} Tags4; + +enum class Classtags3 { + classtags3_1, + classtags3_2, + classtags3_3, +}; + +enum class Typedtags3 : unsigned int { + typedtags3_1, + typedtags3_2, + typedtags3_3, +}; + +typedef union Union3 { + short *Shorts; + int *Ints; + float *Floats; +} Union3; + +typedef union Union4 { + short *Shorts; + double *Doubles; + int *Ints; + float *Floats; +} Union4; + +// It is not obvious which enum is the tag for the union. +class MaybeTaggedUnion1 { // No warnings expected. + enum Tags3 TagA; + enum Tags4 TagB; + union Union4 Data; +}; + +// It is not obvious which union does the tag belong to. +class MaybeTaggedUnion2 { // No warnings expected. + enum Tags3 Tag; + union Union3 DataB; + union Union3 DataA; +}; + +// It is not obvious which union does the tag belong to. +class MaybeTaggedUnion3 { // No warnings expected. + enum Tags3 Tag; + union { + int I1; + int I2; + int I3; + }; + union { + float F1; + float F2; + float F3; + }; +}; + +// CHECK-MESSAGES: :[[@LINE+1]]:7: warning: tagged union has more data members (4) than tags (3) +class TaggedUnionClassPredefinedTagAndPredefinedUnion { + enum Tags3 Tag; + union Union4 Data; +}; + +// CHECK-MESSAGES: :[[@LINE+1]]:7: warning: tagged union has more data members (4) than tags (3) +class TaggedUnionClassPredefinedTagAndInlineUnion { + enum Tags3 Tag; + union { + int *Ints; + char Characters[13]; + class { + double Re; + double Im; + } Complex; + long L; + } Data; +}; + +// CHECK-MESSAGES: :[[@LINE+1]]:7: warning: tagged union has more data members (4) than tags (3) +class TaggedUnionClassInlineTagAndPredefinedUnion { + enum { + tag1, + tag2, + tag3, + } Tag; + union Union4 Data; +}; + +// CHECK-MESSAGES: :[[@LINE+1]]:7: warning: tagged union has more data members (4) than tags (3) +class TaggedUnionClassInlineTagAndInlineUnion { + enum { + tag1, + tag2, + tag3, + } Tag; + union { + int *Ints; + char Characters[13]; + class { + double Re; + double Im; + } Complex; + long L; + } Data; +}; + +// CHECK-MESSAGES: :[[@LINE+1]]:7: warning: tagged union has more data members (4) than tags (3) +class TaggedUnionClassWithNestedTaggedUnionClass { + enum Tags3 Tag; + union { + float F; + int I; + long L; + // CHECK-MESSAGES: :[[@LINE+1]]:11: warning: tagged union has more data members (4) than tags (3) + class Innerdecl { + enum Tags3 Tag; + union Union4 Data; + } Inner; + } Data; +}; + +// CHECK-MESSAGES: :[[@LINE+1]]:7: warning: tagged union has more data members (4) than tags (3) +class TaggedUnionClassWithTypedefedTag { + Tags3 Tag; + Union4 Data; +}; + +// CHECK-MESSAGES: :[[@LINE+1]]:8: warning: tagged union has more data members (4) than tags (3) +struct TaggedUnionStructWithEnumClass { + enum Classtags3 Tag; + Union4 Data; +}; + +// CHECK-MESSAGES: :[[@LINE+1]]:7: warning: tagged union has more data members (4) than tags (3) +class TaggedUnionClasswithEnumClass { + enum Classtags3 Tag; + Union4 Data; +}; + +// CHECK-MESSAGES: :[[@LINE+1]]:8: warning: tagged union has more data members (4) than tags (3) +struct TaggedUnionStructWithTypedEnum { + Typedtags3 Tag; + Union4 Data; +}; + +// CHECK-MESSAGES: :[[@LINE+1]]:7: warning: tagged union has more data members (4) than tags (3) +class TaggedUnionClassWithTypedEnum { + Typedtags3 Tag; + Union4 Data; +}; + +// CHECK-MESSAGES: :[[@LINE+1]]:8: warning: tagged union has more data members (4) than tags (3) +struct AnonymousTaggedUnionStruct { + Tags3 Tag; + union { + char A; + short B; + int C; + long D; + }; +}; + +// CHECK-MESSAGES: :[[@LINE+1]]:7: warning: tagged union has more data members (4) than tags (3) +class TaggedUnionClassWithAnonymousUnion { + Tags3 Tag; + union { + char A; + short B; + int C; + long D; + }; +}; + +namespace testnamespace { + +enum Tags3 { + tags3_1, + tags3_2, + tags3_3, +}; + +union Union4 { + short *Shorts; + double *Doubles; + int *Ints; + float *Floats; +}; + +// CHECK-MESSAGES: :[[@LINE+1]]:8: warning: tagged union has more data members (4) than tags (3) +struct TaggedUnionStructInNamespace { + Tags3 Tags; + Union4 Data; +}; + +// CHECK-MESSAGES: :[[@LINE+1]]:7: warning: tagged union has more data members (4) than tags (3) +class TaggedUnionClassInNamespace { + Tags3 Tags; + Union4 Data; +}; + +} // namespace testnamespace + +// CHECK-MESSAGES: :[[@LINE+1]]:8: warning: tagged union has more data members (4) than tags (3) +struct TaggedUnionStructWithNamespacedTagAndUnion { + testnamespace::Tags3 Tags; + testnamespace::Union4 Data; +}; + +// CHECK-MESSAGES: :[[@LINE+1]]:7: warning: tagged union has more data members (4) than tags (3) +class TaggedUnionClassWithNamespacedTagAndUnion { + testnamespace::Tags3 Tags; + testnamespace::Union4 Data; +}; + +// CHECK-MESSAGES: :[[@LINE+2]]:8: warning: tagged union has more data members (4) than tags (3) +template +struct TemplatedStructWithNamespacedTagAndUnion { + Tag Kind; + Union Data; +}; + +TemplatedStructWithNamespacedTagAndUnion TemplatedStruct3; + +// CHECK-MESSAGES: :[[@LINE+2]]:7: warning: tagged union has more data members (4) than tags (3) +template +class TemplatedClassWithNamespacedTagAndUnion { + Tag Kind; + Union Data; +}; + +TemplatedClassWithNamespacedTagAndUnion TemplatedClass3; + +// CHECK-MESSAGES: :[[@LINE+2]]:8: warning: tagged union has more data members (4) than tags (3) +template +struct TemplatedStruct { + Tag Kind; + Union Data; +}; + +TemplatedStruct TemplatedStruct1; // No warning expected +TemplatedStruct TemplatedStruct2; + +// CHECK-MESSAGES: :[[@LINE+2]]:7: warning: tagged union has more data members (4) than tags (3) +template +class TemplatedClass { + Tag Kind; + Union Data; +}; + +TemplatedClass TemplatedClass1; // No warning expected +TemplatedClass TemplatedClass2; + +// CHECK-MESSAGES: :[[@LINE+2]]:8: warning: tagged union has more data members (4) than tags (3) +template +struct TemplatedStructButTaggedUnionPartIsNotTemplated { + Tags3 Kind; + Union4 Data; + T SomethingElse; +}; + +// CHECK-MESSAGES: :[[@LINE+2]]:7: warning: tagged union has more data members (4) than tags (3) +template +class TemplatedClassButTaggedUnionPartIsNotTemplated { + Tags3 Kind; + Union4 Data; + T SomethingElse; +}; + +#define DECLARE_TAGGED_UNION_STRUCT(Tag, Union, Name)\ +struct Name {\ + Tag Kind;\ + Union Data;\ +} + +// CHECK-MESSAGES: :[[@LINE+1]]:44: warning: tagged union has more data members (4) than tags (3) +DECLARE_TAGGED_UNION_STRUCT(Tags3, Union4, TaggedUnionStructFromMacro); + +#define DECLARE_TAGGED_UNION_CLASS(Tag, Union, Name)\ +class Name {\ + Tag Kind;\ + Union Data;\ +} + +// CHECK-MESSAGES: :[[@LINE+1]]:43: warning: tagged union has more data members (4) than tags (3) +DECLARE_TAGGED_UNION_CLASS(Tags3, Union4, TaggedUnionClassFromMacro); + +// Lambdas implicitly compile down to an unnamed CXXRecordDecl and if they have captures, +// then those become unnamed fields. +void DoNotMatchLambdas() { + enum { + A + } e; + union { + long A; + char B; + } u; + auto L = [e, u] () {}; +} diff --git a/clang/docs/RealtimeSanitizer.rst b/clang/docs/RealtimeSanitizer.rst index 5e281a2a35790..3f96267603aef 100644 --- a/clang/docs/RealtimeSanitizer.rst +++ b/clang/docs/RealtimeSanitizer.rst @@ -84,6 +84,76 @@ non-zero exit code. #14 0x0001958960dc () #15 0x2f557ffffffffffc () +Run-time flags +-------------- + +RealtimeSanitizer supports a number of run-time flags, which can be specified in the ``RTSAN_OPTIONS`` environment variable: + +.. code-block:: console + + % RTSAN_OPTIONS=option_1=true:path_option_2="/some/file.txt" ./a.out + ... + +Or at compile-time by providing the symbol ``__rtsan_default_options``: + +.. code-block:: c + + __attribute__((__visibility__("default"))) + extern "C" const char *__rtsan_default_options() { + return "symbolize=false:abort_on_error=0:log_to_syslog=0"; + } + +You can see all sanitizer options (some of which are unsupported) by using the ``help`` flag: + +.. code-block:: console + + % RTSAN_OPTIONS=help=true ./a.out + +A **partial** list of flags RealtimeSanitizer respects: + +.. list-table:: Run-time Flags + :widths: 20 10 10 70 + :header-rows: 1 + + * - Flag name + - Default value + - Type + - Short description + * - ``halt_on_error`` + - ``true`` + - boolean + - Exit after first reported error. If false (continue after a detected error), deduplicates error stacks so errors appear only once. + * - ``print_stats_on_exit`` + - ``false`` + - boolean + - Print stats on exit. Includes total and unique errors. + * - ``color`` + - ``"auto"`` + - string + - Colorize reports: (always|never|auto). + * - ``fast_unwind_on_fatal`` + - ``false`` + - boolean + - If available, use the fast frame-pointer-based unwinder on detected errors. If true, ensure the code under test has been compiled with frame pointers with ``-fno-omit-frame-pointers`` or similar. + * - ``abort_on_error`` + - OS dependent + - boolean + - If true, the tool calls abort() instead of _exit() after printing the error report. On some OSes (OSX, for exmple) this is beneficial because a better stack trace is emitted on crash. + * - ``symbolize`` + - ``true`` + - boolean + - If set, use the symbolizer to turn virtual addresses to file/line locations. If false, can greatly speed up the error reporting. + + +Some issues with flags can be debugged using the ``verbosity=$NUM`` flag: + +.. code-block:: console + + % RTSAN_OPTIONS=verbosity=1:misspelled_flag=true ./a.out + WARNING: found 1 unrecognized flag(s): + misspelled_flag + ... + Disabling --------- diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 35c31452cef41..7e64134f7eb19 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -205,6 +205,9 @@ Resolutions to C++ Defect Reports - Reject explicit object parameters with type ``void`` (``this void``). (`CWG2915: Explicit object parameters of type void `_). +- Clang now allows trailing requires clause on explicit deduction guides. + (`CWG2707: Deduction guides cannot have a trailing requires-clause `_). + C Language Changes ------------------ @@ -359,6 +362,8 @@ Improvements to Clang's diagnostics - Clang now diagnoses cases where a dangling ``GSLOwner`` object is constructed, e.g. ``std::vector v = {std::string()};`` (#GH100526). +- Clang now diagnoses when a ``requires`` expression has a local parameter of void type, aligning with the function parameter (#GH109831). + Improvements to Clang's time-trace ---------------------------------- @@ -448,6 +453,10 @@ Bug Fixes to C++ Support diagnosing a failed cast caused indirectly by a failed implicit conversion to the type of the constructor parameter. - Fixed an assertion failure by adjusting integral to boolean vector conversions (#GH108326) - Mangle friend function templates with a constraint that depends on a template parameter from an enclosing template as members of the enclosing class. (#GH110247) +- Fixed an issue in constraint evaluation, where type constraints on the lambda expression + containing outer unexpanded parameters were not correctly expanded. (#GH101754) +- Fixed a bug in constraint expression comparison where the ``sizeof...`` expression was not handled properly + in certain friend declarations. (#GH93099) Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -511,6 +520,14 @@ X86 Support * Supported MINMAX intrinsics of ``*_(mask(z)))_minmax(ne)_p[s|d|h|bh]`` and ``*_(mask(z)))_minmax_s[s|d|h]``. +- All intrinsics in lzcntintrin.h can now be used in constant expressions. + +- All intrinsics in bmiintrin.h can now be used in constant expressions. + +- All bzhi/pdep/pext intrinsics in bmi2intrin.h can now be used in constant expressions. + +- All intrinsics in tbmintrin.h can now be used in constant expressions. + Arm and AArch64 Support ^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/docs/analyzer/checkers.rst b/clang/docs/analyzer/checkers.rst index a22bda189dd29..81264428c72ed 100644 --- a/clang/docs/analyzer/checkers.rst +++ b/clang/docs/analyzer/checkers.rst @@ -1288,6 +1288,34 @@ by explicitly marking the ``size`` parameter as sanitized. See the delete[] ptr; } +.. _optin-taint-TaintedDiv: + +optin.taint.TaintedDiv (C, C++, ObjC) +""""""""""""""""""""""""""""""""""""" +This checker warns when the denominator in a division +operation is a tainted (potentially attacker controlled) value. +If the attacker can set the denominator to 0, a runtime error can +be triggered. The checker warns when the denominator is a tainted +value and the analyzer cannot prove that it is not 0. This warning +is more pessimistic than the :ref:`core-DivideZero` checker +which warns only when it can prove that the denominator is 0. + +.. code-block:: c + + int vulnerable(int n) { + size_t size = 0; + scanf("%zu", &size); + return n / size; // warn: Division by a tainted value, possibly zero + } + + int not_vulnerable(int n) { + size_t size = 0; + scanf("%zu", &size); + if (!size) + return 0; + return n / size; // no warning + } + .. _security-checkers: security diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index 3db9871a4b07b..a4d36f2eacd5d 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -1205,7 +1205,8 @@ class ASTContext : public RefCountedBase { #include "clang/Basic/RISCVVTypes.def" #define WASM_TYPE(Name, Id, SingletonId) CanQualType SingletonId; #include "clang/Basic/WebAssemblyReferenceTypes.def" -#define AMDGPU_TYPE(Name, Id, SingletonId) CanQualType SingletonId; +#define AMDGPU_TYPE(Name, Id, SingletonId, Width, Align) \ + CanQualType SingletonId; #include "clang/Basic/AMDGPUTypes.def" #define HLSL_INTANGIBLE_TYPE(Name, Id, SingletonId) CanQualType SingletonId; #include "clang/Basic/HLSLIntangibleTypes.def" diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h index 252e6e9256414..2693cc0e95b4b 100644 --- a/clang/include/clang/AST/DeclCXX.h +++ b/clang/include/clang/AST/DeclCXX.h @@ -1965,9 +1965,11 @@ class CXXDeductionGuideDecl : public FunctionDecl { ExplicitSpecifier ES, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, SourceLocation EndLocation, - CXXConstructorDecl *Ctor, DeductionCandidate Kind) + CXXConstructorDecl *Ctor, DeductionCandidate Kind, + Expr *TrailingRequiresClause) : FunctionDecl(CXXDeductionGuide, C, DC, StartLoc, NameInfo, T, TInfo, - SC_None, false, false, ConstexprSpecKind::Unspecified), + SC_None, false, false, ConstexprSpecKind::Unspecified, + TrailingRequiresClause), Ctor(Ctor), ExplicitSpec(ES) { if (EndLocation.isValid()) setRangeEnd(EndLocation); @@ -1987,7 +1989,8 @@ class CXXDeductionGuideDecl : public FunctionDecl { ExplicitSpecifier ES, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, SourceLocation EndLocation, CXXConstructorDecl *Ctor = nullptr, - DeductionCandidate Kind = DeductionCandidate::Normal); + DeductionCandidate Kind = DeductionCandidate::Normal, + Expr *TrailingRequiresClause = nullptr); static CXXDeductionGuideDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); diff --git a/clang/include/clang/AST/OpenACCClause.h b/clang/include/clang/AST/OpenACCClause.h index ea1ffbc7fd08b..90f5b7fc9ab6f 100644 --- a/clang/include/clang/AST/OpenACCClause.h +++ b/clang/include/clang/AST/OpenACCClause.h @@ -547,6 +547,32 @@ class OpenACCAsyncClause : public OpenACCClauseWithSingleIntExpr { SourceLocation EndLoc); }; +/// Represents a 'collapse' clause on a 'loop' construct. This clause takes an +/// integer constant expression 'N' that represents how deep to collapse the +/// construct. It also takes an optional 'force' tag that permits intervening +/// code in the loops. +class OpenACCCollapseClause : public OpenACCClauseWithSingleIntExpr { + bool HasForce = false; + + OpenACCCollapseClause(SourceLocation BeginLoc, SourceLocation LParenLoc, + bool HasForce, Expr *LoopCount, SourceLocation EndLoc); + +public: + const Expr *getLoopCount() const { return getIntExpr(); } + Expr *getLoopCount() { return getIntExpr(); } + + bool hasForce() const { return HasForce; } + + static bool classof(const OpenACCClause *C) { + return C->getClauseKind() == OpenACCClauseKind::Collapse; + } + + static OpenACCCollapseClause *Create(const ASTContext &C, + SourceLocation BeginLoc, + SourceLocation LParenLoc, bool HasForce, + Expr *LoopCount, SourceLocation EndLoc); +}; + /// Represents a clause with one or more 'var' objects, represented as an expr, /// as its arguments. Var-list is expected to be stored in trailing storage. /// For now, we're just storing the original expression in its entirety, unlike diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index 67e75652a1664..7126940058bae 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -3050,7 +3050,7 @@ class BuiltinType : public Type { #define WASM_TYPE(Name, Id, SingletonId) Id, #include "clang/Basic/WebAssemblyReferenceTypes.def" // AMDGPU types -#define AMDGPU_TYPE(Name, Id, SingletonId) Id, +#define AMDGPU_TYPE(Name, Id, SingletonId, Width, Align) Id, #include "clang/Basic/AMDGPUTypes.def" // HLSL intangible Types #define HLSL_INTANGIBLE_TYPE(Name, Id, SingletonId) Id, diff --git a/clang/include/clang/AST/TypeProperties.td b/clang/include/clang/AST/TypeProperties.td index bb7bfa8cd0b76..d05072607e949 100644 --- a/clang/include/clang/AST/TypeProperties.td +++ b/clang/include/clang/AST/TypeProperties.td @@ -893,7 +893,7 @@ let Class = BuiltinType in { case BuiltinType::ID: return ctx.SINGLETON_ID; #include "clang/Basic/WebAssemblyReferenceTypes.def" -#define AMDGPU_TYPE(NAME, ID, SINGLETON_ID) \ +#define AMDGPU_TYPE(NAME, ID, SINGLETON_ID, WIDTH, ALIGN) \ case BuiltinType::ID: return ctx.SINGLETON_ID; #include "clang/Basic/AMDGPUTypes.def" diff --git a/clang/include/clang/Analysis/Analyses/ThreadSafety.h b/clang/include/clang/Analysis/Analyses/ThreadSafety.h index 0866b09bab299..169eef811f579 100644 --- a/clang/include/clang/Analysis/Analyses/ThreadSafety.h +++ b/clang/include/clang/Analysis/Analyses/ThreadSafety.h @@ -26,6 +26,7 @@ namespace clang { class AnalysisDeclContext; class FunctionDecl; class NamedDecl; +class Attr; namespace threadSafety { @@ -230,6 +231,9 @@ class ThreadSafetyHandler { /// Warn that there is a cycle in acquired_before/after dependencies. virtual void handleBeforeAfterCycle(Name L1Name, SourceLocation Loc) {} + virtual void handleAttributeMismatch(const FunctionDecl *FD1, + const FunctionDecl *FD2) {} + /// Called by the analysis when starting analysis of a function. /// Used to issue suggestions for changes to annotations. virtual void enterFunction(const FunctionDecl *FD) {} diff --git a/clang/include/clang/Basic/AMDGPUTypes.def b/clang/include/clang/Basic/AMDGPUTypes.def index 7454d61f5dd51..e47e544fdc82c 100644 --- a/clang/include/clang/Basic/AMDGPUTypes.def +++ b/clang/include/clang/Basic/AMDGPUTypes.def @@ -11,11 +11,11 @@ //===----------------------------------------------------------------------===// #ifndef AMDGPU_OPAQUE_PTR_TYPE -#define AMDGPU_OPAQUE_PTR_TYPE(Name, AS, Width, Align, Id, SingletonId) \ - AMDGPU_TYPE(Name, Id, SingletonId) +#define AMDGPU_OPAQUE_PTR_TYPE(Name, Id, SingletonId, Width, Align, AS) \ + AMDGPU_TYPE(Name, Id, SingletonId, Width, Align) #endif -AMDGPU_OPAQUE_PTR_TYPE("__amdgpu_buffer_rsrc_t", 8, 128, 128, AMDGPUBufferRsrc, AMDGPUBufferRsrcTy) +AMDGPU_OPAQUE_PTR_TYPE("__amdgpu_buffer_rsrc_t", AMDGPUBufferRsrc, AMDGPUBufferRsrcTy, 128, 128, 8) #undef AMDGPU_TYPE #undef AMDGPU_OPAQUE_PTR_TYPE diff --git a/clang/include/clang/Basic/BuiltinsRISCV.td b/clang/include/clang/Basic/BuiltinsRISCV.td index 4cc89a8a9d8af..3263603a8a1cf 100644 --- a/clang/include/clang/Basic/BuiltinsRISCV.td +++ b/clang/include/clang/Basic/BuiltinsRISCV.td @@ -146,3 +146,8 @@ let Features = "zihintntl", Attributes = [CustomTypeChecking] in { def ntl_load : RISCVBuiltin<"void(...)">; def ntl_store : RISCVBuiltin<"void(...)">; } // Features = "zihintntl", Attributes = [CustomTypeChecking] + +//===----------------------------------------------------------------------===// +// XCV extensions. +//===----------------------------------------------------------------------===// +include "clang/Basic/BuiltinsRISCVXCV.td" diff --git a/clang/include/clang/Basic/BuiltinsRISCVXCV.td b/clang/include/clang/Basic/BuiltinsRISCVXCV.td new file mode 100644 index 0000000000000..06ce07ade5c12 --- /dev/null +++ b/clang/include/clang/Basic/BuiltinsRISCVXCV.td @@ -0,0 +1,41 @@ +//==- BuiltinsRISCVXCV.td - RISC-V CORE-V Builtin database ----*- C++ -*-==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines the CORE-V-specific builtin function database. Users of +// this file must define the BUILTIN macro to make use of this information. +// +//===----------------------------------------------------------------------===// + +class RISCXCVBuiltin : TargetBuiltin { + let Spellings = ["__builtin_riscv_cv_" # NAME]; + let Prototype = prototype; + let Features = features; +} + +let Attributes = [NoThrow, Const] in { +//===----------------------------------------------------------------------===// +// XCValu extension. +//===----------------------------------------------------------------------===// +def alu_slet : RISCXCVBuiltin<"int(int, int)", "xcvalu">; +def alu_sletu : RISCXCVBuiltin<"int(unsigned int, unsigned int)", "xcvalu">; +def alu_exths : RISCXCVBuiltin<"int(int)", "xcvalu">; +def alu_exthz : RISCXCVBuiltin<"unsigned int(unsigned int)", "xcvalu">; +def alu_extbs : RISCXCVBuiltin<"int(int)", "xcvalu">; +def alu_extbz : RISCXCVBuiltin<"unsigned int(unsigned int)", "xcvalu">; + +def alu_clip : RISCXCVBuiltin<"int(int, int)", "xcvalu">; +def alu_clipu : RISCXCVBuiltin<"unsigned int(unsigned int, unsigned int)", "xcvalu">; +def alu_addN : RISCXCVBuiltin<"int(int, int, unsigned int)", "xcvalu">; +def alu_adduN : RISCXCVBuiltin<"unsigned int(unsigned int, unsigned int, unsigned int)", "xcvalu">; +def alu_addRN : RISCXCVBuiltin<"int(int, int, unsigned int)", "xcvalu">; +def alu_adduRN : RISCXCVBuiltin<"unsigned int(unsigned int, unsigned int, unsigned int)", "xcvalu">; +def alu_subN : RISCXCVBuiltin<"int(int, int, unsigned int)", "xcvalu">; +def alu_subuN : RISCXCVBuiltin<"unsigned int(unsigned int, unsigned int, unsigned int)", "xcvalu">; +def alu_subRN : RISCXCVBuiltin<"int(int, int, unsigned int)", "xcvalu">; +def alu_subuRN : RISCXCVBuiltin<"unsigned int(unsigned int, unsigned int, unsigned int)", "xcvalu">; +} // Attributes = [NoThrow, Const] diff --git a/clang/include/clang/Basic/BuiltinsX86.def b/clang/include/clang/Basic/BuiltinsX86.def index e4eb9bfbdd173..2a987abcf9a35 100644 --- a/clang/include/clang/Basic/BuiltinsX86.def +++ b/clang/include/clang/Basic/BuiltinsX86.def @@ -551,18 +551,18 @@ TARGET_BUILTIN(__builtin_ia32_rdseed16_step, "UiUs*", "n", "rdseed") TARGET_BUILTIN(__builtin_ia32_rdseed32_step, "UiUi*", "n", "rdseed") // LZCNT -TARGET_BUILTIN(__builtin_ia32_lzcnt_u16, "UsUs", "nc", "lzcnt") -TARGET_BUILTIN(__builtin_ia32_lzcnt_u32, "UiUi", "nc", "lzcnt") +TARGET_BUILTIN(__builtin_ia32_lzcnt_u16, "UsUs", "ncE", "lzcnt") +TARGET_BUILTIN(__builtin_ia32_lzcnt_u32, "UiUi", "ncE", "lzcnt") // BMI TARGET_BUILTIN(__builtin_ia32_bextr_u32, "UiUiUi", "ncE", "bmi") -TARGET_BUILTIN(__builtin_ia32_tzcnt_u16, "UsUs", "nc", "") -TARGET_BUILTIN(__builtin_ia32_tzcnt_u32, "UiUi", "nc", "") +TARGET_BUILTIN(__builtin_ia32_tzcnt_u16, "UsUs", "ncE", "") +TARGET_BUILTIN(__builtin_ia32_tzcnt_u32, "UiUi", "ncE", "") // BMI2 -TARGET_BUILTIN(__builtin_ia32_bzhi_si, "UiUiUi", "nc", "bmi2") -TARGET_BUILTIN(__builtin_ia32_pdep_si, "UiUiUi", "nc", "bmi2") -TARGET_BUILTIN(__builtin_ia32_pext_si, "UiUiUi", "nc", "bmi2") +TARGET_BUILTIN(__builtin_ia32_bzhi_si, "UiUiUi", "ncE", "bmi2") +TARGET_BUILTIN(__builtin_ia32_pdep_si, "UiUiUi", "ncE", "bmi2") +TARGET_BUILTIN(__builtin_ia32_pext_si, "UiUiUi", "ncE", "bmi2") // TBM TARGET_BUILTIN(__builtin_ia32_bextri_u32, "UiUiIUi", "ncE", "tbm") diff --git a/clang/include/clang/Basic/BuiltinsX86_64.def b/clang/include/clang/Basic/BuiltinsX86_64.def index 81fd46ee6d166..d5fdb272d92d1 100644 --- a/clang/include/clang/Basic/BuiltinsX86_64.def +++ b/clang/include/clang/Basic/BuiltinsX86_64.def @@ -70,12 +70,12 @@ TARGET_BUILTIN(__builtin_ia32_addcarryx_u64, "UcUcUOiUOiUOi*", "n", "") TARGET_BUILTIN(__builtin_ia32_subborrow_u64, "UcUcUOiUOiUOi*", "n", "") TARGET_BUILTIN(__builtin_ia32_rdrand64_step, "UiUOi*", "n", "rdrnd") TARGET_BUILTIN(__builtin_ia32_rdseed64_step, "UiUOi*", "n", "rdseed") -TARGET_BUILTIN(__builtin_ia32_lzcnt_u64, "UOiUOi", "nc", "lzcnt") +TARGET_BUILTIN(__builtin_ia32_lzcnt_u64, "UOiUOi", "ncE", "lzcnt") TARGET_BUILTIN(__builtin_ia32_bextr_u64, "UOiUOiUOi", "ncE", "bmi") -TARGET_BUILTIN(__builtin_ia32_tzcnt_u64, "UOiUOi", "nc", "") -TARGET_BUILTIN(__builtin_ia32_bzhi_di, "UOiUOiUOi", "nc", "bmi2") -TARGET_BUILTIN(__builtin_ia32_pdep_di, "UOiUOiUOi", "nc", "bmi2") -TARGET_BUILTIN(__builtin_ia32_pext_di, "UOiUOiUOi", "nc", "bmi2") +TARGET_BUILTIN(__builtin_ia32_tzcnt_u64, "UOiUOi", "ncE", "") +TARGET_BUILTIN(__builtin_ia32_bzhi_di, "UOiUOiUOi", "ncE", "bmi2") +TARGET_BUILTIN(__builtin_ia32_pdep_di, "UOiUOiUOi", "ncE", "bmi2") +TARGET_BUILTIN(__builtin_ia32_pext_di, "UOiUOiUOi", "ncE", "bmi2") TARGET_BUILTIN(__builtin_ia32_bextri_u64, "UOiUOiIUOi", "ncE", "tbm") TARGET_BUILTIN(__builtin_ia32_lwpins64, "UcUOiUiIUi", "n", "lwp") TARGET_BUILTIN(__builtin_ia32_lwpval64, "vUOiUiIUi", "n", "lwp") diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 9e8f152852fd1..f218a82122c88 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -3050,8 +3050,6 @@ def note_is_deducible_constraint_evaluated_to_false : Note< "cannot deduce template arguments for %0 from %1">; def err_constrained_virtual_method : Error< "virtual function cannot have a requires clause">; -def err_trailing_requires_clause_on_deduction_guide : Error< - "deduction guide cannot have a requires clause">; def err_constrained_non_templated_function : Error<"non-templated function cannot have a requires clause">; def err_non_temp_spec_requires_clause : Error< @@ -4033,7 +4031,9 @@ def warn_acquired_before : Warning< def warn_acquired_before_after_cycle : Warning< "cycle in acquired_before/after dependencies, starting with '%0'">, InGroup, DefaultIgnore; - +def warn_attribute_mismatch : Warning< + "attribute mismatch between function definition and declaration of %0">, + InGroup, DefaultIgnore; // Thread safety warnings negative capabilities def warn_acquire_requires_negative_cap : Warning< @@ -12608,6 +12608,9 @@ def note_acc_construct_here : Note<"'%0' construct is here">; def err_acc_loop_spec_conflict : Error<"OpenACC clause '%0' on '%1' construct conflicts with previous " "data dependence clause">; +def err_acc_collapse_loop_count + : Error<"OpenACC 'collapse' clause loop count must be a %select{constant " + "expression|positive integer value, evaluated to %1}0">; // AMDGCN builtins diagnostics def err_amdgcn_global_load_lds_size_invalid_value : Error<"invalid size value">; diff --git a/clang/include/clang/Basic/OpenACCClauses.def b/clang/include/clang/Basic/OpenACCClauses.def index 85f4859925f0b..19cdfe7672133 100644 --- a/clang/include/clang/Basic/OpenACCClauses.def +++ b/clang/include/clang/Basic/OpenACCClauses.def @@ -24,6 +24,7 @@ VISIT_CLAUSE(Auto) VISIT_CLAUSE(Async) VISIT_CLAUSE(Attach) +VISIT_CLAUSE(Collapse) VISIT_CLAUSE(Copy) CLAUSE_ALIAS(PCopy, Copy, true) CLAUSE_ALIAS(PresentOrCopy, Copy, true) diff --git a/clang/include/clang/Basic/arm_sme.td b/clang/include/clang/Basic/arm_sme.td index ae6b55e98827f..45673cb915c5e 100644 --- a/clang/include/clang/Basic/arm_sme.td +++ b/clang/include/clang/Basic/arm_sme.td @@ -817,4 +817,11 @@ multiclass ZAReadzArray{ defm SVREADZ_VG2 : ZAReadzArray<"2">; defm SVREADZ_VG4 : ZAReadzArray<"4">; + +let SMETargetGuard = "sme2,sme-lutv2" in { + def SVWRITE_LANE_ZT : SInst<"svwrite_lane_zt[_{d}]", "vidi", "cUcsUsiUilUlfhdb", MergeNone, "aarch64_sme_write_lane_zt", [IsStreaming, IsInOutZT0], [ImmCheck<0, ImmCheck0_0>, ImmCheck<2, ImmCheck1_3>]>; + def SVWRITE_ZT : SInst<"svwrite_zt[_{d}]", "vid", "cUcsUsiUilUlfhdb", MergeNone, "aarch64_sme_write_zt", [IsStreaming, IsOutZT0], [ImmCheck<0, ImmCheck0_0>]>; + def SVLUTI4_ZT_X4 : SInst<"svluti4_zt_{d}_x4", "4i2.u", "cUc", MergeNone, "aarch64_sme_luti4_zt_x4", [IsStreaming, IsInZT0], [ImmCheck<0, ImmCheck0_0>]>; +} + } // let SVETargetGuard = InvalidMode diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index aedc4c16d4e9d..607ff47a857b8 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -6898,6 +6898,8 @@ def module_suffix : Separate<["-"], "module-suffix">, Group, MetaVarNa HelpText<"Use as the suffix for module files (the default value is `.mod`)">; def fno_reformat : Flag<["-"], "fno-reformat">, Group, HelpText<"Dump the cooked character stream in -E mode">; +def fpreprocess_include_lines : Flag<["-"], "fpreprocess-include-lines">, Group, + HelpText<"Treat INCLUDE lines like #include directives in -E mode">; defm analyzed_objects_for_unparse : OptOutFC1FFlag<"analyzed-objects-for-unparse", "", "Do not use the analyzed objects when unparsing">; def emit_fir : Flag<["-"], "emit-fir">, Group, diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index a9ce3681338d4..d616c3834c429 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -11253,6 +11253,7 @@ class Sema final : public SemaBase { ConceptDecl *NamedConcept, NamedDecl *FoundDecl, const TemplateArgumentListInfo *TemplateArgs, TemplateTypeParmDecl *ConstrainedParameter, + QualType ConstrainedType, SourceLocation EllipsisLoc); bool AttachTypeConstraint(AutoTypeLoc TL, diff --git a/clang/include/clang/Sema/SemaOpenACC.h b/clang/include/clang/Sema/SemaOpenACC.h index 0ca76842e5f90..839fdb79cd0ac 100644 --- a/clang/include/clang/Sema/SemaOpenACC.h +++ b/clang/include/clang/Sema/SemaOpenACC.h @@ -87,9 +87,14 @@ class SemaOpenACC : public SemaBase { SmallVector VarList; }; + struct CollapseDetails { + bool IsForce; + Expr *LoopCount; + }; + std::variant + ReductionDetails, CollapseDetails> Details = std::monostate{}; public: @@ -246,6 +251,18 @@ class SemaOpenACC : public SemaBase { return std::get(Details).IsZero; } + bool isForce() const { + assert(ClauseKind == OpenACCClauseKind::Collapse && + "Only 'collapse' has a force tag"); + return std::get(Details).IsForce; + } + + Expr *getLoopCount() const { + assert(ClauseKind == OpenACCClauseKind::Collapse && + "Only 'collapse' has a loop count"); + return std::get(Details).LoopCount; + } + ArrayRef getDeviceTypeArchitectures() const { assert((ClauseKind == OpenACCClauseKind::DeviceType || ClauseKind == OpenACCClauseKind::DType) && @@ -384,6 +401,12 @@ class SemaOpenACC : public SemaBase { "Only 'device_type'/'dtype' has a device-type-arg list"); Details = DeviceTypeDetails{std::move(Archs)}; } + + void setCollapseDetails(bool IsForce, Expr *LoopCount) { + assert(ClauseKind == OpenACCClauseKind::Collapse && + "Only 'collapse' has collapse details"); + Details = CollapseDetails{IsForce, LoopCount}; + } }; SemaOpenACC(Sema &S); @@ -448,6 +471,8 @@ class SemaOpenACC : public SemaBase { Expr *LowerBound, SourceLocation ColonLocFirst, Expr *Length, SourceLocation RBLoc); + /// Checks the loop depth value for a collapse clause. + ExprResult CheckCollapseLoopCount(Expr *LoopCount); /// Helper type for the registration/assignment of constructs that need to /// 'know' about their parent constructs and hold a reference to them, such as diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h index 5be33ae0ed1b9..bde19a09d6ae0 100644 --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -1128,7 +1128,7 @@ enum PredefinedTypeIDs { #define WASM_TYPE(Name, Id, SingletonId) PREDEF_TYPE_##Id##_ID, #include "clang/Basic/WebAssemblyReferenceTypes.def" // \brief AMDGPU types with auto numeration -#define AMDGPU_TYPE(Name, Id, SingletonId) PREDEF_TYPE_##Id##_ID, +#define AMDGPU_TYPE(Name, Id, SingletonId, Width, Align) PREDEF_TYPE_##Id##_ID, #include "clang/Basic/AMDGPUTypes.def" // \brief HLSL intangible types with auto numeration #define HLSL_INTANGIBLE_TYPE(Name, Id, SingletonId) PREDEF_TYPE_##Id##_ID, diff --git a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td index 6bc389f9da265..349040c15eeb8 100644 --- a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td +++ b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td @@ -1703,6 +1703,12 @@ def TaintedAllocChecker: Checker<"TaintedAlloc">, Dependencies<[DynamicMemoryModeling, TaintPropagationChecker]>, Documentation; +def TaintedDivChecker: Checker<"TaintedDiv">, + HelpText<"Check for divisions where the denominator is tainted " + "(attacker controlled) and might be 0.">, + Dependencies<[TaintPropagationChecker]>, + Documentation; + } // end "optin.taint" //===----------------------------------------------------------------------===// diff --git a/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h b/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h index 24c5b66fd5822..de40b96614dbc 100644 --- a/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h +++ b/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h @@ -221,6 +221,10 @@ class CheckerManager { return static_cast(CheckerTags[tag]); } + template bool isRegisteredChecker() { + return CheckerTags.contains(getTag()); + } + //===----------------------------------------------------------------------===// // Functions for running checkers for AST traversing. //===----------------------------------------------------------------------===// diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 458075020f6b2..735def67f7840 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -1441,7 +1441,7 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target, if (Target.getTriple().isAMDGPU() || (AuxTarget && AuxTarget->getTriple().isAMDGPU())) { -#define AMDGPU_TYPE(Name, Id, SingletonId) \ +#define AMDGPU_TYPE(Name, Id, SingletonId, Width, Align) \ InitBuiltinType(SingletonId, BuiltinType::Id); #include "clang/Basic/AMDGPUTypes.def" } @@ -2264,7 +2264,7 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { Align = 8; \ break; #include "clang/Basic/WebAssemblyReferenceTypes.def" -#define AMDGPU_OPAQUE_PTR_TYPE(NAME, AS, WIDTH, ALIGN, ID, SINGLETONID) \ +#define AMDGPU_TYPE(NAME, ID, SINGLETONID, WIDTH, ALIGN) \ case BuiltinType::ID: \ Width = WIDTH; \ Align = ALIGN; \ @@ -3398,7 +3398,7 @@ static void encodeTypeForFunctionPointerAuth(const ASTContext &Ctx, #include "clang/Basic/HLSLIntangibleTypes.def" case BuiltinType::Dependent: llvm_unreachable("should never get here"); -#define AMDGPU_TYPE(Name, Id, SingletonId) case BuiltinType::Id: +#define AMDGPU_TYPE(Name, Id, SingletonId, Width, Align) case BuiltinType::Id: #include "clang/Basic/AMDGPUTypes.def" case BuiltinType::WasmExternRef: #define RVV_TYPE(Name, Id, SingletonId) case BuiltinType::Id: @@ -8633,7 +8633,7 @@ static char getObjCEncodingForPrimitiveType(const ASTContext *C, #include "clang/Basic/RISCVVTypes.def" #define WASM_TYPE(Name, Id, SingletonId) case BuiltinType::Id: #include "clang/Basic/WebAssemblyReferenceTypes.def" -#define AMDGPU_TYPE(Name, Id, SingletonId) case BuiltinType::Id: +#define AMDGPU_TYPE(Name, Id, SingletonId, Width, Align) case BuiltinType::Id: #include "clang/Basic/AMDGPUTypes.def" { DiagnosticsEngine &Diags = C->getDiagnostics(); diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 60175f1ccb342..020a2f396b5aa 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -1138,7 +1138,7 @@ ExpectedType ASTNodeImporter::VisitBuiltinType(const BuiltinType *T) { case BuiltinType::Id: \ return Importer.getToContext().SingletonId; #include "clang/Basic/WebAssemblyReferenceTypes.def" -#define AMDGPU_TYPE(Name, Id, SingletonId) \ +#define AMDGPU_TYPE(Name, Id, SingletonId, Width, Align) \ case BuiltinType::Id: \ return Importer.getToContext().SingletonId; #include "clang/Basic/AMDGPUTypes.def" diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp index c24c4b6db2a5b..680be736aa647 100644 --- a/clang/lib/AST/ByteCode/Compiler.cpp +++ b/clang/lib/AST/ByteCode/Compiler.cpp @@ -763,6 +763,9 @@ bool Compiler::VisitFixedPointLiteral(const FixedPointLiteral *E) { assert(E->getType()->isFixedPointType()); assert(classifyPrim(E) == PT_FixedPoint); + if (DiscardResult) + return true; + auto Sem = Ctx.getASTContext().getFixedPointSemantics(E->getType()); APInt Value = E->getValue(); return this->emitConstFixedPoint(FixedPoint(Value, Sem), E); @@ -1542,19 +1545,30 @@ bool Compiler::VisitFixedPointBinOp(const BinaryOperator *E) { return true; }; + auto MaybeCastToBool = [&](bool Result) { + if (!Result) + return false; + PrimType T = classifyPrim(E); + if (DiscardResult) + return this->emitPop(T, E); + if (T != PT_Bool) + return this->emitCast(PT_Bool, T, E); + return true; + }; + switch (E->getOpcode()) { case BO_EQ: - return this->emitEQFixedPoint(E); + return MaybeCastToBool(this->emitEQFixedPoint(E)); case BO_NE: - return this->emitNEFixedPoint(E); + return MaybeCastToBool(this->emitNEFixedPoint(E)); case BO_LT: - return this->emitLTFixedPoint(E); + return MaybeCastToBool(this->emitLTFixedPoint(E)); case BO_LE: - return this->emitLEFixedPoint(E); + return MaybeCastToBool(this->emitLEFixedPoint(E)); case BO_GT: - return this->emitGTFixedPoint(E); + return MaybeCastToBool(this->emitGTFixedPoint(E)); case BO_GE: - return this->emitGEFixedPoint(E); + return MaybeCastToBool(this->emitGEFixedPoint(E)); case BO_Add: return ConvertResult(this->emitAddFixedPoint(E)); case BO_Sub: diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h index 68c04587a4919..8a3c6810e0e11 100644 --- a/clang/lib/AST/ByteCode/Interp.h +++ b/clang/lib/AST/ByteCode/Interp.h @@ -235,14 +235,16 @@ bool CheckDivRem(InterpState &S, CodePtr OpPC, const T &LHS, const T &RHS) { return false; } - if (LHS.isSigned() && LHS.isMin() && RHS.isNegative() && RHS.isMinusOne()) { - APSInt LHSInt = LHS.toAPSInt(); - SmallString<32> Trunc; - (-LHSInt.extend(LHSInt.getBitWidth() + 1)).toString(Trunc, 10); - const SourceInfo &Loc = S.Current->getSource(OpPC); - const Expr *E = S.Current->getExpr(OpPC); - S.CCEDiag(Loc, diag::note_constexpr_overflow) << Trunc << E->getType(); - return false; + if constexpr (!std::is_same_v) { + if (LHS.isSigned() && LHS.isMin() && RHS.isNegative() && RHS.isMinusOne()) { + APSInt LHSInt = LHS.toAPSInt(); + SmallString<32> Trunc; + (-LHSInt.extend(LHSInt.getBitWidth() + 1)).toString(Trunc, 10); + const SourceInfo &Loc = S.Current->getSource(OpPC); + const Expr *E = S.Current->getExpr(OpPC); + S.CCEDiag(Loc, diag::note_constexpr_overflow) << Trunc << E->getType(); + return false; + } } return true; } diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp index 82ed6d9e7a2ff..347b23d7b89c4 100644 --- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp +++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp @@ -14,6 +14,7 @@ #include "clang/AST/OSLog.h" #include "clang/AST/RecordLayout.h" #include "clang/Basic/Builtins.h" +#include "clang/Basic/TargetBuiltins.h" #include "clang/Basic/TargetInfo.h" #include "llvm/Support/SipHash.h" @@ -1152,6 +1153,72 @@ static bool interp__builtin_is_aligned_up_down(InterpState &S, CodePtr OpPC, return false; } +static bool interp__builtin_ia32_bextr(InterpState &S, CodePtr OpPC, + const InterpFrame *Frame, + const Function *Func, + const CallExpr *Call) { + PrimType ValT = *S.Ctx.classify(Call->getArg(0)); + PrimType IndexT = *S.Ctx.classify(Call->getArg(1)); + APSInt Val = peekToAPSInt(S.Stk, ValT, + align(primSize(ValT)) + align(primSize(IndexT))); + APSInt Index = peekToAPSInt(S.Stk, IndexT); + + unsigned BitWidth = Val.getBitWidth(); + uint64_t Shift = Index.extractBitsAsZExtValue(8, 0); + uint64_t Length = Index.extractBitsAsZExtValue(8, 8); + Length = Length > BitWidth ? BitWidth : Length; + + // Handle out of bounds cases. + if (Length == 0 || Shift >= BitWidth) { + pushInteger(S, 0, Call->getType()); + return true; + } + + uint64_t Result = Val.getZExtValue() >> Shift; + Result &= llvm::maskTrailingOnes(Length); + pushInteger(S, Result, Call->getType()); + return true; +} + +static bool interp__builtin_ia32_bzhi(InterpState &S, CodePtr OpPC, + const InterpFrame *Frame, + const Function *Func, + const CallExpr *Call) { + PrimType ValT = *S.Ctx.classify(Call->getArg(0)); + PrimType IndexT = *S.Ctx.classify(Call->getArg(1)); + + APSInt Val = peekToAPSInt(S.Stk, ValT, + align(primSize(ValT)) + align(primSize(IndexT))); + APSInt Idx = peekToAPSInt(S.Stk, IndexT); + + unsigned BitWidth = Val.getBitWidth(); + uint64_t Index = Idx.extractBitsAsZExtValue(8, 0); + + if (Index < BitWidth) + Val.clearHighBits(BitWidth - Index); + + pushInteger(S, Val, Call->getType()); + return true; +} + +static bool interp__builtin_ia32_lzcnt(InterpState &S, CodePtr OpPC, + const InterpFrame *Frame, + const Function *Func, + const CallExpr *Call) { + APSInt Val = peekToAPSInt(S.Stk, *S.Ctx.classify(Call->getArg(0))); + pushInteger(S, Val.countLeadingZeros(), Call->getType()); + return true; +} + +static bool interp__builtin_ia32_tzcnt(InterpState &S, CodePtr OpPC, + const InterpFrame *Frame, + const Function *Func, + const CallExpr *Call) { + APSInt Val = peekToAPSInt(S.Stk, *S.Ctx.classify(Call->getArg(0))); + pushInteger(S, Val.countTrailingZeros(), Call->getType()); + return true; +} + static bool interp__builtin_os_log_format_buffer_size(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, @@ -1737,6 +1804,34 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F, return false; break; + case clang::X86::BI__builtin_ia32_bextr_u32: + case clang::X86::BI__builtin_ia32_bextr_u64: + case clang::X86::BI__builtin_ia32_bextri_u32: + case clang::X86::BI__builtin_ia32_bextri_u64: + if (!interp__builtin_ia32_bextr(S, OpPC, Frame, F, Call)) + return false; + break; + + case clang::X86::BI__builtin_ia32_bzhi_si: + case clang::X86::BI__builtin_ia32_bzhi_di: + if (!interp__builtin_ia32_bzhi(S, OpPC, Frame, F, Call)) + return false; + break; + + case clang::X86::BI__builtin_ia32_lzcnt_u16: + case clang::X86::BI__builtin_ia32_lzcnt_u32: + case clang::X86::BI__builtin_ia32_lzcnt_u64: + if (!interp__builtin_ia32_lzcnt(S, OpPC, Frame, F, Call)) + return false; + break; + + case clang::X86::BI__builtin_ia32_tzcnt_u16: + case clang::X86::BI__builtin_ia32_tzcnt_u32: + case clang::X86::BI__builtin_ia32_tzcnt_u64: + if (!interp__builtin_ia32_tzcnt(S, OpPC, Frame, F, Call)) + return false; + break; + case Builtin::BI__builtin_os_log_format_buffer_size: if (!interp__builtin_os_log_format_buffer_size(S, OpPC, Frame, F, Call)) return false; diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index a14b1b33d35ef..84ef9f74582ef 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -3302,6 +3302,7 @@ bool FunctionDecl::isImmediateFunction() const { bool FunctionDecl::isMain() const { return isNamed(this, "main") && !getLangOpts().Freestanding && + !getLangOpts().HLSL && (getDeclContext()->getRedeclContext()->isTranslationUnit() || isExternC()); } diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index 01143391edab4..f5a0aa8f82512 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -2211,9 +2211,10 @@ CXXDeductionGuideDecl *CXXDeductionGuideDecl::Create( ASTContext &C, DeclContext *DC, SourceLocation StartLoc, ExplicitSpecifier ES, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, SourceLocation EndLocation, CXXConstructorDecl *Ctor, - DeductionCandidate Kind) { - return new (C, DC) CXXDeductionGuideDecl(C, DC, StartLoc, ES, NameInfo, T, - TInfo, EndLocation, Ctor, Kind); + DeductionCandidate Kind, Expr *TrailingRequiresClause) { + return new (C, DC) + CXXDeductionGuideDecl(C, DC, StartLoc, ES, NameInfo, T, TInfo, + EndLocation, Ctor, Kind, TrailingRequiresClause); } CXXDeductionGuideDecl * @@ -2221,7 +2222,7 @@ CXXDeductionGuideDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { return new (C, ID) CXXDeductionGuideDecl( C, nullptr, SourceLocation(), ExplicitSpecifier(), DeclarationNameInfo(), QualType(), nullptr, SourceLocation(), nullptr, - DeductionCandidate::Normal); + DeductionCandidate::Normal, nullptr); } RequiresExprBodyDecl *RequiresExprBodyDecl::Create( diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 5185669394476..48816d3078826 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -12114,7 +12114,7 @@ GCCTypeClass EvaluateBuiltinClassifyType(QualType T, #include "clang/Basic/RISCVVTypes.def" #define WASM_TYPE(Name, Id, SingletonId) case BuiltinType::Id: #include "clang/Basic/WebAssemblyReferenceTypes.def" -#define AMDGPU_TYPE(Name, Id, SingletonId) case BuiltinType::Id: +#define AMDGPU_TYPE(Name, Id, SingletonId, Width, Align) case BuiltinType::Id: #include "clang/Basic/AMDGPUTypes.def" #define HLSL_INTANGIBLE_TYPE(Name, Id, SingletonId) case BuiltinType::Id: #include "clang/Basic/HLSLIntangibleTypes.def" @@ -13486,6 +13486,68 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, Result &= llvm::maskTrailingOnes(Length); return Success(Result, E); } + + case clang::X86::BI__builtin_ia32_bzhi_si: + case clang::X86::BI__builtin_ia32_bzhi_di: { + APSInt Val, Idx; + if (!EvaluateInteger(E->getArg(0), Val, Info) || + !EvaluateInteger(E->getArg(1), Idx, Info)) + return false; + + unsigned BitWidth = Val.getBitWidth(); + unsigned Index = Idx.extractBitsAsZExtValue(8, 0); + if (Index < BitWidth) + Val.clearHighBits(BitWidth - Index); + return Success(Val, E); + } + + case clang::X86::BI__builtin_ia32_lzcnt_u16: + case clang::X86::BI__builtin_ia32_lzcnt_u32: + case clang::X86::BI__builtin_ia32_lzcnt_u64: { + APSInt Val; + if (!EvaluateInteger(E->getArg(0), Val, Info)) + return false; + return Success(Val.countLeadingZeros(), E); + } + + case clang::X86::BI__builtin_ia32_tzcnt_u16: + case clang::X86::BI__builtin_ia32_tzcnt_u32: + case clang::X86::BI__builtin_ia32_tzcnt_u64: { + APSInt Val; + if (!EvaluateInteger(E->getArg(0), Val, Info)) + return false; + return Success(Val.countTrailingZeros(), E); + } + + case clang::X86::BI__builtin_ia32_pdep_si: + case clang::X86::BI__builtin_ia32_pdep_di: { + APSInt Val, Msk; + if (!EvaluateInteger(E->getArg(0), Val, Info) || + !EvaluateInteger(E->getArg(1), Msk, Info)) + return false; + + unsigned BitWidth = Val.getBitWidth(); + APInt Result = APInt::getZero(BitWidth); + for (unsigned I = 0, P = 0; I != BitWidth; ++I) + if (Msk[I]) + Result.setBitVal(I, Val[P++]); + return Success(Result, E); + } + + case clang::X86::BI__builtin_ia32_pext_si: + case clang::X86::BI__builtin_ia32_pext_di: { + APSInt Val, Msk; + if (!EvaluateInteger(E->getArg(0), Val, Info) || + !EvaluateInteger(E->getArg(1), Msk, Info)) + return false; + + unsigned BitWidth = Val.getBitWidth(); + APInt Result = APInt::getZero(BitWidth); + for (unsigned I = 0, P = 0; I != BitWidth; ++I) + if (Msk[I]) + Result.setBitVal(P++, Val[I]); + return Success(Result, E); + } } } diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index 117255178eebb..1feec13f9deef 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -3430,7 +3430,7 @@ void CXXNameMangler::mangleType(const BuiltinType *T) { Out << 'u' << type_name.size() << type_name; \ break; #include "clang/Basic/WebAssemblyReferenceTypes.def" -#define AMDGPU_TYPE(Name, Id, SingletonId) \ +#define AMDGPU_TYPE(Name, Id, SingletonId, Width, Align) \ case BuiltinType::Id: \ type_name = Name; \ Out << 'u' << type_name.size() << type_name; \ diff --git a/clang/lib/AST/MicrosoftMangle.cpp b/clang/lib/AST/MicrosoftMangle.cpp index 7b069c66aed59..e4c8663c134fd 100644 --- a/clang/lib/AST/MicrosoftMangle.cpp +++ b/clang/lib/AST/MicrosoftMangle.cpp @@ -2814,7 +2814,7 @@ void MicrosoftCXXNameMangler::mangleType(const BuiltinType *T, Qualifiers, #include "clang/Basic/PPCTypes.def" #define RVV_TYPE(Name, Id, SingletonId) case BuiltinType::Id: #include "clang/Basic/RISCVVTypes.def" -#define AMDGPU_TYPE(Name, Id, SingletonId) case BuiltinType::Id: +#define AMDGPU_TYPE(Name, Id, SingletonId, Width, Align) case BuiltinType::Id: #include "clang/Basic/AMDGPUTypes.def" case BuiltinType::ShortAccum: case BuiltinType::Accum: diff --git a/clang/lib/AST/NSAPI.cpp b/clang/lib/AST/NSAPI.cpp index 3d1f8488a8927..311fec32bbfa9 100644 --- a/clang/lib/AST/NSAPI.cpp +++ b/clang/lib/AST/NSAPI.cpp @@ -453,7 +453,7 @@ NSAPI::getNSNumberFactoryMethodKind(QualType T) const { #include "clang/Basic/RISCVVTypes.def" #define WASM_TYPE(Name, Id, SingletonId) case BuiltinType::Id: #include "clang/Basic/WebAssemblyReferenceTypes.def" -#define AMDGPU_TYPE(Name, Id, SingletonId) case BuiltinType::Id: +#define AMDGPU_TYPE(Name, Id, SingletonId, Width, Align) case BuiltinType::Id: #include "clang/Basic/AMDGPUTypes.def" #define HLSL_INTANGIBLE_TYPE(Name, Id, SingletonId) case BuiltinType::Id: #include "clang/Basic/HLSLIntangibleTypes.def" diff --git a/clang/lib/AST/OpenACCClause.cpp b/clang/lib/AST/OpenACCClause.cpp index 95089a9b79e26..d864ded33e8d1 100644 --- a/clang/lib/AST/OpenACCClause.cpp +++ b/clang/lib/AST/OpenACCClause.cpp @@ -43,7 +43,7 @@ bool OpenACCClauseWithCondition::classof(const OpenACCClause *C) { bool OpenACCClauseWithSingleIntExpr::classof(const OpenACCClause *C) { return OpenACCNumWorkersClause::classof(C) || OpenACCVectorLengthClause::classof(C) || - OpenACCAsyncClause::classof(C); + OpenACCCollapseClause::classof(C) || OpenACCAsyncClause::classof(C); } OpenACCDefaultClause *OpenACCDefaultClause::Create(const ASTContext &C, OpenACCDefaultClauseKind K, @@ -134,6 +134,30 @@ OpenACCNumWorkersClause::Create(const ASTContext &C, SourceLocation BeginLoc, OpenACCNumWorkersClause(BeginLoc, LParenLoc, IntExpr, EndLoc); } +OpenACCCollapseClause::OpenACCCollapseClause(SourceLocation BeginLoc, + SourceLocation LParenLoc, + bool HasForce, Expr *LoopCount, + SourceLocation EndLoc) + : OpenACCClauseWithSingleIntExpr(OpenACCClauseKind::Collapse, BeginLoc, + LParenLoc, LoopCount, EndLoc), + HasForce(HasForce) { + assert(LoopCount && "LoopCount required"); +} + +OpenACCCollapseClause * +OpenACCCollapseClause::Create(const ASTContext &C, SourceLocation BeginLoc, + SourceLocation LParenLoc, bool HasForce, + Expr *LoopCount, SourceLocation EndLoc) { + assert( + LoopCount && + (LoopCount->isInstantiationDependent() || isa(LoopCount)) && + "Loop count not constant expression"); + void *Mem = + C.Allocate(sizeof(OpenACCCollapseClause), alignof(OpenACCCollapseClause)); + return new (Mem) + OpenACCCollapseClause(BeginLoc, LParenLoc, HasForce, LoopCount, EndLoc); +} + OpenACCVectorLengthClause::OpenACCVectorLengthClause(SourceLocation BeginLoc, SourceLocation LParenLoc, Expr *IntExpr, @@ -550,3 +574,11 @@ void OpenACCClausePrinter::VisitIndependentClause( void OpenACCClausePrinter::VisitSeqClause(const OpenACCSeqClause &C) { OS << "seq"; } + +void OpenACCClausePrinter::VisitCollapseClause(const OpenACCCollapseClause &C) { + OS << "collapse("; + if (C.hasForce()) + OS << "force:"; + printExpr(C.getLoopCount()); + OS << ")"; +} diff --git a/clang/lib/AST/PrintfFormatString.cpp b/clang/lib/AST/PrintfFormatString.cpp index 3c6cd2d0f4341..2181591ba1790 100644 --- a/clang/lib/AST/PrintfFormatString.cpp +++ b/clang/lib/AST/PrintfFormatString.cpp @@ -865,7 +865,7 @@ bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt, #include "clang/Basic/RISCVVTypes.def" #define WASM_TYPE(Name, Id, SingletonId) case BuiltinType::Id: #include "clang/Basic/WebAssemblyReferenceTypes.def" -#define AMDGPU_TYPE(Name, Id, SingletonId) case BuiltinType::Id: +#define AMDGPU_TYPE(Name, Id, SingletonId, Width, Align) case BuiltinType::Id: #include "clang/Basic/AMDGPUTypes.def" #define HLSL_INTANGIBLE_TYPE(Name, Id, SingletonId) case BuiltinType::Id: #include "clang/Basic/HLSLIntangibleTypes.def" diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp index ad4281986f668..c3812844ab8a3 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -2558,6 +2558,12 @@ void OpenACCClauseProfiler::VisitNumWorkersClause( Profiler.VisitStmt(Clause.getIntExpr()); } +void OpenACCClauseProfiler::VisitCollapseClause( + const OpenACCCollapseClause &Clause) { + assert(Clause.getLoopCount() && "collapse clause requires a valid int expr"); + Profiler.VisitStmt(Clause.getLoopCount()); +} + void OpenACCClauseProfiler::VisitPrivateClause( const OpenACCPrivateClause &Clause) { for (auto *E : Clause.getVarList()) diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp index 3c51c74647182..8a74159c7c93e 100644 --- a/clang/lib/AST/TextNodeDumper.cpp +++ b/clang/lib/AST/TextNodeDumper.cpp @@ -419,6 +419,12 @@ void TextNodeDumper::Visit(const OpenACCClause *C) { // but print 'clause' here so it is clear what is happening from the dump. OS << " clause"; break; + case OpenACCClauseKind::Collapse: + OS << " clause"; + if (cast(C)->hasForce()) + OS << ": force"; + break; + case OpenACCClauseKind::CopyIn: case OpenACCClauseKind::PCopyIn: case OpenACCClauseKind::PresentOrCopyIn: diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index a55e6c8bf0261..c703e43f12a9a 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -3453,7 +3453,7 @@ StringRef BuiltinType::getName(const PrintingPolicy &Policy) const { case Id: \ return Name; #include "clang/Basic/WebAssemblyReferenceTypes.def" -#define AMDGPU_TYPE(Name, Id, SingletonId) \ +#define AMDGPU_TYPE(Name, Id, SingletonId, Width, Align) \ case Id: \ return Name; #include "clang/Basic/AMDGPUTypes.def" @@ -4793,7 +4793,7 @@ bool Type::canHaveNullability(bool ResultIfUnknown) const { #include "clang/Basic/RISCVVTypes.def" #define WASM_TYPE(Name, Id, SingletonId) case BuiltinType::Id: #include "clang/Basic/WebAssemblyReferenceTypes.def" -#define AMDGPU_TYPE(Name, Id, SingletonId) case BuiltinType::Id: +#define AMDGPU_TYPE(Name, Id, SingletonId, Width, Align) case BuiltinType::Id: #include "clang/Basic/AMDGPUTypes.def" #define HLSL_INTANGIBLE_TYPE(Name, Id, SingletonId) case BuiltinType::Id: #include "clang/Basic/HLSLIntangibleTypes.def" diff --git a/clang/lib/AST/TypeLoc.cpp b/clang/lib/AST/TypeLoc.cpp index 8aada7e603407..fbb7fc5cd7690 100644 --- a/clang/lib/AST/TypeLoc.cpp +++ b/clang/lib/AST/TypeLoc.cpp @@ -428,7 +428,7 @@ TypeSpecifierType BuiltinTypeLoc::getWrittenTypeSpec() const { #include "clang/Basic/RISCVVTypes.def" #define WASM_TYPE(Name, Id, SingletonId) case BuiltinType::Id: #include "clang/Basic/WebAssemblyReferenceTypes.def" -#define AMDGPU_TYPE(Name, Id, SingletonId) case BuiltinType::Id: +#define AMDGPU_TYPE(Name, Id, SingletonId, Width, Align) case BuiltinType::Id: #include "clang/Basic/AMDGPUTypes.def" #define HLSL_INTANGIBLE_TYPE(Name, Id, SingletonId) case BuiltinType::Id: #include "clang/Basic/HLSLIntangibleTypes.def" diff --git a/clang/lib/Analysis/ThreadSafety.cpp b/clang/lib/Analysis/ThreadSafety.cpp index 5577f45aa5217..01ef18f7eba37 100644 --- a/clang/lib/Analysis/ThreadSafety.cpp +++ b/clang/lib/Analysis/ThreadSafety.cpp @@ -1073,6 +1073,8 @@ class ThreadSafetyAnalyzer { ProtectedOperationKind POK); void checkPtAccess(const FactSet &FSet, const Expr *Exp, AccessKind AK, ProtectedOperationKind POK); + + void checkMismatchedFunctionAttrs(const FunctionDecl *FD); }; } // namespace @@ -2263,6 +2265,28 @@ static bool neverReturns(const CFGBlock *B) { return false; } +void ThreadSafetyAnalyzer::checkMismatchedFunctionAttrs( + const FunctionDecl *FD) { + FD = FD->getMostRecentDecl(); + + auto collectCapabilities = [&](const FunctionDecl *FD) { + SmallVector Args; + for (const auto *A : FD->specific_attrs()) { + for (const Expr *E : A->args()) + Args.push_back(SxBuilder.translateAttrExpr(E, nullptr)); + } + return Args; + }; + + auto FDArgs = collectCapabilities(FD); + for (const FunctionDecl *D = FD->getPreviousDecl(); D; + D = D->getPreviousDecl()) { + auto DArgs = collectCapabilities(D); + if (DArgs.size() != FDArgs.size()) + Handler.handleAttributeMismatch(FD, D); + } +} + /// Check a function's CFG for thread-safety violations. /// /// We traverse the blocks in the CFG, compute the set of mutexes that are held @@ -2282,6 +2306,9 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) { const NamedDecl *D = walker.getDecl(); CurrentFunction = dyn_cast(D); + if (CurrentFunction) + checkMismatchedFunctionAttrs(CurrentFunction); + if (D->hasAttr()) return; diff --git a/clang/lib/Basic/Targets/RISCV.cpp b/clang/lib/Basic/Targets/RISCV.cpp index b6ea4440507ea..2a225820208c8 100644 --- a/clang/lib/Basic/Targets/RISCV.cpp +++ b/clang/lib/Basic/Targets/RISCV.cpp @@ -44,7 +44,7 @@ ArrayRef RISCVTargetInfo::getGCCRegNames() const { "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31", // CSRs - "fflags", "frm", "vtype", "vl", "vxsat", "vxrm" + "fflags", "frm", "vtype", "vl", "vxsat", "vxrm", "sf.vcix_state" }; // clang-format on return llvm::ArrayRef(GCCRegNames); diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index d739597de4c85..da3eca73bfb57 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -22340,10 +22340,60 @@ Value *CodeGenFunction::EmitRISCVBuiltinExpr(unsigned BuiltinID, return Store; } + // XCValu + case RISCV::BI__builtin_riscv_cv_alu_addN: + ID = Intrinsic::riscv_cv_alu_addN; + break; + case RISCV::BI__builtin_riscv_cv_alu_addRN: + ID = Intrinsic::riscv_cv_alu_addRN; + break; + case RISCV::BI__builtin_riscv_cv_alu_adduN: + ID = Intrinsic::riscv_cv_alu_adduN; + break; + case RISCV::BI__builtin_riscv_cv_alu_adduRN: + ID = Intrinsic::riscv_cv_alu_adduRN; + break; + case RISCV::BI__builtin_riscv_cv_alu_clip: + ID = Intrinsic::riscv_cv_alu_clip; + break; + case RISCV::BI__builtin_riscv_cv_alu_clipu: + ID = Intrinsic::riscv_cv_alu_clipu; + break; + case RISCV::BI__builtin_riscv_cv_alu_extbs: + return Builder.CreateSExt(Builder.CreateTrunc(Ops[0], Int8Ty), Int32Ty, + "extbs"); + case RISCV::BI__builtin_riscv_cv_alu_extbz: + return Builder.CreateZExt(Builder.CreateTrunc(Ops[0], Int8Ty), Int32Ty, + "extbz"); + case RISCV::BI__builtin_riscv_cv_alu_exths: + return Builder.CreateSExt(Builder.CreateTrunc(Ops[0], Int16Ty), Int32Ty, + "exths"); + case RISCV::BI__builtin_riscv_cv_alu_exthz: + return Builder.CreateZExt(Builder.CreateTrunc(Ops[0], Int16Ty), Int32Ty, + "exthz"); + case RISCV::BI__builtin_riscv_cv_alu_slet: + return Builder.CreateZExt(Builder.CreateICmpSLE(Ops[0], Ops[1]), Int32Ty, + "sle"); + case RISCV::BI__builtin_riscv_cv_alu_sletu: + return Builder.CreateZExt(Builder.CreateICmpULE(Ops[0], Ops[1]), Int32Ty, + "sleu"); + case RISCV::BI__builtin_riscv_cv_alu_subN: + ID = Intrinsic::riscv_cv_alu_subN; + break; + case RISCV::BI__builtin_riscv_cv_alu_subRN: + ID = Intrinsic::riscv_cv_alu_subRN; + break; + case RISCV::BI__builtin_riscv_cv_alu_subuN: + ID = Intrinsic::riscv_cv_alu_subuN; + break; + case RISCV::BI__builtin_riscv_cv_alu_subuRN: + ID = Intrinsic::riscv_cv_alu_subuRN; + break; - // Vector builtins are handled from here. + // Vector builtins are handled from here. #include "clang/Basic/riscv_vector_builtin_cg.inc" - // SiFive Vector builtins are handled from here. + + // SiFive Vector builtins are handled from here. #include "clang/Basic/riscv_sifive_vector_builtin_cg.inc" } diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index 4782e80f22177..8887c4de7c4c8 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -900,7 +900,7 @@ llvm::DIType *CGDebugInfo::CreateType(const BuiltinType *BT) { return SingletonId; \ } #include "clang/Basic/WebAssemblyReferenceTypes.def" -#define AMDGPU_OPAQUE_PTR_TYPE(Name, AS, Width, Align, Id, SingletonId) \ +#define AMDGPU_OPAQUE_PTR_TYPE(Name, Id, SingletonId, Width, Align, AS) \ case BuiltinType::Id: { \ if (!SingletonId) \ SingletonId = \ diff --git a/clang/lib/CodeGen/CGDebugInfo.h b/clang/lib/CodeGen/CGDebugInfo.h index 4ccff581cadb2..3fd0237a1c61d 100644 --- a/clang/lib/CodeGen/CGDebugInfo.h +++ b/clang/lib/CodeGen/CGDebugInfo.h @@ -85,7 +85,8 @@ class CGDebugInfo { #include "clang/Basic/OpenCLExtensionTypes.def" #define WASM_TYPE(Name, Id, SingletonId) llvm::DIType *SingletonId = nullptr; #include "clang/Basic/WebAssemblyReferenceTypes.def" -#define AMDGPU_TYPE(Name, Id, SingletonId) llvm::DIType *SingletonId = nullptr; +#define AMDGPU_TYPE(Name, Id, SingletonId, Width, Align) \ + llvm::DIType *SingletonId = nullptr; #include "clang/Basic/AMDGPUTypes.def" #define HLSL_INTANGIBLE_TYPE(Name, Id, SingletonId) \ llvm::DIType *SingletonId = nullptr; diff --git a/clang/lib/CodeGen/CGDeclCXX.cpp b/clang/lib/CodeGen/CGDeclCXX.cpp index c44f38ef02a3f..8dcb5f6100619 100644 --- a/clang/lib/CodeGen/CGDeclCXX.cpp +++ b/clang/lib/CodeGen/CGDeclCXX.cpp @@ -640,13 +640,13 @@ CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D, addUsedGlobal(COMDATKey); } - // If comdats are in use and supported, place the initializer function into - // the comdat group of the global. In the MS ABI, initializers are mangled - // and have their own comdat, so we don't include them in the group for - // consistency with MSVC. + // If we used a COMDAT key for the global ctor, the init function can be + // discarded if the global ctor entry is discarded. + // FIXME: Do we need to restrict this to ELF and Wasm? llvm::Comdat *C = Addr->getComdat(); - if (COMDATKey && C && getTriple().supportsCOMDAT() && - !getTarget().getCXXABI().isMicrosoft()) { + if (COMDATKey && C && + (getTarget().getTriple().isOSBinFormatELF() || + getTarget().getTriple().isOSBinFormatWasm())) { Fn->setComdat(C); } } else { diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp index 59d8fc830dcc8..3237d93ca31ce 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.cpp +++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp @@ -415,7 +415,7 @@ void CGHLSLRuntime::emitEntryFunction(const FunctionDecl *FD, } CallInst *CI = B.CreateCall(FunctionCallee(Fn), Args); - (void)CI; + CI->setCallingConv(Fn->getCallingConv()); // FIXME: Handle codegen for return type semantics. // See: https://github.com/llvm/llvm-project/issues/57875 B.CreateRetVoid(); diff --git a/clang/lib/CodeGen/CodeGenTypes.cpp b/clang/lib/CodeGen/CodeGenTypes.cpp index 77c1b27cebf40..0b486a644f57b 100644 --- a/clang/lib/CodeGen/CodeGenTypes.cpp +++ b/clang/lib/CodeGen/CodeGenTypes.cpp @@ -558,7 +558,7 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) { llvm_unreachable("Unexpected wasm reference builtin type!"); \ } break; #include "clang/Basic/WebAssemblyReferenceTypes.def" -#define AMDGPU_OPAQUE_PTR_TYPE(Name, AS, Width, Align, Id, SingletonId) \ +#define AMDGPU_OPAQUE_PTR_TYPE(Name, Id, SingletonId, Width, Align, AS) \ case BuiltinType::Id: \ return llvm::PointerType::get(getLLVMContext(), AS); #include "clang/Basic/AMDGPUTypes.def" diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp index dcc35d5689831..965e09a7a760e 100644 --- a/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -3639,7 +3639,7 @@ static bool TypeInfoIsInStandardLibrary(const BuiltinType *Ty) { #include "clang/Basic/RISCVVTypes.def" #define WASM_TYPE(Name, Id, SingletonId) case BuiltinType::Id: #include "clang/Basic/WebAssemblyReferenceTypes.def" -#define AMDGPU_TYPE(Name, Id, SingletonId) case BuiltinType::Id: +#define AMDGPU_TYPE(Name, Id, SingletonId, Width, Align) case BuiltinType::Id: #include "clang/Basic/AMDGPUTypes.def" #define HLSL_INTANGIBLE_TYPE(Name, Id, SingletonId) case BuiltinType::Id: #include "clang/Basic/HLSLIntangibleTypes.def" diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index d0c8bdba0ede9..fba6a8853c396 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -6481,6 +6481,7 @@ const ToolChain &Driver::getToolChain(const ArgList &Args, case llvm::Triple::ZOS: TC = std::make_unique(*this, Target, Args); break; + case llvm::Triple::Vulkan: case llvm::Triple::ShaderModel: TC = std::make_unique(*this, Target, Args); break; diff --git a/clang/lib/Headers/CMakeLists.txt b/clang/lib/Headers/CMakeLists.txt index f5cc07c303f9e..ff392e7122a44 100644 --- a/clang/lib/Headers/CMakeLists.txt +++ b/clang/lib/Headers/CMakeLists.txt @@ -120,6 +120,7 @@ set(ppc_htm_files set(riscv_files riscv_bitmanip.h + riscv_corev_alu.h riscv_crypto.h riscv_ntlh.h sifive_vector.h diff --git a/clang/lib/Headers/bmi2intrin.h b/clang/lib/Headers/bmi2intrin.h index f0a3343bef915..7b2c2f145b14a 100644 --- a/clang/lib/Headers/bmi2intrin.h +++ b/clang/lib/Headers/bmi2intrin.h @@ -17,6 +17,12 @@ /* Define the default attributes for the functions in this file. */ #define __DEFAULT_FN_ATTRS __attribute__((__always_inline__, __nodebug__, __target__("bmi2"))) +#if defined(__cplusplus) && (__cplusplus >= 201103L) +#define __DEFAULT_FN_ATTRS_CONSTEXPR __DEFAULT_FN_ATTRS constexpr +#else +#define __DEFAULT_FN_ATTRS_CONSTEXPR __DEFAULT_FN_ATTRS +#endif + /// Copies the unsigned 32-bit integer \a __X and zeroes the upper bits /// starting at bit number \a __Y. /// @@ -37,7 +43,7 @@ /// \param __Y /// The lower 8 bits specify the bit number of the lowest bit to zero. /// \returns The partially zeroed 32-bit value. -static __inline__ unsigned int __DEFAULT_FN_ATTRS +static __inline__ unsigned int __DEFAULT_FN_ATTRS_CONSTEXPR _bzhi_u32(unsigned int __X, unsigned int __Y) { return __builtin_ia32_bzhi_si(__X, __Y); @@ -67,7 +73,7 @@ _bzhi_u32(unsigned int __X, unsigned int __Y) /// \param __Y /// The 32-bit mask specifying where to deposit source bits. /// \returns The 32-bit result. -static __inline__ unsigned int __DEFAULT_FN_ATTRS +static __inline__ unsigned int __DEFAULT_FN_ATTRS_CONSTEXPR _pdep_u32(unsigned int __X, unsigned int __Y) { return __builtin_ia32_pdep_si(__X, __Y); @@ -97,7 +103,7 @@ _pdep_u32(unsigned int __X, unsigned int __Y) /// \param __Y /// The 32-bit mask specifying which source bits to extract. /// \returns The 32-bit result. -static __inline__ unsigned int __DEFAULT_FN_ATTRS +static __inline__ unsigned int __DEFAULT_FN_ATTRS_CONSTEXPR _pext_u32(unsigned int __X, unsigned int __Y) { return __builtin_ia32_pext_si(__X, __Y); @@ -153,7 +159,7 @@ _mulx_u32(unsigned int __X, unsigned int __Y, unsigned int *__P) /// \param __Y /// The lower 8 bits specify the bit number of the lowest bit to zero. /// \returns The partially zeroed 64-bit value. -static __inline__ unsigned long long __DEFAULT_FN_ATTRS +static __inline__ unsigned long long __DEFAULT_FN_ATTRS_CONSTEXPR _bzhi_u64(unsigned long long __X, unsigned long long __Y) { return __builtin_ia32_bzhi_di(__X, __Y); @@ -183,7 +189,7 @@ _bzhi_u64(unsigned long long __X, unsigned long long __Y) /// \param __Y /// The 64-bit mask specifying where to deposit source bits. /// \returns The 64-bit result. -static __inline__ unsigned long long __DEFAULT_FN_ATTRS +static __inline__ unsigned long long __DEFAULT_FN_ATTRS_CONSTEXPR _pdep_u64(unsigned long long __X, unsigned long long __Y) { return __builtin_ia32_pdep_di(__X, __Y); @@ -213,7 +219,7 @@ _pdep_u64(unsigned long long __X, unsigned long long __Y) /// \param __Y /// The 64-bit mask specifying which source bits to extract. /// \returns The 64-bit result. -static __inline__ unsigned long long __DEFAULT_FN_ATTRS +static __inline__ unsigned long long __DEFAULT_FN_ATTRS_CONSTEXPR _pext_u64(unsigned long long __X, unsigned long long __Y) { return __builtin_ia32_pext_di(__X, __Y); @@ -251,5 +257,6 @@ _mulx_u64 (unsigned long long __X, unsigned long long __Y, #endif /* __x86_64__ */ #undef __DEFAULT_FN_ATTRS +#undef __DEFAULT_FN_ATTRS_CONSTEXPR #endif /* __BMI2INTRIN_H */ diff --git a/clang/lib/Headers/bmiintrin.h b/clang/lib/Headers/bmiintrin.h index 72c84d12c0e52..673f043ccfb30 100644 --- a/clang/lib/Headers/bmiintrin.h +++ b/clang/lib/Headers/bmiintrin.h @@ -17,7 +17,12 @@ /* Allow using the tzcnt intrinsics even for non-BMI targets. Since the TZCNT instruction behaves as BSF on non-BMI targets, there is code that expects to use it as a potentially faster version of BSF. */ +#if defined(__cplusplus) && (__cplusplus >= 201103L) +#define __RELAXED_FN_ATTRS \ + __attribute__((__always_inline__, __nodebug__)) constexpr +#else #define __RELAXED_FN_ATTRS __attribute__((__always_inline__, __nodebug__)) +#endif /// Counts the number of trailing zero bits in the operand. /// @@ -164,12 +169,12 @@ _mm_tzcnt_64(unsigned long long __X) #if !defined(__SCE__) || __has_feature(modules) || defined(__BMI__) /* Define the default attributes for the functions in this file. */ -#define __DEFAULT_FN_ATTRS __attribute__((__always_inline__, __nodebug__, __target__("bmi"))) - #if defined(__cplusplus) && (__cplusplus >= 201103L) -#define __DEFAULT_FN_ATTRS_CONSTEXPR __DEFAULT_FN_ATTRS constexpr +#define __DEFAULT_FN_ATTRS \ + __attribute__((__always_inline__, __nodebug__, __target__("bmi"))) constexpr #else -#define __DEFAULT_FN_ATTRS_CONSTEXPR __DEFAULT_FN_ATTRS +#define __DEFAULT_FN_ATTRS \ + __attribute__((__always_inline__, __nodebug__, __target__("bmi"))) #endif /// Performs a bitwise AND of the second operand with the one's @@ -229,7 +234,7 @@ __andn_u32(unsigned int __X, unsigned int __Y) /// \returns An unsigned integer whose least significant bits contain the /// extracted bits. /// \see _bextr_u32 -static __inline__ unsigned int __DEFAULT_FN_ATTRS_CONSTEXPR +static __inline__ unsigned int __DEFAULT_FN_ATTRS __bextr_u32(unsigned int __X, unsigned int __Y) { return __builtin_ia32_bextr_u32(__X, __Y); } @@ -253,7 +258,7 @@ __bextr_u32(unsigned int __X, unsigned int __Y) { /// \returns An unsigned integer whose least significant bits contain the /// extracted bits. /// \see __bextr_u32 -static __inline__ unsigned int __DEFAULT_FN_ATTRS_CONSTEXPR +static __inline__ unsigned int __DEFAULT_FN_ATTRS _bextr_u32(unsigned int __X, unsigned int __Y, unsigned int __Z) { return __builtin_ia32_bextr_u32(__X, ((__Y & 0xff) | ((__Z & 0xff) << 8))); } @@ -275,7 +280,7 @@ _bextr_u32(unsigned int __X, unsigned int __Y, unsigned int __Z) { /// \returns An unsigned integer whose least significant bits contain the /// extracted bits. /// \see __bextr_u32 -static __inline__ unsigned int __DEFAULT_FN_ATTRS_CONSTEXPR +static __inline__ unsigned int __DEFAULT_FN_ATTRS _bextr2_u32(unsigned int __X, unsigned int __Y) { return __builtin_ia32_bextr_u32(__X, __Y); } @@ -448,7 +453,7 @@ __andn_u64 (unsigned long long __X, unsigned long long __Y) /// \returns An unsigned 64-bit integer whose least significant bits contain the /// extracted bits. /// \see _bextr_u64 -static __inline__ unsigned long long __DEFAULT_FN_ATTRS_CONSTEXPR +static __inline__ unsigned long long __DEFAULT_FN_ATTRS __bextr_u64(unsigned long long __X, unsigned long long __Y) { return __builtin_ia32_bextr_u64(__X, __Y); } @@ -472,7 +477,7 @@ __bextr_u64(unsigned long long __X, unsigned long long __Y) { /// \returns An unsigned 64-bit integer whose least significant bits contain the /// extracted bits. /// \see __bextr_u64 -static __inline__ unsigned long long __DEFAULT_FN_ATTRS_CONSTEXPR +static __inline__ unsigned long long __DEFAULT_FN_ATTRS _bextr_u64(unsigned long long __X, unsigned int __Y, unsigned int __Z) { return __builtin_ia32_bextr_u64(__X, ((__Y & 0xff) | ((__Z & 0xff) << 8))); } @@ -494,7 +499,7 @@ _bextr_u64(unsigned long long __X, unsigned int __Y, unsigned int __Z) { /// \returns An unsigned 64-bit integer whose least significant bits contain the /// extracted bits. /// \see __bextr_u64 -static __inline__ unsigned long long __DEFAULT_FN_ATTRS_CONSTEXPR +static __inline__ unsigned long long __DEFAULT_FN_ATTRS _bextr2_u64(unsigned long long __X, unsigned long long __Y) { return __builtin_ia32_bextr_u64(__X, __Y); } diff --git a/clang/lib/Headers/lzcntintrin.h b/clang/lib/Headers/lzcntintrin.h index f4ddce9d0e683..db00474ffd394 100644 --- a/clang/lib/Headers/lzcntintrin.h +++ b/clang/lib/Headers/lzcntintrin.h @@ -15,7 +15,13 @@ #define __LZCNTINTRIN_H /* Define the default attributes for the functions in this file. */ -#define __DEFAULT_FN_ATTRS __attribute__((__always_inline__, __nodebug__, __target__("lzcnt"))) +#if defined(__cplusplus) && (__cplusplus >= 201103L) +#define __DEFAULT_FN_ATTRS \ + __attribute__((__always_inline__, __nodebug__, __target__("lzcnt"))) constexpr +#else +#define __DEFAULT_FN_ATTRS \ + __attribute__((__always_inline__, __nodebug__, __target__("lzcnt"))) +#endif #ifndef _MSC_VER /// Counts the number of leading zero bits in the operand. diff --git a/clang/lib/Headers/riscv_corev_alu.h b/clang/lib/Headers/riscv_corev_alu.h new file mode 100644 index 0000000000000..d2832ddf72efe --- /dev/null +++ b/clang/lib/Headers/riscv_corev_alu.h @@ -0,0 +1,128 @@ +/*===---- riscv_corev_alu.h - CORE-V ALU intrinsics ------------------------=== + * + * 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 __RISCV_COREV_ALU_H +#define __RISCV_COREV_ALU_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +#if defined(__riscv_xcvalu) + +#define __DEFAULT_FN_ATTRS __attribute__((__always_inline__, __nodebug__)) + +static __inline__ long __DEFAULT_FN_ATTRS __riscv_cv_abs(long a) { + return __builtin_abs(a); +} + +static __inline__ long __DEFAULT_FN_ATTRS __riscv_cv_alu_slet(long a, long b) { + return __builtin_riscv_cv_alu_slet(a, b); +} + +static __inline__ long __DEFAULT_FN_ATTRS +__riscv_cv_alu_sletu(unsigned long a, unsigned long b) { + return __builtin_riscv_cv_alu_sletu(a, b); +} + +static __inline__ long __DEFAULT_FN_ATTRS __riscv_cv_alu_min(long a, long b) { + return __builtin_elementwise_min(a, b); +} + +static __inline__ unsigned long __DEFAULT_FN_ATTRS +__riscv_cv_alu_minu(unsigned long a, unsigned long b) { + return __builtin_elementwise_min(a, b); +} + +static __inline__ long __DEFAULT_FN_ATTRS __riscv_cv_alu_max(long a, long b) { + return __builtin_elementwise_max(a, b); +} + +static __inline__ unsigned long __DEFAULT_FN_ATTRS +__riscv_cv_alu_maxu(unsigned long a, unsigned long b) { + return __builtin_elementwise_max(a, b); +} + +static __inline__ long __DEFAULT_FN_ATTRS __riscv_cv_alu_exths(int16_t a) { + return __builtin_riscv_cv_alu_exths(a); +} + +static __inline__ unsigned long __DEFAULT_FN_ATTRS +__riscv_cv_alu_exthz(uint16_t a) { + return __builtin_riscv_cv_alu_exthz(a); +} + +static __inline__ long __DEFAULT_FN_ATTRS __riscv_cv_alu_extbs(int8_t a) { + return __builtin_riscv_cv_alu_extbs(a); +} + +static __inline__ unsigned long __DEFAULT_FN_ATTRS +__riscv_cv_alu_extbz(uint8_t a) { + return __builtin_riscv_cv_alu_extbz(a); +} + +static __inline__ long __DEFAULT_FN_ATTRS __riscv_cv_alu_clip(long a, + unsigned long b) { + return __builtin_riscv_cv_alu_clip(a, b); +} + +static __inline__ unsigned long __DEFAULT_FN_ATTRS +__riscv_cv_alu_clipu(unsigned long a, unsigned long b) { + return __builtin_riscv_cv_alu_clipu(a, b); +} + +static __inline__ long __DEFAULT_FN_ATTRS __riscv_cv_alu_addN(long a, long b, + uint8_t shft) { + return __builtin_riscv_cv_alu_addN(a, b, shft); +} + +static __inline__ unsigned long __DEFAULT_FN_ATTRS +__riscv_cv_alu_adduN(unsigned long a, unsigned long b, uint8_t shft) { + return __builtin_riscv_cv_alu_adduN(a, b, shft); +} + +static __inline__ long __DEFAULT_FN_ATTRS __riscv_cv_alu_addRN(long a, long b, + uint8_t shft) { + return __builtin_riscv_cv_alu_addRN(a, b, shft); +} + +static __inline__ unsigned long __DEFAULT_FN_ATTRS +__riscv_cv_alu_adduRN(unsigned long a, unsigned long b, uint8_t shft) { + return __builtin_riscv_cv_alu_adduRN(a, b, shft); +} + +static __inline__ long __DEFAULT_FN_ATTRS __riscv_cv_alu_subN(long a, long b, + uint8_t shft) { + return __builtin_riscv_cv_alu_subN(a, b, shft); +} + +static __inline__ unsigned long __DEFAULT_FN_ATTRS +__riscv_cv_alu_subuN(unsigned long a, unsigned long b, uint8_t shft) { + return __builtin_riscv_cv_alu_subuN(a, b, shft); +} + +static __inline__ long __DEFAULT_FN_ATTRS __riscv_cv_alu_subRN(long a, long b, + uint8_t shft) { + return __builtin_riscv_cv_alu_subRN(a, b, shft); +} + +static __inline__ unsigned long __DEFAULT_FN_ATTRS +__riscv_cv_alu_subuRN(unsigned long a, unsigned long b, uint8_t shft) { + return __builtin_riscv_cv_alu_subuRN(a, b, shft); +} + +#endif // defined(__riscv_xcvalu) + +#if defined(__cplusplus) +} +#endif + +#endif // define __RISCV_COREV_ALU_H diff --git a/clang/lib/Headers/tbmintrin.h b/clang/lib/Headers/tbmintrin.h index f4e848a1c0019..48a9d07568ff2 100644 --- a/clang/lib/Headers/tbmintrin.h +++ b/clang/lib/Headers/tbmintrin.h @@ -15,7 +15,13 @@ #define __TBMINTRIN_H /* Define the default attributes for the functions in this file. */ -#define __DEFAULT_FN_ATTRS __attribute__((__always_inline__, __nodebug__, __target__("tbm"))) +#if defined(__cplusplus) && (__cplusplus >= 201103L) +#define __DEFAULT_FN_ATTRS \ + __attribute__((__always_inline__, __nodebug__, __target__("tbm"))) constexpr +#else +#define __DEFAULT_FN_ATTRS \ + __attribute__((__always_inline__, __nodebug__, __target__("tbm"))) +#endif #define __bextri_u32(a, b) \ ((unsigned int)__builtin_ia32_bextri_u32((unsigned int)(a), \ diff --git a/clang/lib/Index/USRGeneration.cpp b/clang/lib/Index/USRGeneration.cpp index f00bc56429f1a..35d0aefaf69a6 100644 --- a/clang/lib/Index/USRGeneration.cpp +++ b/clang/lib/Index/USRGeneration.cpp @@ -780,7 +780,7 @@ void USRGenerator::VisitType(QualType T) { #include "clang/Basic/RISCVVTypes.def" #define WASM_TYPE(Name, Id, SingletonId) case BuiltinType::Id: #include "clang/Basic/WebAssemblyReferenceTypes.def" -#define AMDGPU_TYPE(Name, Id, SingletonId) \ +#define AMDGPU_TYPE(Name, Id, SingletonId, Width, Align) \ case BuiltinType::Id: \ Out << "@BT@" << #Name; \ break; diff --git a/clang/lib/Parse/ParseOpenACC.cpp b/clang/lib/Parse/ParseOpenACC.cpp index 0261e8ea3c9b7..e66abd6873794 100644 --- a/clang/lib/Parse/ParseOpenACC.cpp +++ b/clang/lib/Parse/ParseOpenACC.cpp @@ -976,14 +976,25 @@ Parser::OpenACCClauseParseResult Parser::ParseOpenACCClauseParams( /*IsReadOnly=*/false, /*IsZero=*/false); break; case OpenACCClauseKind::Collapse: { - tryParseAndConsumeSpecialTokenKind(*this, OpenACCSpecialTokenKind::Force, - ClauseKind); - ExprResult NumLoops = + bool HasForce = tryParseAndConsumeSpecialTokenKind( + *this, OpenACCSpecialTokenKind::Force, ClauseKind); + ExprResult LoopCount = getActions().CorrectDelayedTyposInExpr(ParseConstantExpression()); - if (NumLoops.isInvalid()) { + if (LoopCount.isInvalid()) { Parens.skipToEnd(); return OpenACCCanContinue(); } + + LoopCount = getActions().OpenACC().ActOnIntExpr( + OpenACCDirectiveKind::Invalid, ClauseKind, + LoopCount.get()->getBeginLoc(), LoopCount.get()); + + if (LoopCount.isInvalid()) { + Parens.skipToEnd(); + return OpenACCCanContinue(); + } + + ParsedClause.setCollapseDetails(HasForce, LoopCount.get()); break; } case OpenACCClauseKind::Bind: { diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp index 6496a33b8f5a5..fb4f97096fb96 100644 --- a/clang/lib/Sema/AnalysisBasedWarnings.cpp +++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -2073,6 +2073,13 @@ class ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler { Warnings.emplace_back(std::move(Warning), getNotes()); } + void handleAttributeMismatch(const FunctionDecl *FD1, + const FunctionDecl *FD2) override { + PartialDiagnosticAt Warning(FD2->getLocation(), + S.PDiag(diag::warn_attribute_mismatch) << FD1); + Warnings.emplace_back(std::move(Warning), getNotes()); + } + void enterFunction(const FunctionDecl* FD) override { CurrentFunction = FD; } diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 03dd39bf03a20..4be7dfbc29392 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -509,7 +509,7 @@ void Sema::Initialize() { if (Context.getTargetInfo().getTriple().isAMDGPU() || (Context.getAuxTargetInfo() && Context.getAuxTargetInfo()->getTriple().isAMDGPU())) { -#define AMDGPU_TYPE(Name, Id, SingletonId) \ +#define AMDGPU_TYPE(Name, Id, SingletonId, Width, Align) \ addImplicitTypedef(Name, Context.SingletonId); #include "clang/Basic/AMDGPUTypes.def" } diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp index 6a1b32598bb4a..67fc603e9ce1d 100644 --- a/clang/lib/Sema/SemaConcept.cpp +++ b/clang/lib/Sema/SemaConcept.cpp @@ -975,11 +975,14 @@ static const Expr *SubstituteConstraintExpressionWithoutSatisfaction( // parameters that the surrounding function hasn't been instantiated yet. Note // this may happen while we're comparing two templates' constraint // equivalence. - LocalInstantiationScope ScopeForParameters(S); - if (auto *FD = DeclInfo.getDecl()->getAsFunction()) + std::optional ScopeForParameters; + if (const NamedDecl *ND = DeclInfo.getDecl(); + ND && ND->isFunctionOrFunctionTemplate()) { + ScopeForParameters.emplace(S); + const FunctionDecl *FD = ND->getAsFunction(); for (auto *PVD : FD->parameters()) { if (!PVD->isParameterPack()) { - ScopeForParameters.InstantiatedLocal(PVD, PVD); + ScopeForParameters->InstantiatedLocal(PVD, PVD); continue; } // This is hacky: we're mapping the parameter pack to a size-of-1 argument @@ -998,9 +1001,10 @@ static const Expr *SubstituteConstraintExpressionWithoutSatisfaction( // that we can eliminate the Scope in the cases where the declarations are // not necessarily instantiated. It would also benefit the noexcept // specifier comparison. - ScopeForParameters.MakeInstantiatedLocalArgPack(PVD); - ScopeForParameters.InstantiatedLocalPackArg(PVD, PVD); + ScopeForParameters->MakeInstantiatedLocalArgPack(PVD); + ScopeForParameters->InstantiatedLocalPackArg(PVD, PVD); } + } std::optional ThisScope; diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 1bf0e800a3622..0e536f71a2f70 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -9293,15 +9293,12 @@ static FunctionDecl *CreateNewFunctionDecl(Sema &SemaRef, Declarator &D, TrailingRequiresClause); } else if (Name.getNameKind() == DeclarationName::CXXDeductionGuideName) { - if (TrailingRequiresClause) - SemaRef.Diag(TrailingRequiresClause->getBeginLoc(), - diag::err_trailing_requires_clause_on_deduction_guide) - << TrailingRequiresClause->getSourceRange(); if (SemaRef.CheckDeductionGuideDeclarator(D, R, SC)) return nullptr; - return CXXDeductionGuideDecl::Create(SemaRef.Context, DC, D.getBeginLoc(), - ExplicitSpecifier, NameInfo, R, TInfo, - D.getEndLoc()); + return CXXDeductionGuideDecl::Create( + SemaRef.Context, DC, D.getBeginLoc(), ExplicitSpecifier, NameInfo, R, + TInfo, D.getEndLoc(), /*Ctor=*/nullptr, + /*Kind=*/DeductionCandidate::Normal, TrailingRequiresClause); } else if (DC->isRecord()) { // If the name of the function is the same as the name of the record, // then this must be an invalid constructor that has a return type. diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index e072fb65b8132..2db9d1fc69ed1 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -6127,7 +6127,7 @@ static bool isPlaceholderToRemoveAsArg(QualType type) { #include "clang/Basic/RISCVVTypes.def" #define WASM_TYPE(Name, Id, SingletonId) case BuiltinType::Id: #include "clang/Basic/WebAssemblyReferenceTypes.def" -#define AMDGPU_TYPE(Name, Id, SingletonId) case BuiltinType::Id: +#define AMDGPU_TYPE(Name, Id, SingletonId, Width, Align) case BuiltinType::Id: #include "clang/Basic/AMDGPUTypes.def" #define HLSL_INTANGIBLE_TYPE(Name, Id, SingletonId) case BuiltinType::Id: #include "clang/Basic/HLSLIntangibleTypes.def" @@ -20999,7 +20999,7 @@ ExprResult Sema::CheckPlaceholderExpr(Expr *E) { #include "clang/Basic/RISCVVTypes.def" #define WASM_TYPE(Name, Id, SingletonId) case BuiltinType::Id: #include "clang/Basic/WebAssemblyReferenceTypes.def" -#define AMDGPU_TYPE(Name, Id, SingletonId) case BuiltinType::Id: +#define AMDGPU_TYPE(Name, Id, SingletonId, Width, Align) case BuiltinType::Id: #include "clang/Basic/AMDGPUTypes.def" #define HLSL_INTANGIBLE_TYPE(Name, Id, SingletonId) case BuiltinType::Id: #include "clang/Basic/HLSLIntangibleTypes.def" diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index ac3fe6ab8f9bd..b30414a8a8277 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -9509,6 +9509,18 @@ Sema::ActOnStartRequiresExpr(SourceLocation RequiresKWLoc, PushDeclContext(BodyScope, Body); for (ParmVarDecl *Param : LocalParameters) { + if (Param->getType()->isVoidType()) { + if (LocalParameters.size() > 1) { + Diag(Param->getBeginLoc(), diag::err_void_only_param); + Param->setType(Context.IntTy); + } else if (Param->getIdentifier()) { + Diag(Param->getBeginLoc(), diag::err_param_with_void_type); + Param->setType(Context.IntTy); + } else if (Param->getType().hasQualifiers()) { + Diag(Param->getBeginLoc(), diag::err_void_param_qualified); + } + } + if (Param->hasDefaultArg()) // C++2a [expr.prim.req] p4 // [...] A local parameter of a requires-expression shall not have a diff --git a/clang/lib/Sema/SemaOpenACC.cpp b/clang/lib/Sema/SemaOpenACC.cpp index ecbcc19413dc6..89142b837e60a 100644 --- a/clang/lib/Sema/SemaOpenACC.cpp +++ b/clang/lib/Sema/SemaOpenACC.cpp @@ -343,6 +343,18 @@ bool doesClauseApplyToDirective(OpenACCDirectiveKind DirectiveKind, return false; } + case OpenACCClauseKind::Collapse: { + switch (DirectiveKind) { + case OpenACCDirectiveKind::Loop: + case OpenACCDirectiveKind::ParallelLoop: + case OpenACCDirectiveKind::SerialLoop: + case OpenACCDirectiveKind::KernelsLoop: + return true; + default: + return false; + } + } + default: // Do nothing so we can go to the 'unimplemented' diagnostic instead. return true; @@ -1037,6 +1049,26 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitReductionClause( ValidVars, Clause.getEndLoc()); } +OpenACCClause *SemaOpenACCClauseVisitor::VisitCollapseClause( + SemaOpenACC::OpenACCParsedClause &Clause) { + // Duplicates here are not really sensible. We could possible permit + // multiples if they all had the same value, but there isn't really a good + // reason to do so. Also, this simplifies the suppression of duplicates, in + // that we know if we 'find' one after instantiation, that it is the same + // clause, which simplifies instantiation/checking/etc. + if (checkAlreadyHasClauseOfKind(SemaRef, ExistingClauses, Clause)) + return nullptr; + + ExprResult LoopCount = SemaRef.CheckCollapseLoopCount(Clause.getLoopCount()); + + if (!LoopCount.isUsable()) + return nullptr; + + return OpenACCCollapseClause::Create(Ctx, Clause.getBeginLoc(), + Clause.getLParenLoc(), Clause.isForce(), + LoopCount.get(), Clause.getEndLoc()); +} + } // namespace SemaOpenACC::SemaOpenACC(Sema &S) : SemaBase(S) {} @@ -1273,6 +1305,9 @@ ExprResult SemaOpenACC::ActOnIntExpr(OpenACCDirectiveKind DK, } } IntExprDiagnoser(DK, CK, IntExpr); + if (!IntExpr) + return ExprError(); + ExprResult IntExprResult = SemaRef.PerformContextualImplicitConversion( Loc, IntExpr, IntExprDiagnoser); if (IntExprResult.isInvalid()) @@ -1583,6 +1618,34 @@ ExprResult SemaOpenACC::ActOnArraySectionExpr(Expr *Base, SourceLocation LBLoc, OK_Ordinary, ColonLoc, RBLoc); } +ExprResult SemaOpenACC::CheckCollapseLoopCount(Expr *LoopCount) { + if (!LoopCount) + return ExprError(); + + assert((LoopCount->isInstantiationDependent() || + LoopCount->getType()->isIntegerType()) && + "Loop argument non integer?"); + + // If this is dependent, there really isn't anything we can check. + if (LoopCount->isInstantiationDependent()) + return ExprResult{LoopCount}; + + std::optional ICE = + LoopCount->getIntegerConstantExpr(getASTContext()); + + // OpenACC 3.3: 2.9.1 + // The argument to the collapse clause must be a constant positive integer + // expression. + if (!ICE || *ICE <= 0) { + Diag(LoopCount->getBeginLoc(), diag::err_acc_collapse_loop_count) + << ICE.has_value() << ICE.value_or(llvm::APSInt{}).getExtValue(); + return ExprError(); + } + + return ExprResult{ + ConstantExpr::Create(getASTContext(), LoopCount, APValue{*ICE})}; +} + bool SemaOpenACC::ActOnStartStmtDirective(OpenACCDirectiveKind K, SourceLocation StartLoc) { SemaRef.DiscardCleanupsInEvaluationContext(); diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index 9afb8cea26fe7..8615da4b044a8 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -9195,7 +9195,7 @@ static bool checkOpenMPIterationSpace( SemaRef.Diag(CollapseLoopCountExpr->getExprLoc(), diag::note_omp_collapse_ordered_expr) << 0 << CollapseLoopCountExpr->getSourceRange(); - else + else if (OrderedLoopCountExpr) SemaRef.Diag(OrderedLoopCountExpr->getExprLoc(), diag::note_omp_collapse_ordered_expr) << 1 << OrderedLoopCountExpr->getSourceRange(); diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 99423b01114cc..c7d48b81bc034 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -1134,7 +1134,8 @@ bool Sema::BuildTypeConstraint(const CXXScopeSpec &SS, SS.isSet() ? SS.getWithLocInContext(Context) : NestedNameSpecifierLoc(), ConceptName, CD, /*FoundDecl=*/USD ? cast(USD) : CD, TypeConstr->LAngleLoc.isValid() ? &TemplateArgs : nullptr, - ConstrainedParameter, EllipsisLoc); + ConstrainedParameter, Context.getTypeDeclType(ConstrainedParameter), + EllipsisLoc); } template @@ -1191,6 +1192,7 @@ bool Sema::AttachTypeConstraint(NestedNameSpecifierLoc NS, ConceptDecl *NamedConcept, NamedDecl *FoundDecl, const TemplateArgumentListInfo *TemplateArgs, TemplateTypeParmDecl *ConstrainedParameter, + QualType ConstrainedType, SourceLocation EllipsisLoc) { // C++2a [temp.param]p4: // [...] If Q is of the form C, then let E' be @@ -1199,7 +1201,7 @@ bool Sema::AttachTypeConstraint(NestedNameSpecifierLoc NS, TemplateArgs ? ASTTemplateArgumentListInfo::Create(Context, *TemplateArgs) : nullptr; - QualType ParamAsArgument(ConstrainedParameter->getTypeForDecl(), 0); + QualType ParamAsArgument = ConstrainedType; ExprResult ImmediatelyDeclaredConstraint = formImmediatelyDeclaredConstraint( *this, NS, NameInfo, NamedConcept, FoundDecl, diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index fd51fa4afcacb..b36381422851f 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -371,7 +371,7 @@ Response HandleFunctionTemplateDecl(const FunctionTemplateDecl *FTD, Specialization->getTemplateInstantiationArgs().asArray(); } Result.addOuterTemplateArguments( - const_cast(FTD), Arguments, + TSTy->getTemplateName().getAsTemplateDecl(), Arguments, /*Final=*/false); } } @@ -1655,6 +1655,21 @@ namespace { SubstTemplateTypeParmPackTypeLoc TL, bool SuppressObjCLifetime); + QualType + TransformSubstTemplateTypeParmType(TypeLocBuilder &TLB, + SubstTemplateTypeParmTypeLoc TL) { + if (SemaRef.CodeSynthesisContexts.back().Kind != + Sema::CodeSynthesisContext::ConstraintSubstitution) + return inherited::TransformSubstTemplateTypeParmType(TLB, TL); + + auto PackIndex = TL.getTypePtr()->getPackIndex(); + std::optional SubstIndex; + if (SemaRef.ArgumentPackSubstitutionIndex == -1 && PackIndex) + SubstIndex.emplace(SemaRef, *PackIndex); + + return inherited::TransformSubstTemplateTypeParmType(TLB, TL); + } + CXXRecordDecl::LambdaDependencyKind ComputeLambdaDependency(LambdaScopeInfo *LSI) { if (auto TypeAlias = @@ -1722,6 +1737,33 @@ namespace { return inherited::TransformLambdaBody(E, Body); } + ExprResult RebuildSizeOfPackExpr(SourceLocation OperatorLoc, + NamedDecl *Pack, SourceLocation PackLoc, + SourceLocation RParenLoc, + std::optional Length, + ArrayRef PartialArgs) { + if (SemaRef.CodeSynthesisContexts.back().Kind != + Sema::CodeSynthesisContext::ConstraintNormalization) + return inherited::RebuildSizeOfPackExpr(OperatorLoc, Pack, PackLoc, + RParenLoc, Length, PartialArgs); + +#ifndef NDEBUG + for (auto *Iter = TemplateArgs.begin(); Iter != TemplateArgs.end(); + ++Iter) + for (const TemplateArgument &TA : Iter->Args) + assert(TA.getKind() != TemplateArgument::Pack || TA.pack_size() == 1); +#endif + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex( + SemaRef, /*NewSubstitutionIndex=*/0); + Decl *NewPack = TransformDecl(PackLoc, Pack); + if (!NewPack) + return ExprError(); + + return inherited::RebuildSizeOfPackExpr(OperatorLoc, + cast(NewPack), PackLoc, + RParenLoc, Length, PartialArgs); + } + ExprResult TransformRequiresExpr(RequiresExpr *E) { LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true); ExprResult TransReq = inherited::TransformRequiresExpr(E); @@ -3078,6 +3120,58 @@ namespace { } // namespace +namespace { + +struct ExpandPackedTypeConstraints + : TreeTransform { + + using inherited = TreeTransform; + + ExpandPackedTypeConstraints(Sema &SemaRef) : inherited(SemaRef) {} + + using inherited::TransformTemplateTypeParmType; + + QualType TransformTemplateTypeParmType(TypeLocBuilder &TLB, + TemplateTypeParmTypeLoc TL, bool) { + const TemplateTypeParmType *T = TL.getTypePtr(); + if (!T->isParameterPack()) { + TemplateTypeParmTypeLoc NewTL = + TLB.push(TL.getType()); + NewTL.setNameLoc(TL.getNameLoc()); + return TL.getType(); + } + + assert(SemaRef.ArgumentPackSubstitutionIndex != -1); + + QualType Result = SemaRef.Context.getSubstTemplateTypeParmType( + TL.getType(), T->getDecl(), T->getIndex(), + SemaRef.ArgumentPackSubstitutionIndex); + SubstTemplateTypeParmTypeLoc NewTL = + TLB.push(Result); + NewTL.setNameLoc(TL.getNameLoc()); + return Result; + } + + QualType TransformSubstTemplateTypeParmType(TypeLocBuilder &TLB, + SubstTemplateTypeParmTypeLoc TL) { + const SubstTemplateTypeParmType *T = TL.getTypePtr(); + if (T->getPackIndex()) { + SubstTemplateTypeParmTypeLoc TypeLoc = + TLB.push(TL.getType()); + TypeLoc.setNameLoc(TL.getNameLoc()); + return TypeLoc.getType(); + } + return inherited::TransformSubstTemplateTypeParmType(TLB, TL); + } + + bool SubstTemplateArguments(ArrayRef Args, + TemplateArgumentListInfo &Out) { + return inherited::TransformTemplateArguments(Args.begin(), Args.end(), Out); + } +}; + +} // namespace + bool Sema::SubstTypeConstraint( TemplateTypeParmDecl *Inst, const TypeConstraint *TC, const MultiLevelTemplateArgumentList &TemplateArgs, @@ -3086,9 +3180,62 @@ bool Sema::SubstTypeConstraint( TC->getTemplateArgsAsWritten(); if (!EvaluateConstraints) { - Inst->setTypeConstraint(TC->getConceptReference(), - TC->getImmediatelyDeclaredConstraint()); - return false; + bool ShouldExpandExplicitTemplateArgs = + TemplArgInfo && ArgumentPackSubstitutionIndex != -1 && + llvm::any_of(TemplArgInfo->arguments(), [](auto &Arg) { + return Arg.getArgument().containsUnexpandedParameterPack(); + }); + + // We want to transform the packs into Subst* nodes for type constraints + // inside a pack expansion. For example, + // + // template void foo() { + // bar([](C auto value) {}...); + // } + // + // As we expand Ts in the process of instantiating foo(), and retain + // the original template depths of Ts until the constraint evaluation, we + // would otherwise have no chance to expand Ts by the time of evaluating + // C. + // + // So we form a Subst* node for Ts along with a proper substitution index + // here, and substitute the node with a complete MLTAL later in evaluation. + if (ShouldExpandExplicitTemplateArgs) { + TemplateArgumentListInfo InstArgs; + InstArgs.setLAngleLoc(TemplArgInfo->LAngleLoc); + InstArgs.setRAngleLoc(TemplArgInfo->RAngleLoc); + if (ExpandPackedTypeConstraints(*this).SubstTemplateArguments( + TemplArgInfo->arguments(), InstArgs)) + return true; + + // The type of the original parameter. + auto *ConstraintExpr = TC->getImmediatelyDeclaredConstraint(); + QualType ConstrainedType; + + if (auto *FE = dyn_cast(ConstraintExpr)) { + assert(FE->getLHS()); + ConstraintExpr = FE->getLHS(); + } + auto *CSE = cast(ConstraintExpr); + assert(!CSE->getTemplateArguments().empty() && + "Empty template arguments?"); + ConstrainedType = CSE->getTemplateArguments()[0].getAsType(); + assert(!ConstrainedType.isNull() && + "Failed to extract the original ConstrainedType?"); + + return AttachTypeConstraint( + TC->getNestedNameSpecifierLoc(), TC->getConceptNameInfo(), + TC->getNamedConcept(), + /*FoundDecl=*/TC->getConceptReference()->getFoundDecl(), &InstArgs, + Inst, ConstrainedType, + Inst->isParameterPack() + ? cast(TC->getImmediatelyDeclaredConstraint()) + ->getEllipsisLoc() + : SourceLocation()); + } + Inst->setTypeConstraint(TC->getConceptReference(), + TC->getImmediatelyDeclaredConstraint()); + return false; } TemplateArgumentListInfo InstArgs; @@ -3104,6 +3251,7 @@ bool Sema::SubstTypeConstraint( TC->getNestedNameSpecifierLoc(), TC->getConceptNameInfo(), TC->getNamedConcept(), /*FoundDecl=*/TC->getConceptReference()->getFoundDecl(), &InstArgs, Inst, + Context.getTypeDeclType(Inst), Inst->isParameterPack() ? cast(TC->getImmediatelyDeclaredConstraint()) ->getEllipsisLoc() diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index c3cb9d5d8c2c3..1c35c7d288e32 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -2233,7 +2233,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl( SemaRef.Context, DC, D->getInnerLocStart(), InstantiatedExplicitSpecifier, NameInfo, T, TInfo, D->getSourceRange().getEnd(), DGuide->getCorrespondingConstructor(), - DGuide->getDeductionCandidateKind()); + DGuide->getDeductionCandidateKind(), TrailingRequiresClause); Function->setAccess(D->getAccess()); } else { Function = FunctionDecl::Create( diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index a7beb9d222c3b..c44fc9c4194ca 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -3035,7 +3035,9 @@ InventTemplateParameter(TypeProcessingState &state, QualType T, AutoLoc.getNestedNameSpecifierLoc(), AutoLoc.getConceptNameInfo(), AutoLoc.getNamedConcept(), /*FoundDecl=*/AutoLoc.getFoundDecl(), AutoLoc.hasExplicitTemplateArgs() ? &TAL : nullptr, - InventedTemplateParam, D.getEllipsisLoc()); + InventedTemplateParam, + S.Context.getTypeDeclType(InventedTemplateParam), + D.getEllipsisLoc()); } } else { // The 'auto' appears in the decl-specifiers; we've not finished forming @@ -3072,7 +3074,9 @@ InventTemplateParameter(TypeProcessingState &state, QualType T, /*FoundDecl=*/ USD ? cast(USD) : CD, TemplateId->LAngleLoc.isValid() ? &TemplateArgsInfo : nullptr, - InventedTemplateParam, D.getEllipsisLoc()); + InventedTemplateParam, + S.Context.getTypeDeclType(InventedTemplateParam), + D.getEllipsisLoc()); } } } diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 91cb980ee26b2..6fdb18d51acef 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -11822,6 +11822,31 @@ void OpenACCClauseTransform::VisitReductionClause( ParsedClause.getLParenLoc(), C.getReductionOp(), ValidVars, ParsedClause.getEndLoc()); } + +template +void OpenACCClauseTransform::VisitCollapseClause( + const OpenACCCollapseClause &C) { + Expr *LoopCount = const_cast(C.getLoopCount()); + assert(LoopCount && "collapse clause constructed with invalid loop count"); + + ExprResult NewLoopCount = Self.TransformExpr(LoopCount); + + NewLoopCount = Self.getSema().OpenACC().ActOnIntExpr( + OpenACCDirectiveKind::Invalid, ParsedClause.getClauseKind(), + NewLoopCount.get()->getBeginLoc(), NewLoopCount.get()); + + NewLoopCount = + Self.getSema().OpenACC().CheckCollapseLoopCount(NewLoopCount.get()); + + if (!NewLoopCount.isUsable()) + return; + + ParsedClause.setCollapseDetails(C.hasForce(), NewLoopCount.get()); + NewClause = OpenACCCollapseClause::Create( + Self.getSema().getASTContext(), ParsedClause.getBeginLoc(), + ParsedClause.getLParenLoc(), ParsedClause.isForce(), + ParsedClause.getLoopCount(), ParsedClause.getEndLoc()); +} } // namespace template OpenACCClause *TreeTransform::TransformOpenACCClause( diff --git a/clang/lib/Serialization/ASTCommon.cpp b/clang/lib/Serialization/ASTCommon.cpp index f30642f513ae4..ab4923de6346f 100644 --- a/clang/lib/Serialization/ASTCommon.cpp +++ b/clang/lib/Serialization/ASTCommon.cpp @@ -258,7 +258,7 @@ serialization::TypeIdxFromBuiltin(const BuiltinType *BT) { ID = PREDEF_TYPE_##Id##_ID; \ break; #include "clang/Basic/WebAssemblyReferenceTypes.def" -#define AMDGPU_TYPE(Name, Id, SingletonId) \ +#define AMDGPU_TYPE(Name, Id, SingletonId, Width, Align) \ case BuiltinType::Id: \ ID = PREDEF_TYPE_##Id##_ID; \ break; diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 8623c030b6d59..0a4251c0e5240 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -7488,7 +7488,7 @@ QualType ASTReader::GetType(TypeID ID) { T = Context.SingletonId; \ break; #include "clang/Basic/WebAssemblyReferenceTypes.def" -#define AMDGPU_TYPE(Name, Id, SingletonId) \ +#define AMDGPU_TYPE(Name, Id, SingletonId, Width, Align) \ case PREDEF_TYPE_##Id##_ID: \ T = Context.SingletonId; \ break; @@ -12283,6 +12283,13 @@ OpenACCClause *ASTRecordReader::readOpenACCClause() { return OpenACCIndependentClause::Create(getContext(), BeginLoc, EndLoc); case OpenACCClauseKind::Auto: return OpenACCAutoClause::Create(getContext(), BeginLoc, EndLoc); + case OpenACCClauseKind::Collapse: { + SourceLocation LParenLoc = readSourceLocation(); + bool HasForce = readBool(); + Expr *LoopCount = readSubExpr(); + return OpenACCCollapseClause::Create(getContext(), BeginLoc, LParenLoc, + HasForce, LoopCount, EndLoc); + } case OpenACCClauseKind::Finalize: case OpenACCClauseKind::IfPresent: @@ -12296,7 +12303,6 @@ OpenACCClause *ASTRecordReader::readOpenACCClause() { case OpenACCClauseKind::DeviceResident: case OpenACCClauseKind::Host: case OpenACCClauseKind::Link: - case OpenACCClauseKind::Collapse: case OpenACCClauseKind::Bind: case OpenACCClauseKind::DeviceNum: case OpenACCClauseKind::DefaultAsync: diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index 7a40c5c65d39d..aa9764e25c323 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -8148,6 +8148,13 @@ void ASTRecordWriter::writeOpenACCClause(const OpenACCClause *C) { // Nothing to do here, there is no additional information beyond the // begin/end loc and clause kind. return; + case OpenACCClauseKind::Collapse: { + const auto *CC = cast(C); + writeSourceLocation(CC->getLParenLoc()); + writeBool(CC->hasForce()); + AddStmt(const_cast(CC->getLoopCount())); + return; + } case OpenACCClauseKind::Finalize: case OpenACCClauseKind::IfPresent: @@ -8161,7 +8168,6 @@ void ASTRecordWriter::writeOpenACCClause(const OpenACCClause *C) { case OpenACCClauseKind::DeviceResident: case OpenACCClauseKind::Host: case OpenACCClauseKind::Link: - case OpenACCClauseKind::Collapse: case OpenACCClauseKind::Bind: case OpenACCClauseKind::DeviceNum: case OpenACCClauseKind::DefaultAsync: diff --git a/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp index 5496f087447fb..7c8b44eb05942 100644 --- a/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp @@ -25,9 +25,7 @@ using namespace ento; using namespace taint; namespace { -class DivZeroChecker : public Checker< check::PreStmt > { - const BugType BT{this, "Division by zero"}; - const BugType TaintBT{this, "Division by zero", categories::TaintedData}; +class DivZeroChecker : public Checker> { void reportBug(StringRef Msg, ProgramStateRef StateZero, CheckerContext &C) const; void reportTaintBug(StringRef Msg, ProgramStateRef StateZero, @@ -35,6 +33,12 @@ class DivZeroChecker : public Checker< check::PreStmt > { llvm::ArrayRef TaintedSyms) const; public: + /// This checker class implements several user facing checkers + enum CheckKind { CK_DivideZero, CK_TaintedDivChecker, CK_NumCheckKinds }; + bool ChecksEnabled[CK_NumCheckKinds] = {false}; + CheckerNameRef CheckNames[CK_NumCheckKinds]; + mutable std::unique_ptr BugTypes[CK_NumCheckKinds]; + void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const; }; } // end anonymous namespace @@ -48,8 +52,14 @@ static const Expr *getDenomExpr(const ExplodedNode *N) { void DivZeroChecker::reportBug(StringRef Msg, ProgramStateRef StateZero, CheckerContext &C) const { + if (!ChecksEnabled[CK_DivideZero]) + return; + if (!BugTypes[CK_DivideZero]) + BugTypes[CK_DivideZero].reset( + new BugType(CheckNames[CK_DivideZero], "Division by zero")); if (ExplodedNode *N = C.generateErrorNode(StateZero)) { - auto R = std::make_unique(BT, Msg, N); + auto R = std::make_unique(*BugTypes[CK_DivideZero], + Msg, N); bugreporter::trackExpressionValue(N, getDenomExpr(N), *R); C.emitReport(std::move(R)); } @@ -58,8 +68,15 @@ void DivZeroChecker::reportBug(StringRef Msg, ProgramStateRef StateZero, void DivZeroChecker::reportTaintBug( StringRef Msg, ProgramStateRef StateZero, CheckerContext &C, llvm::ArrayRef TaintedSyms) const { - if (ExplodedNode *N = C.generateErrorNode(StateZero)) { - auto R = std::make_unique(TaintBT, Msg, N); + if (!ChecksEnabled[CK_TaintedDivChecker]) + return; + if (!BugTypes[CK_TaintedDivChecker]) + BugTypes[CK_TaintedDivChecker].reset( + new BugType(CheckNames[CK_TaintedDivChecker], "Division by zero", + categories::TaintedData)); + if (ExplodedNode *N = C.generateNonFatalErrorNode(StateZero)) { + auto R = std::make_unique( + *BugTypes[CK_TaintedDivChecker], Msg, N); bugreporter::trackExpressionValue(N, getDenomExpr(N), *R); for (auto Sym : TaintedSyms) R->markInteresting(Sym); @@ -101,8 +118,8 @@ void DivZeroChecker::checkPreStmt(const BinaryOperator *B, if ((stateNotZero && stateZero)) { std::vector taintedSyms = getTaintedSymbols(C.getState(), *DV); if (!taintedSyms.empty()) { - reportTaintBug("Division by a tainted value, possibly zero", stateZero, C, - taintedSyms); + reportTaintBug("Division by a tainted value, possibly zero", stateNotZero, + C, taintedSyms); return; } } @@ -113,9 +130,27 @@ void DivZeroChecker::checkPreStmt(const BinaryOperator *B, } void ento::registerDivZeroChecker(CheckerManager &mgr) { - mgr.registerChecker(); + DivZeroChecker *checker = mgr.registerChecker(); + checker->ChecksEnabled[DivZeroChecker::CK_DivideZero] = true; + checker->CheckNames[DivZeroChecker::CK_DivideZero] = + mgr.getCurrentCheckerName(); } bool ento::shouldRegisterDivZeroChecker(const CheckerManager &mgr) { return true; } + +void ento::registerTaintedDivChecker(CheckerManager &mgr) { + DivZeroChecker *checker; + if (!mgr.isRegisteredChecker()) + checker = mgr.registerChecker(); + else + checker = mgr.getChecker(); + checker->ChecksEnabled[DivZeroChecker::CK_TaintedDivChecker] = true; + checker->CheckNames[DivZeroChecker::CK_TaintedDivChecker] = + mgr.getCurrentCheckerName(); +} + +bool ento::shouldRegisterTaintedDivChecker(const CheckerManager &mgr) { + return true; +} diff --git a/clang/test/AST/ByteCode/fixed-point.cpp b/clang/test/AST/ByteCode/fixed-point.cpp index 48673d8be6f60..4bf80ba7c58f0 100644 --- a/clang/test/AST/ByteCode/fixed-point.cpp +++ b/clang/test/AST/ByteCode/fixed-point.cpp @@ -11,6 +11,8 @@ static_assert(1.0k != 1.0k); // both-error {{failed due to requirement '1.0k != static_assert(1.0k != 1); // both-error {{failed due to requirement '1.0k != 1'}} static_assert(-12.0k == -(-(-12.0k))); +constexpr _Accum acc = (0.5r, 6.9k); + /// Zero-init. constexpr _Accum A{}; static_assert(A == 0.0k); diff --git a/clang/test/AST/ast-print-openacc-loop-construct.cpp b/clang/test/AST/ast-print-openacc-loop-construct.cpp index cde302a66f3af..ae1f7964f019e 100644 --- a/clang/test/AST/ast-print-openacc-loop-construct.cpp +++ b/clang/test/AST/ast-print-openacc-loop-construct.cpp @@ -57,4 +57,29 @@ void foo() { // CHECK-NEXT: ; #pragma acc loop private(i, array[1], array, array[1:2]) for(;;); + +// CHECK: #pragma acc loop collapse(1) +// CHECK-NEXT: for (;;) +// CHECK-NEXT: ; +#pragma acc loop collapse(1) + for(;;); +// CHECK: #pragma acc loop collapse(force:1) +// CHECK-NEXT: for (;;) +// CHECK-NEXT: ; +#pragma acc loop collapse(force:1) + for(;;); +// CHECK: #pragma acc loop collapse(2) +// CHECK-NEXT: for (;;) +// CHECK-NEXT: for (;;) +// CHECK-NEXT: ; +#pragma acc loop collapse(2) + for(;;) + for(;;); +// CHECK: #pragma acc loop collapse(force:2) +// CHECK-NEXT: for (;;) +// CHECK-NEXT: for (;;) +// CHECK-NEXT: ; +#pragma acc loop collapse(force:2) + for(;;) + for(;;); } diff --git a/clang/test/Analysis/divzero-tainted-div-difference.c b/clang/test/Analysis/divzero-tainted-div-difference.c new file mode 100644 index 0000000000000..28486ccdf7e4f --- /dev/null +++ b/clang/test/Analysis/divzero-tainted-div-difference.c @@ -0,0 +1,34 @@ +// RUN: %clang_analyze_cc1 -Wno-format-security -Wno-pointer-to-int-cast \ +// RUN: -Wno-incompatible-library-redeclaration -verify=normaldiv %s \ +// RUN: -analyzer-checker=optin.taint.GenericTaint \ +// RUN: -analyzer-checker=core + +// RUN: %clang_analyze_cc1 -Wno-format-security -Wno-pointer-to-int-cast \ +// RUN: -Wno-incompatible-library-redeclaration -verify=tainteddiv %s \ +// RUN: -analyzer-checker=optin.taint.GenericTaint \ +// RUN: -analyzer-checker=optin.taint.TaintedDiv + +int getchar(void); + + +//If we are sure that we divide by zero +//we emit a divide by zero warning +int testDivZero(void) { + int x = getchar(); // taint source + if (!x) + return 5 / x; // normaldiv-warning{{Division by zero}} + return 8; +} + +// The attacker provided value might be 0 +int testDivZero2(void) { + int x = getchar(); // taint source + return 5 / x; // tainteddiv-warning{{Division by a tainted value}} +} + +int testDivZero3(void) { + int x = getchar(); // taint source + if (!x) + return 0; + return 5 / x; // no warning +} diff --git a/clang/test/Analysis/taint-diagnostic-visitor.c b/clang/test/Analysis/taint-diagnostic-visitor.c index 526c04c360777..223df9951fd6b 100644 --- a/clang/test/Analysis/taint-diagnostic-visitor.c +++ b/clang/test/Analysis/taint-diagnostic-visitor.c @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -analyze -analyzer-checker=optin.taint,core,alpha.security.ArrayBoundV2,optin.taint.TaintedAlloc -analyzer-output=text -verify %s +// RUN: %clang_cc1 -analyze -analyzer-checker=optin.taint,core,alpha.security.ArrayBoundV2 -analyzer-output=text -verify %s // This file is for testing enhanced diagnostics produced by the GenericTaintChecker diff --git a/clang/test/Analysis/taint-generic.c b/clang/test/Analysis/taint-generic.c index a5cfdd9db1157..ad5a99fe8b3a3 100644 --- a/clang/test/Analysis/taint-generic.c +++ b/clang/test/Analysis/taint-generic.c @@ -1,6 +1,7 @@ // RUN: %clang_analyze_cc1 -Wno-format-security -Wno-pointer-to-int-cast \ // RUN: -Wno-incompatible-library-redeclaration -verify %s \ // RUN: -analyzer-checker=optin.taint.GenericTaint \ +// RUN: -analyzer-checker=optin.taint.TaintedDiv \ // RUN: -analyzer-checker=core \ // RUN: -analyzer-checker=alpha.security.ArrayBoundV2 \ // RUN: -analyzer-checker=debug.ExprInspection \ @@ -11,16 +12,15 @@ // RUN: -Wno-incompatible-library-redeclaration -verify %s \ // RUN: -DFILE_IS_STRUCT \ // RUN: -analyzer-checker=optin.taint.GenericTaint \ +// RUN: -analyzer-checker=optin.taint.TaintedDiv \ // RUN: -analyzer-checker=core \ // RUN: -analyzer-checker=alpha.security.ArrayBoundV2 \ // RUN: -analyzer-checker=debug.ExprInspection \ // RUN: -analyzer-config \ // RUN: optin.taint.TaintPropagation:Config=%S/Inputs/taint-generic-config.yaml -// RUN: not %clang_analyze_cc1 -Wno-pointer-to-int-cast \ -// RUN: -Wno-incompatible-library-redeclaration -verify %s \ +// RUN: not %clang_analyze_cc1 -verify %s \ // RUN: -analyzer-checker=optin.taint.GenericTaint \ -// RUN: -analyzer-checker=debug.ExprInspection \ // RUN: -analyzer-config \ // RUN: optin.taint.TaintPropagation:Config=justguessit \ // RUN: 2>&1 | FileCheck %s -check-prefix=CHECK-INVALID-FILE @@ -30,10 +30,8 @@ // CHECK-INVALID-FILE-SAME: that expects a valid filename instead of // CHECK-INVALID-FILE-SAME: 'justguessit' -// RUN: not %clang_analyze_cc1 -Wno-incompatible-library-redeclaration \ -// RUN: -verify %s \ +// RUN: not %clang_analyze_cc1 -verify %s \ // RUN: -analyzer-checker=optin.taint.GenericTaint \ -// RUN: -analyzer-checker=debug.ExprInspection \ // RUN: -analyzer-config \ // RUN: optin.taint.TaintPropagation:Config=%S/Inputs/taint-generic-config-ill-formed.yaml \ // RUN: 2>&1 | FileCheck -DMSG=%errc_EINVAL %s -check-prefix=CHECK-ILL-FORMED @@ -42,10 +40,8 @@ // CHECK-ILL-FORMED-SAME: 'optin.taint.TaintPropagation:Config', // CHECK-ILL-FORMED-SAME: that expects a valid yaml file: [[MSG]] -// RUN: not %clang_analyze_cc1 -Wno-incompatible-library-redeclaration \ -// RUN: -verify %s \ +// RUN: not %clang_analyze_cc1 -verify %s \ // RUN: -analyzer-checker=optin.taint.GenericTaint \ -// RUN: -analyzer-checker=debug.ExprInspection \ // RUN: -analyzer-config \ // RUN: optin.taint.TaintPropagation:Config=%S/Inputs/taint-generic-config-invalid-arg.yaml \ // RUN: 2>&1 | FileCheck %s -check-prefix=CHECK-INVALID-ARG @@ -408,6 +404,14 @@ int testDivByZero(void) { return 5/x; // expected-warning {{Division by a tainted value, possibly zero}} } +int testTaintedDivFP(void) { + int x; + scanf("%d", &x); + if (!x) + return 0; + return 5/x; // x cannot be 0, so no tainted warning either +} + // Zero-sized VLAs. void testTaintedVLASize(void) { int x; diff --git a/clang/test/CXX/dcl/dcl.decl/p3.cpp b/clang/test/CXX/dcl/dcl.decl/p3.cpp index f141568ba6c22..b082e1c122a09 100644 --- a/clang/test/CXX/dcl/dcl.decl/p3.cpp +++ b/clang/test/CXX/dcl/dcl.decl/p3.cpp @@ -65,4 +65,4 @@ struct R { }; template -R(T) -> R requires true; // expected-error{{deduction guide cannot have a requires clause}} +R(T) -> R requires true; diff --git a/clang/test/CXX/drs/cwg27xx.cpp b/clang/test/CXX/drs/cwg27xx.cpp index 2b57dbc60aed7..581e2af822d55 100644 --- a/clang/test/CXX/drs/cwg27xx.cpp +++ b/clang/test/CXX/drs/cwg27xx.cpp @@ -201,3 +201,31 @@ static_assert(false, f().s); #endif } // namespace cwg2798 +namespace cwg2707 { // cwg2707: 20 + +#if __cplusplus >= 202002L + +template struct A { + T value[N]; +}; + +template +A(T...) -> A requires (sizeof...(T) == 2); + +// Brace elision is not allowed for synthesized CTAD guides if the array size +// is value-dependent. +// So this should pick up our explicit deduction guide. +A a = {1, 2}; + +A b = {3, 4, 5}; +// expected-error@-1 {{no viable constructor or deduction guide}} \ +// expected-note@-13 {{candidate function template not viable}} \ +// expected-note@-13 {{implicit deduction guide}} \ +// expected-note@-8 {{constraints not satisfied}} \ +// expected-note@-8 {{because 'sizeof...(T) == 2' (3 == 2) evaluated to false}} \ +// expected-note@-13 {{candidate function template not viable}} \ +// expected-note@-13 {{implicit deduction guide}} + +#endif + +} // namespace cwg2707 diff --git a/clang/test/CXX/drs/cwg29xx.cpp b/clang/test/CXX/drs/cwg29xx.cpp index e55e8e35e86f2..9629bdd41a2a5 100644 --- a/clang/test/CXX/drs/cwg29xx.cpp +++ b/clang/test/CXX/drs/cwg29xx.cpp @@ -6,6 +6,26 @@ // RUN: %clang_cc1 -std=c++23 -pedantic-errors -verify=expected %s // RUN: %clang_cc1 -std=c++2c -pedantic-errors -verify=expected %s +namespace cwg2913 { // cwg2913: 20 tentatively ready 2024-08-16 + +#if __cplusplus >= 202002L + +template +struct R { + R(T); + R(T, T); +}; + +template +R(T) -> R requires true; + +template +R(T, T) requires true -> R; // expected-error {{expected function body after function declarator}} + +#endif + +} // namespace cwg2913 + namespace cwg2915 { // cwg2915: 20 tentatively ready 2024-08-16 #if __cplusplus >= 202302L struct A { diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.req/requires-expr.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.req/requires-expr.cpp index 90a38292d15d3..09f8f36d3c5ba 100644 --- a/clang/test/CXX/expr/expr.prim/expr.prim.req/requires-expr.cpp +++ b/clang/test/CXX/expr/expr.prim/expr.prim.req/requires-expr.cpp @@ -65,4 +65,18 @@ template requires requires { T::value; S::s; } struct r4 { }; using r4i = r4; -// expected-error@-1 {{constraints not satisfied for class template 'r4' [with T = int]}} \ No newline at end of file +// expected-error@-1 {{constraints not satisfied for class template 'r4' [with T = int]}} + +namespace GH109538 { +static_assert(requires(void *t) { t; }); +static_assert(requires(void) { 42; }); +static_assert(requires(void t) { // expected-error {{argument may not have 'void' type}} + t; +}); +static_assert(requires(void t, int a) { // expected-error {{'void' must be the first and only parameter if specified}} + t; +}); +static_assert(requires(const void) { // expected-error {{'void' as parameter must not have type qualifiers}} + 42; +}); +} // namespace GH109538 diff --git a/clang/test/CodeGen/RISCV/riscv-xcvalu-c-api.c b/clang/test/CodeGen/RISCV/riscv-xcvalu-c-api.c new file mode 100644 index 0000000000000..b4690a5f1c1ca --- /dev/null +++ b/clang/test/CodeGen/RISCV/riscv-xcvalu-c-api.c @@ -0,0 +1,434 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py +// RUN: %clang_cc1 -triple riscv32 -target-feature +xcvalu -emit-llvm %s -o - \ +// RUN: | FileCheck %s + +#include +#include + +// CHECK-LABEL: @test_alu_slet( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR_I:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[B_ADDR_I:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[B_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store i32 [[A:%.*]], ptr [[A_ADDR]], align 4 +// CHECK-NEXT: store i32 [[B:%.*]], ptr [[B_ADDR]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4 +// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[B_ADDR]], align 4 +// CHECK-NEXT: store i32 [[TMP0]], ptr [[A_ADDR_I]], align 4 +// CHECK-NEXT: store i32 [[TMP1]], ptr [[B_ADDR_I]], align 4 +// CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[A_ADDR_I]], align 4 +// CHECK-NEXT: [[TMP3:%.*]] = load i32, ptr [[B_ADDR_I]], align 4 +// CHECK-NEXT: [[TMP4:%.*]] = icmp sle i32 [[TMP2]], [[TMP3]] +// CHECK-NEXT: [[SLE_I:%.*]] = zext i1 [[TMP4]] to i32 +// CHECK-NEXT: ret i32 [[SLE_I]] +// +int test_alu_slet(int32_t a, int32_t b) { + return __riscv_cv_alu_slet(a, b); +} + +// CHECK-LABEL: @test_alu_sletu( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR_I:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[B_ADDR_I:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[B_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store i32 [[A:%.*]], ptr [[A_ADDR]], align 4 +// CHECK-NEXT: store i32 [[B:%.*]], ptr [[B_ADDR]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4 +// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[B_ADDR]], align 4 +// CHECK-NEXT: store i32 [[TMP0]], ptr [[A_ADDR_I]], align 4 +// CHECK-NEXT: store i32 [[TMP1]], ptr [[B_ADDR_I]], align 4 +// CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[A_ADDR_I]], align 4 +// CHECK-NEXT: [[TMP3:%.*]] = load i32, ptr [[B_ADDR_I]], align 4 +// CHECK-NEXT: [[TMP4:%.*]] = icmp ule i32 [[TMP2]], [[TMP3]] +// CHECK-NEXT: [[SLEU_I:%.*]] = zext i1 [[TMP4]] to i32 +// CHECK-NEXT: ret i32 [[SLEU_I]] +// +int test_alu_sletu(uint32_t a, uint32_t b) { + return __riscv_cv_alu_sletu(a, b); +} + +// CHECK-LABEL: @test_alu_min( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR_I:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[B_ADDR_I:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[B_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store i32 [[A:%.*]], ptr [[A_ADDR]], align 4 +// CHECK-NEXT: store i32 [[B:%.*]], ptr [[B_ADDR]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4 +// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[B_ADDR]], align 4 +// CHECK-NEXT: store i32 [[TMP0]], ptr [[A_ADDR_I]], align 4 +// CHECK-NEXT: store i32 [[TMP1]], ptr [[B_ADDR_I]], align 4 +// CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[A_ADDR_I]], align 4 +// CHECK-NEXT: [[TMP3:%.*]] = load i32, ptr [[B_ADDR_I]], align 4 +// CHECK-NEXT: [[ELT_MIN_I:%.*]] = call i32 @llvm.smin.i32(i32 [[TMP2]], i32 [[TMP3]]) +// CHECK-NEXT: ret i32 [[ELT_MIN_I]] +// +int test_alu_min(int32_t a, int32_t b) { + return __riscv_cv_alu_min(a, b); +} + +// CHECK-LABEL: @test_alu_minu( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR_I:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[B_ADDR_I:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[B_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store i32 [[A:%.*]], ptr [[A_ADDR]], align 4 +// CHECK-NEXT: store i32 [[B:%.*]], ptr [[B_ADDR]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4 +// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[B_ADDR]], align 4 +// CHECK-NEXT: store i32 [[TMP0]], ptr [[A_ADDR_I]], align 4 +// CHECK-NEXT: store i32 [[TMP1]], ptr [[B_ADDR_I]], align 4 +// CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[A_ADDR_I]], align 4 +// CHECK-NEXT: [[TMP3:%.*]] = load i32, ptr [[B_ADDR_I]], align 4 +// CHECK-NEXT: [[ELT_MIN_I:%.*]] = call i32 @llvm.umin.i32(i32 [[TMP2]], i32 [[TMP3]]) +// CHECK-NEXT: ret i32 [[ELT_MIN_I]] +// +int test_alu_minu(uint32_t a, uint32_t b) { + return __riscv_cv_alu_minu(a, b); +} + +// CHECK-LABEL: @test_alu_max( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR_I:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[B_ADDR_I:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[B_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store i32 [[A:%.*]], ptr [[A_ADDR]], align 4 +// CHECK-NEXT: store i32 [[B:%.*]], ptr [[B_ADDR]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4 +// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[B_ADDR]], align 4 +// CHECK-NEXT: store i32 [[TMP0]], ptr [[A_ADDR_I]], align 4 +// CHECK-NEXT: store i32 [[TMP1]], ptr [[B_ADDR_I]], align 4 +// CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[A_ADDR_I]], align 4 +// CHECK-NEXT: [[TMP3:%.*]] = load i32, ptr [[B_ADDR_I]], align 4 +// CHECK-NEXT: [[ELT_MAX_I:%.*]] = call i32 @llvm.smax.i32(i32 [[TMP2]], i32 [[TMP3]]) +// CHECK-NEXT: ret i32 [[ELT_MAX_I]] +// +int test_alu_max(int32_t a, int32_t b) { + return __riscv_cv_alu_max(a, b); +} + +// CHECK-LABEL: @test_alu_maxu( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR_I:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[B_ADDR_I:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[B_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store i32 [[A:%.*]], ptr [[A_ADDR]], align 4 +// CHECK-NEXT: store i32 [[B:%.*]], ptr [[B_ADDR]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4 +// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[B_ADDR]], align 4 +// CHECK-NEXT: store i32 [[TMP0]], ptr [[A_ADDR_I]], align 4 +// CHECK-NEXT: store i32 [[TMP1]], ptr [[B_ADDR_I]], align 4 +// CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[A_ADDR_I]], align 4 +// CHECK-NEXT: [[TMP3:%.*]] = load i32, ptr [[B_ADDR_I]], align 4 +// CHECK-NEXT: [[ELT_MAX_I:%.*]] = call i32 @llvm.umax.i32(i32 [[TMP2]], i32 [[TMP3]]) +// CHECK-NEXT: ret i32 [[ELT_MAX_I]] +// +int test_alu_maxu(uint32_t a, uint32_t b) { + return __riscv_cv_alu_maxu(a, b); +} + +// CHECK-LABEL: @test_alu_exths( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR_I:%.*]] = alloca i16, align 2 +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i16, align 2 +// CHECK-NEXT: store i16 [[A:%.*]], ptr [[A_ADDR]], align 2 +// CHECK-NEXT: [[TMP0:%.*]] = load i16, ptr [[A_ADDR]], align 2 +// CHECK-NEXT: store i16 [[TMP0]], ptr [[A_ADDR_I]], align 2 +// CHECK-NEXT: [[TMP1:%.*]] = load i16, ptr [[A_ADDR_I]], align 2 +// CHECK-NEXT: [[CONV_I:%.*]] = sext i16 [[TMP1]] to i32 +// CHECK-NEXT: [[EXTHS_I:%.*]] = sext i16 [[TMP1]] to i32 +// CHECK-NEXT: ret i32 [[EXTHS_I]] +// +int test_alu_exths(int16_t a) { + return __riscv_cv_alu_exths(a); +} + +// CHECK-LABEL: @test_alu_exthz( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR_I:%.*]] = alloca i16, align 2 +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i16, align 2 +// CHECK-NEXT: store i16 [[A:%.*]], ptr [[A_ADDR]], align 2 +// CHECK-NEXT: [[TMP0:%.*]] = load i16, ptr [[A_ADDR]], align 2 +// CHECK-NEXT: store i16 [[TMP0]], ptr [[A_ADDR_I]], align 2 +// CHECK-NEXT: [[TMP1:%.*]] = load i16, ptr [[A_ADDR_I]], align 2 +// CHECK-NEXT: [[CONV_I:%.*]] = zext i16 [[TMP1]] to i32 +// CHECK-NEXT: [[EXTHZ_I:%.*]] = zext i16 [[TMP1]] to i32 +// CHECK-NEXT: ret i32 [[EXTHZ_I]] +// +int test_alu_exthz(uint16_t a) { + return __riscv_cv_alu_exthz(a); +} + +// CHECK-LABEL: @test_alu_extbs( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR_I:%.*]] = alloca i8, align 1 +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i8, align 1 +// CHECK-NEXT: store i8 [[A:%.*]], ptr [[A_ADDR]], align 1 +// CHECK-NEXT: [[TMP0:%.*]] = load i8, ptr [[A_ADDR]], align 1 +// CHECK-NEXT: store i8 [[TMP0]], ptr [[A_ADDR_I]], align 1 +// CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr [[A_ADDR_I]], align 1 +// CHECK-NEXT: [[CONV_I:%.*]] = sext i8 [[TMP1]] to i32 +// CHECK-NEXT: [[EXTBS_I:%.*]] = sext i8 [[TMP1]] to i32 +// CHECK-NEXT: ret i32 [[EXTBS_I]] +// +int test_alu_extbs(int8_t a) { + return __riscv_cv_alu_extbs(a); +} + +// CHECK-LABEL: @test_alu_extbz( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR_I:%.*]] = alloca i8, align 1 +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i8, align 1 +// CHECK-NEXT: store i8 [[A:%.*]], ptr [[A_ADDR]], align 1 +// CHECK-NEXT: [[TMP0:%.*]] = load i8, ptr [[A_ADDR]], align 1 +// CHECK-NEXT: store i8 [[TMP0]], ptr [[A_ADDR_I]], align 1 +// CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr [[A_ADDR_I]], align 1 +// CHECK-NEXT: [[CONV_I:%.*]] = zext i8 [[TMP1]] to i32 +// CHECK-NEXT: [[EXTBZ_I:%.*]] = zext i8 [[TMP1]] to i32 +// CHECK-NEXT: ret i32 [[EXTBZ_I]] +// +int test_alu_extbz(uint8_t a) { + return __riscv_cv_alu_extbz(a); +} + +// CHECK-LABEL: @test_alu_clip( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR_I:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[B_ADDR_I:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store i32 [[A:%.*]], ptr [[A_ADDR]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4 +// CHECK-NEXT: store i32 [[TMP0]], ptr [[A_ADDR_I]], align 4 +// CHECK-NEXT: store i32 0, ptr [[B_ADDR_I]], align 4 +// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[A_ADDR_I]], align 4 +// CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[B_ADDR_I]], align 4 +// CHECK-NEXT: [[TMP3:%.*]] = call i32 @llvm.riscv.cv.alu.clip(i32 [[TMP1]], i32 [[TMP2]]) +// CHECK-NEXT: ret i32 [[TMP3]] +// +int test_alu_clip(int32_t a) { + return __riscv_cv_alu_clip(a, 0); +} + +// CHECK-LABEL: @test_alu_clipu( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR_I:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[B_ADDR_I:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store i32 [[A:%.*]], ptr [[A_ADDR]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4 +// CHECK-NEXT: store i32 [[TMP0]], ptr [[A_ADDR_I]], align 4 +// CHECK-NEXT: store i32 0, ptr [[B_ADDR_I]], align 4 +// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[A_ADDR_I]], align 4 +// CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[B_ADDR_I]], align 4 +// CHECK-NEXT: [[TMP3:%.*]] = call i32 @llvm.riscv.cv.alu.clipu(i32 [[TMP1]], i32 [[TMP2]]) +// CHECK-NEXT: ret i32 [[TMP3]] +// +int test_alu_clipu(uint32_t a) { + return __riscv_cv_alu_clipu(a, 0); +} + +// CHECK-LABEL: @test_alu_addN( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR_I:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[B_ADDR_I:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[SHFT_ADDR_I:%.*]] = alloca i8, align 1 +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[B_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store i32 [[A:%.*]], ptr [[A_ADDR]], align 4 +// CHECK-NEXT: store i32 [[B:%.*]], ptr [[B_ADDR]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4 +// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[B_ADDR]], align 4 +// CHECK-NEXT: store i32 [[TMP0]], ptr [[A_ADDR_I]], align 4 +// CHECK-NEXT: store i32 [[TMP1]], ptr [[B_ADDR_I]], align 4 +// CHECK-NEXT: store i8 0, ptr [[SHFT_ADDR_I]], align 1 +// CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[A_ADDR_I]], align 4 +// CHECK-NEXT: [[TMP3:%.*]] = load i32, ptr [[B_ADDR_I]], align 4 +// CHECK-NEXT: [[TMP4:%.*]] = load i8, ptr [[SHFT_ADDR_I]], align 1 +// CHECK-NEXT: [[CONV_I:%.*]] = zext i8 [[TMP4]] to i32 +// CHECK-NEXT: [[TMP5:%.*]] = call i32 @llvm.riscv.cv.alu.addN(i32 [[TMP2]], i32 [[TMP3]], i32 [[CONV_I]]) +// CHECK-NEXT: ret i32 [[TMP5]] +// +int test_alu_addN(int32_t a, int32_t b) { + return __riscv_cv_alu_addN(a, b, 0); +} + +// CHECK-LABEL: @test_alu_adduN( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR_I:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[B_ADDR_I:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[SHFT_ADDR_I:%.*]] = alloca i8, align 1 +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[B_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store i32 [[A:%.*]], ptr [[A_ADDR]], align 4 +// CHECK-NEXT: store i32 [[B:%.*]], ptr [[B_ADDR]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4 +// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[B_ADDR]], align 4 +// CHECK-NEXT: store i32 [[TMP0]], ptr [[A_ADDR_I]], align 4 +// CHECK-NEXT: store i32 [[TMP1]], ptr [[B_ADDR_I]], align 4 +// CHECK-NEXT: store i8 0, ptr [[SHFT_ADDR_I]], align 1 +// CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[A_ADDR_I]], align 4 +// CHECK-NEXT: [[TMP3:%.*]] = load i32, ptr [[B_ADDR_I]], align 4 +// CHECK-NEXT: [[TMP4:%.*]] = load i8, ptr [[SHFT_ADDR_I]], align 1 +// CHECK-NEXT: [[CONV_I:%.*]] = zext i8 [[TMP4]] to i32 +// CHECK-NEXT: [[TMP5:%.*]] = call i32 @llvm.riscv.cv.alu.adduN(i32 [[TMP2]], i32 [[TMP3]], i32 [[CONV_I]]) +// CHECK-NEXT: ret i32 [[TMP5]] +// +int test_alu_adduN(uint32_t a, uint32_t b) { + return __riscv_cv_alu_adduN(a, b, 0); +} + +// CHECK-LABEL: @test_alu_addRN( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR_I:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[B_ADDR_I:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[SHFT_ADDR_I:%.*]] = alloca i8, align 1 +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[B_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store i32 [[A:%.*]], ptr [[A_ADDR]], align 4 +// CHECK-NEXT: store i32 [[B:%.*]], ptr [[B_ADDR]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4 +// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[B_ADDR]], align 4 +// CHECK-NEXT: store i32 [[TMP0]], ptr [[A_ADDR_I]], align 4 +// CHECK-NEXT: store i32 [[TMP1]], ptr [[B_ADDR_I]], align 4 +// CHECK-NEXT: store i8 0, ptr [[SHFT_ADDR_I]], align 1 +// CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[A_ADDR_I]], align 4 +// CHECK-NEXT: [[TMP3:%.*]] = load i32, ptr [[B_ADDR_I]], align 4 +// CHECK-NEXT: [[TMP4:%.*]] = load i8, ptr [[SHFT_ADDR_I]], align 1 +// CHECK-NEXT: [[CONV_I:%.*]] = zext i8 [[TMP4]] to i32 +// CHECK-NEXT: [[TMP5:%.*]] = call i32 @llvm.riscv.cv.alu.addRN(i32 [[TMP2]], i32 [[TMP3]], i32 [[CONV_I]]) +// CHECK-NEXT: ret i32 [[TMP5]] +// +int test_alu_addRN(int32_t a, int32_t b) { + return __riscv_cv_alu_addRN(a, b, 0); +} + +// CHECK-LABEL: @test_alu_adduRN( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR_I:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[B_ADDR_I:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[SHFT_ADDR_I:%.*]] = alloca i8, align 1 +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[B_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store i32 [[A:%.*]], ptr [[A_ADDR]], align 4 +// CHECK-NEXT: store i32 [[B:%.*]], ptr [[B_ADDR]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4 +// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[B_ADDR]], align 4 +// CHECK-NEXT: store i32 [[TMP0]], ptr [[A_ADDR_I]], align 4 +// CHECK-NEXT: store i32 [[TMP1]], ptr [[B_ADDR_I]], align 4 +// CHECK-NEXT: store i8 0, ptr [[SHFT_ADDR_I]], align 1 +// CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[A_ADDR_I]], align 4 +// CHECK-NEXT: [[TMP3:%.*]] = load i32, ptr [[B_ADDR_I]], align 4 +// CHECK-NEXT: [[TMP4:%.*]] = load i8, ptr [[SHFT_ADDR_I]], align 1 +// CHECK-NEXT: [[CONV_I:%.*]] = zext i8 [[TMP4]] to i32 +// CHECK-NEXT: [[TMP5:%.*]] = call i32 @llvm.riscv.cv.alu.adduRN(i32 [[TMP2]], i32 [[TMP3]], i32 [[CONV_I]]) +// CHECK-NEXT: ret i32 [[TMP5]] +// +int test_alu_adduRN(uint32_t a, uint32_t b) { + return __riscv_cv_alu_adduRN(a, b, 0); +} + +// CHECK-LABEL: @test_alu_subN( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR_I:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[B_ADDR_I:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[SHFT_ADDR_I:%.*]] = alloca i8, align 1 +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[B_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store i32 [[A:%.*]], ptr [[A_ADDR]], align 4 +// CHECK-NEXT: store i32 [[B:%.*]], ptr [[B_ADDR]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4 +// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[B_ADDR]], align 4 +// CHECK-NEXT: store i32 [[TMP0]], ptr [[A_ADDR_I]], align 4 +// CHECK-NEXT: store i32 [[TMP1]], ptr [[B_ADDR_I]], align 4 +// CHECK-NEXT: store i8 0, ptr [[SHFT_ADDR_I]], align 1 +// CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[A_ADDR_I]], align 4 +// CHECK-NEXT: [[TMP3:%.*]] = load i32, ptr [[B_ADDR_I]], align 4 +// CHECK-NEXT: [[TMP4:%.*]] = load i8, ptr [[SHFT_ADDR_I]], align 1 +// CHECK-NEXT: [[CONV_I:%.*]] = zext i8 [[TMP4]] to i32 +// CHECK-NEXT: [[TMP5:%.*]] = call i32 @llvm.riscv.cv.alu.subN(i32 [[TMP2]], i32 [[TMP3]], i32 [[CONV_I]]) +// CHECK-NEXT: ret i32 [[TMP5]] +// +int test_alu_subN(int32_t a, int32_t b) { + return __riscv_cv_alu_subN(a, b, 0); +} + +// CHECK-LABEL: @test_alu_subuN( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR_I:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[B_ADDR_I:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[SHFT_ADDR_I:%.*]] = alloca i8, align 1 +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[B_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store i32 [[A:%.*]], ptr [[A_ADDR]], align 4 +// CHECK-NEXT: store i32 [[B:%.*]], ptr [[B_ADDR]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4 +// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[B_ADDR]], align 4 +// CHECK-NEXT: store i32 [[TMP0]], ptr [[A_ADDR_I]], align 4 +// CHECK-NEXT: store i32 [[TMP1]], ptr [[B_ADDR_I]], align 4 +// CHECK-NEXT: store i8 0, ptr [[SHFT_ADDR_I]], align 1 +// CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[A_ADDR_I]], align 4 +// CHECK-NEXT: [[TMP3:%.*]] = load i32, ptr [[B_ADDR_I]], align 4 +// CHECK-NEXT: [[TMP4:%.*]] = load i8, ptr [[SHFT_ADDR_I]], align 1 +// CHECK-NEXT: [[CONV_I:%.*]] = zext i8 [[TMP4]] to i32 +// CHECK-NEXT: [[TMP5:%.*]] = call i32 @llvm.riscv.cv.alu.subuN(i32 [[TMP2]], i32 [[TMP3]], i32 [[CONV_I]]) +// CHECK-NEXT: ret i32 [[TMP5]] +// +int test_alu_subuN(uint32_t a, uint32_t b) { + return __riscv_cv_alu_subuN(a, b, 0); +} + +// CHECK-LABEL: @test_alu_subRN( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR_I:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[B_ADDR_I:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[SHFT_ADDR_I:%.*]] = alloca i8, align 1 +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[B_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store i32 [[A:%.*]], ptr [[A_ADDR]], align 4 +// CHECK-NEXT: store i32 [[B:%.*]], ptr [[B_ADDR]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4 +// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[B_ADDR]], align 4 +// CHECK-NEXT: store i32 [[TMP0]], ptr [[A_ADDR_I]], align 4 +// CHECK-NEXT: store i32 [[TMP1]], ptr [[B_ADDR_I]], align 4 +// CHECK-NEXT: store i8 0, ptr [[SHFT_ADDR_I]], align 1 +// CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[A_ADDR_I]], align 4 +// CHECK-NEXT: [[TMP3:%.*]] = load i32, ptr [[B_ADDR_I]], align 4 +// CHECK-NEXT: [[TMP4:%.*]] = load i8, ptr [[SHFT_ADDR_I]], align 1 +// CHECK-NEXT: [[CONV_I:%.*]] = zext i8 [[TMP4]] to i32 +// CHECK-NEXT: [[TMP5:%.*]] = call i32 @llvm.riscv.cv.alu.subRN(i32 [[TMP2]], i32 [[TMP3]], i32 [[CONV_I]]) +// CHECK-NEXT: ret i32 [[TMP5]] +// +int test_alu_subRN(int32_t a, int32_t b) { + return __riscv_cv_alu_subRN(a, b, 0); +} + +// CHECK-LABEL: @test_alu_subuRN( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR_I:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[B_ADDR_I:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[SHFT_ADDR_I:%.*]] = alloca i8, align 1 +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[B_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store i32 [[A:%.*]], ptr [[A_ADDR]], align 4 +// CHECK-NEXT: store i32 [[B:%.*]], ptr [[B_ADDR]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4 +// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[B_ADDR]], align 4 +// CHECK-NEXT: store i32 [[TMP0]], ptr [[A_ADDR_I]], align 4 +// CHECK-NEXT: store i32 [[TMP1]], ptr [[B_ADDR_I]], align 4 +// CHECK-NEXT: store i8 0, ptr [[SHFT_ADDR_I]], align 1 +// CHECK-NEXT: [[TMP2:%.*]] = load i32, ptr [[A_ADDR_I]], align 4 +// CHECK-NEXT: [[TMP3:%.*]] = load i32, ptr [[B_ADDR_I]], align 4 +// CHECK-NEXT: [[TMP4:%.*]] = load i8, ptr [[SHFT_ADDR_I]], align 1 +// CHECK-NEXT: [[CONV_I:%.*]] = zext i8 [[TMP4]] to i32 +// CHECK-NEXT: [[TMP5:%.*]] = call i32 @llvm.riscv.cv.alu.subuRN(i32 [[TMP2]], i32 [[TMP3]], i32 [[CONV_I]]) +// CHECK-NEXT: ret i32 [[TMP5]] +// +int test_alu_subuRN(uint32_t a, uint32_t b) { + return __riscv_cv_alu_subuRN(a, b, 0); +} diff --git a/clang/test/CodeGen/RISCV/riscv-xcvalu.c b/clang/test/CodeGen/RISCV/riscv-xcvalu.c new file mode 100644 index 0000000000000..e4c2a2c3ca28b --- /dev/null +++ b/clang/test/CodeGen/RISCV/riscv-xcvalu.c @@ -0,0 +1,249 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py +// RUN: %clang_cc1 -triple riscv32 -target-feature +xcvalu -emit-llvm %s -o - \ +// RUN: | FileCheck %s + +#include + +// CHECK-LABEL: @test_abs( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store i32 [[A:%.*]], ptr [[A_ADDR]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4 +// CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.abs.i32(i32 [[TMP0]], i1 true) +// CHECK-NEXT: ret i32 [[TMP1]] +// +int test_abs(int a) { + return __builtin_abs(a); +} + +// CHECK-LABEL: @test_alu_slet( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[B_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store i32 [[A:%.*]], ptr [[A_ADDR]], align 4 +// CHECK-NEXT: store i32 [[B:%.*]], ptr [[B_ADDR]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4 +// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[B_ADDR]], align 4 +// CHECK-NEXT: [[TMP2:%.*]] = icmp sle i32 [[TMP0]], [[TMP1]] +// CHECK-NEXT: [[SLE:%.*]] = zext i1 [[TMP2]] to i32 +// CHECK-NEXT: ret i32 [[SLE]] +// +int test_alu_slet(int32_t a, int32_t b) { + return __builtin_riscv_cv_alu_slet(a, b); +} + +// CHECK-LABEL: @test_alu_sletu( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[B_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store i32 [[A:%.*]], ptr [[A_ADDR]], align 4 +// CHECK-NEXT: store i32 [[B:%.*]], ptr [[B_ADDR]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4 +// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[B_ADDR]], align 4 +// CHECK-NEXT: [[TMP2:%.*]] = icmp ule i32 [[TMP0]], [[TMP1]] +// CHECK-NEXT: [[SLEU:%.*]] = zext i1 [[TMP2]] to i32 +// CHECK-NEXT: ret i32 [[SLEU]] +// +int test_alu_sletu(uint32_t a, uint32_t b) { + return __builtin_riscv_cv_alu_sletu(a, b); +} + +// CHECK-LABEL: @test_alu_exths( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i16, align 2 +// CHECK-NEXT: store i16 [[A:%.*]], ptr [[A_ADDR]], align 2 +// CHECK-NEXT: [[TMP0:%.*]] = load i16, ptr [[A_ADDR]], align 2 +// CHECK-NEXT: [[CONV:%.*]] = sext i16 [[TMP0]] to i32 +// CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[CONV]] to i16 +// CHECK-NEXT: [[EXTHS:%.*]] = sext i16 [[TMP1]] to i32 +// CHECK-NEXT: ret i32 [[EXTHS]] +// +int test_alu_exths(int16_t a) { + return __builtin_riscv_cv_alu_exths(a); +} + +// CHECK-LABEL: @test_alu_exthz( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i16, align 2 +// CHECK-NEXT: store i16 [[A:%.*]], ptr [[A_ADDR]], align 2 +// CHECK-NEXT: [[TMP0:%.*]] = load i16, ptr [[A_ADDR]], align 2 +// CHECK-NEXT: [[CONV:%.*]] = zext i16 [[TMP0]] to i32 +// CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[CONV]] to i16 +// CHECK-NEXT: [[EXTHZ:%.*]] = zext i16 [[TMP1]] to i32 +// CHECK-NEXT: ret i32 [[EXTHZ]] +// +int test_alu_exthz(uint16_t a) { + return __builtin_riscv_cv_alu_exthz(a); +} + +// CHECK-LABEL: @test_alu_extbs( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i8, align 1 +// CHECK-NEXT: store i8 [[A:%.*]], ptr [[A_ADDR]], align 1 +// CHECK-NEXT: [[TMP0:%.*]] = load i8, ptr [[A_ADDR]], align 1 +// CHECK-NEXT: [[CONV:%.*]] = sext i8 [[TMP0]] to i32 +// CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[CONV]] to i8 +// CHECK-NEXT: [[EXTBS:%.*]] = sext i8 [[TMP1]] to i32 +// CHECK-NEXT: ret i32 [[EXTBS]] +// +int test_alu_extbs(int8_t a) { + return __builtin_riscv_cv_alu_extbs(a); +} + +// CHECK-LABEL: @test_alu_extbz( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i8, align 1 +// CHECK-NEXT: store i8 [[A:%.*]], ptr [[A_ADDR]], align 1 +// CHECK-NEXT: [[TMP0:%.*]] = load i8, ptr [[A_ADDR]], align 1 +// CHECK-NEXT: [[CONV:%.*]] = zext i8 [[TMP0]] to i32 +// CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[CONV]] to i8 +// CHECK-NEXT: [[EXTBZ:%.*]] = zext i8 [[TMP1]] to i32 +// CHECK-NEXT: ret i32 [[EXTBZ]] +// +int test_alu_extbz(uint8_t a) { + return __builtin_riscv_cv_alu_extbz(a); +} + +// CHECK-LABEL: @test_alu_clip( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store i32 [[A:%.*]], ptr [[A_ADDR]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4 +// CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.riscv.cv.alu.clip(i32 [[TMP0]], i32 15) +// CHECK-NEXT: ret i32 [[TMP1]] +// +int test_alu_clip(int32_t a) { + return __builtin_riscv_cv_alu_clip(a, 15); +} + +// CHECK-LABEL: @test_alu_clipu( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store i32 [[A:%.*]], ptr [[A_ADDR]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4 +// CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.riscv.cv.alu.clipu(i32 [[TMP0]], i32 15) +// CHECK-NEXT: ret i32 [[TMP1]] +// +int test_alu_clipu(uint32_t a) { + return __builtin_riscv_cv_alu_clipu(a, 15); +} + +// CHECK-LABEL: @test_alu_addN( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[B_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store i32 [[A:%.*]], ptr [[A_ADDR]], align 4 +// CHECK-NEXT: store i32 [[B:%.*]], ptr [[B_ADDR]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4 +// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[B_ADDR]], align 4 +// CHECK-NEXT: [[TMP2:%.*]] = call i32 @llvm.riscv.cv.alu.addN(i32 [[TMP0]], i32 [[TMP1]], i32 0) +// CHECK-NEXT: ret i32 [[TMP2]] +// +int test_alu_addN(int32_t a, int32_t b) { + return __builtin_riscv_cv_alu_addN(a, b, 0); +} + +// CHECK-LABEL: @test_alu_adduN( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[B_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store i32 [[A:%.*]], ptr [[A_ADDR]], align 4 +// CHECK-NEXT: store i32 [[B:%.*]], ptr [[B_ADDR]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4 +// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[B_ADDR]], align 4 +// CHECK-NEXT: [[TMP2:%.*]] = call i32 @llvm.riscv.cv.alu.adduN(i32 [[TMP0]], i32 [[TMP1]], i32 0) +// CHECK-NEXT: ret i32 [[TMP2]] +// +int test_alu_adduN(uint32_t a, uint32_t b) { + return __builtin_riscv_cv_alu_adduN(a, b, 0); +} + +// CHECK-LABEL: @test_alu_addRN( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[B_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store i32 [[A:%.*]], ptr [[A_ADDR]], align 4 +// CHECK-NEXT: store i32 [[B:%.*]], ptr [[B_ADDR]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4 +// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[B_ADDR]], align 4 +// CHECK-NEXT: [[TMP2:%.*]] = call i32 @llvm.riscv.cv.alu.addRN(i32 [[TMP0]], i32 [[TMP1]], i32 0) +// CHECK-NEXT: ret i32 [[TMP2]] +// +int test_alu_addRN(int32_t a, int32_t b) { + return __builtin_riscv_cv_alu_addRN(a, b, 0); +} + +// CHECK-LABEL: @test_alu_adduRN( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[B_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store i32 [[A:%.*]], ptr [[A_ADDR]], align 4 +// CHECK-NEXT: store i32 [[B:%.*]], ptr [[B_ADDR]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4 +// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[B_ADDR]], align 4 +// CHECK-NEXT: [[TMP2:%.*]] = call i32 @llvm.riscv.cv.alu.adduRN(i32 [[TMP0]], i32 [[TMP1]], i32 0) +// CHECK-NEXT: ret i32 [[TMP2]] +// +int test_alu_adduRN(uint32_t a, uint32_t b) { + return __builtin_riscv_cv_alu_adduRN(a, b, 0); +} + +// CHECK-LABEL: @test_alu_subN( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[B_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store i32 [[A:%.*]], ptr [[A_ADDR]], align 4 +// CHECK-NEXT: store i32 [[B:%.*]], ptr [[B_ADDR]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4 +// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[B_ADDR]], align 4 +// CHECK-NEXT: [[TMP2:%.*]] = call i32 @llvm.riscv.cv.alu.subN(i32 [[TMP0]], i32 [[TMP1]], i32 0) +// CHECK-NEXT: ret i32 [[TMP2]] +// +int test_alu_subN(int32_t a, int32_t b) { + return __builtin_riscv_cv_alu_subN(a, b, 0); +} + +// CHECK-LABEL: @test_alu_subuN( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[B_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store i32 [[A:%.*]], ptr [[A_ADDR]], align 4 +// CHECK-NEXT: store i32 [[B:%.*]], ptr [[B_ADDR]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4 +// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[B_ADDR]], align 4 +// CHECK-NEXT: [[TMP2:%.*]] = call i32 @llvm.riscv.cv.alu.subuN(i32 [[TMP0]], i32 [[TMP1]], i32 0) +// CHECK-NEXT: ret i32 [[TMP2]] +// +int test_alu_subuN(uint32_t a, uint32_t b) { + return __builtin_riscv_cv_alu_subuN(a, b, 0); +} + +// CHECK-LABEL: @test_alu_subRN( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[B_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store i32 [[A:%.*]], ptr [[A_ADDR]], align 4 +// CHECK-NEXT: store i32 [[B:%.*]], ptr [[B_ADDR]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4 +// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[B_ADDR]], align 4 +// CHECK-NEXT: [[TMP2:%.*]] = call i32 @llvm.riscv.cv.alu.subRN(i32 [[TMP0]], i32 [[TMP1]], i32 0) +// CHECK-NEXT: ret i32 [[TMP2]] +// +int test_alu_subRN(int32_t a, int32_t b) { + return __builtin_riscv_cv_alu_subRN(a, b, 0); +} + +// CHECK-LABEL: @test_alu_subuRN( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[B_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store i32 [[A:%.*]], ptr [[A_ADDR]], align 4 +// CHECK-NEXT: store i32 [[B:%.*]], ptr [[B_ADDR]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_ADDR]], align 4 +// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[B_ADDR]], align 4 +// CHECK-NEXT: [[TMP2:%.*]] = call i32 @llvm.riscv.cv.alu.subuRN(i32 [[TMP0]], i32 [[TMP1]], i32 0) +// CHECK-NEXT: ret i32 [[TMP2]] +// +int test_alu_subuRN(uint32_t a, uint32_t b) { + return __builtin_riscv_cv_alu_subuRN(a, b, 0); +} diff --git a/clang/test/CodeGen/X86/bmi-builtins.c b/clang/test/CodeGen/X86/bmi-builtins.c index 530d38dcf342c..ded40ca59781e 100644 --- a/clang/test/CodeGen/X86/bmi-builtins.c +++ b/clang/test/CodeGen/X86/bmi-builtins.c @@ -237,6 +237,9 @@ unsigned long long test_blsr_u64(unsigned long long __X) { // Test constexpr handling. #if defined(__cplusplus) && (__cplusplus >= 201103L) +char andnu32[__andn_u32(0x01234567, 0xFECDBA98) == (~0x01234567 & 0xFECDBA98) ? 1 : -1]; +char andn2u32[_andn_u32(0x01234567, 0xFECDBA98) == (~0x01234567 & 0xFECDBA98) ? 1 : -1]; + char bextr32_0[__bextr_u32(0x00000000, 0x00000000) == 0x00000000 ? 1 : -1]; char bextr32_1[__bextr_u32(0x000003F0, 0xFFFF1004) == 0x0000003F ? 1 : -1]; char bextr32_2[__bextr_u32(0x000003F0, 0xFFFF3008) == 0x00000003 ? 1 : -1]; @@ -249,7 +252,39 @@ char bextr32_6[_bextr_u32(0x00000000, 0x00000000, 0x00000000) == 0x00000000 ? 1 char bextr32_7[_bextr_u32(0x000003F0, 0xFFFFFF04, 0xFFFFFF10) == 0x0000003F ? 1 : -1]; char bextr32_8[_bextr_u32(0x000003F0, 0xFFFFFF08, 0xFFFFFF30) == 0x00000003 ? 1 : -1]; +char blsiu32[__blsi_u32(0x89ABCDEF) == (0x89ABCDEF & -0x89ABCDEF) ? 1 : -1]; +char blsi2u32[_blsi_u32(0x89ABCDEF) == (0x89ABCDEF & -0x89ABCDEF) ? 1 : -1]; + +char blsmasku32[__blsmsk_u32(0x89ABCDEF) == (0x89ABCDEF ^ (0x89ABCDEF - 1)) ? 1 : -1]; +char blsmask2u32[_blsmsk_u32(0x89ABCDEF) == (0x89ABCDEF ^ (0x89ABCDEF - 1)) ? 1 : -1]; + +char blsru32[__blsr_u32(0x89ABCDEF) == (0x89ABCDEF & (0x89ABCDEF - 1)) ? 1 : -1]; +char blsr2u32[_blsr_u32(0x89ABCDEF) == (0x89ABCDEF & (0x89ABCDEF - 1)) ? 1 : -1]; + +char tzcntu16_0[__tzcnt_u16(0x0000) == 16 ? 1 : -1]; +char tzcntu16_1[__tzcnt_u16(0x0001) == 0 ? 1 : -1]; +char tzcntu16_2[__tzcnt_u16(0x0010) == 4 ? 1 : -1]; + +char tzcnt2u16_0[_tzcnt_u16(0x0000) == 16 ? 1 : -1]; +char tzcnt2u16_1[_tzcnt_u16(0x0001) == 0 ? 1 : -1]; +char tzcnt2u16_2[_tzcnt_u16(0x0010) == 4 ? 1 : -1]; + +char tzcntu32_0[__tzcnt_u32(0x00000000) == 32 ? 1 : -1]; +char tzcntu32_1[__tzcnt_u32(0x00000001) == 0 ? 1 : -1]; +char tzcntu32_2[__tzcnt_u32(0x00000080) == 7 ? 1 : -1]; + +char tzcnt2u32_0[_tzcnt_u32(0x00000000) == 32 ? 1 : -1]; +char tzcnt2u32_1[_tzcnt_u32(0x00000001) == 0 ? 1 : -1]; +char tzcnt2u32_2[_tzcnt_u32(0x00000080) == 7 ? 1 : -1]; + +char tzcnt3u32_0[_mm_tzcnt_32(0x00000000) == 32 ? 1 : -1]; +char tzcnt3u32_1[_mm_tzcnt_32(0x00000001) == 0 ? 1 : -1]; +char tzcnt3u32_2[_mm_tzcnt_32(0x00000080) == 7 ? 1 : -1]; + #ifdef __x86_64__ +char andnu64[__andn_u64(0x0123456789ABCDEFULL, 0xFECDBA9876543210ULL) == (~0x0123456789ABCDEFULL & 0xFECDBA9876543210ULL) ? 1 : -1]; +char andn2u64[_andn_u64(0x0123456789ABCDEFULL, 0xFECDBA9876543210ULL) == (~0x0123456789ABCDEFULL & 0xFECDBA9876543210ULL) ? 1 : -1]; + char bextr64_0[__bextr_u64(0x0000000000000000ULL, 0x0000000000000000ULL) == 0x0000000000000000ULL ? 1 : -1]; char bextr64_1[__bextr_u64(0xF000000000000001ULL, 0x0000000000004001ULL) == 0x7800000000000000ULL ? 1 : -1]; char bextr64_2[__bextr_u64(0xF000000000000001ULL, 0xFFFFFFFFFFFF1001ULL) == 0x0000000000000000ULL ? 1 : -1]; @@ -261,5 +296,26 @@ char bextr64_5[_bextr2_u64(0xF000000000000001ULL, 0xFFFFFFFFFFFF1001ULL) == 0x00 char bextr64_6[_bextr_u64(0x0000000000000000ULL, 0x0000000000000000ULL, 0x0000000000000000ULL) == 0x0000000000000000ULL ? 1 : -1]; char bextr64_7[_bextr_u64(0xF000000000000001ULL, 0x0000000000000001ULL, 0x0000000000000040ULL) == 0x7800000000000000ULL ? 1 : -1]; char bextr64_8[_bextr_u64(0xF000000000000001ULL, 0xFFFFFFFFFFFFFF01ULL, 0xFFFFFFFFFFFFFF10ULL) == 0x0000000000000000ULL ? 1 : -1]; + +char blsiu64[__blsi_u64(0x0123456789ABCDEFULL) == (0x0123456789ABCDEFULL & -0x0123456789ABCDEFULL) ? 1 : -1]; +char blsi2u64[_blsi_u64(0x0123456789ABCDEFULL) == (0x0123456789ABCDEFULL & -0x0123456789ABCDEFULL) ? 1 : -1]; + +char blsmasku64[__blsmsk_u64(0x0123456789ABCDEFULL) == (0x0123456789ABCDEFULL ^ (0x0123456789ABCDEFULL - 1)) ? 1 : -1]; +char blsmask2u64[_blsmsk_u64(0x0123456789ABCDEFULL) == (0x0123456789ABCDEFULL ^ (0x0123456789ABCDEFULL - 1)) ? 1 : -1]; + +char blsru64[__blsr_u64(0x0123456789ABCDEFULL) == (0x0123456789ABCDEFULL & (0x0123456789ABCDEFULL - 1)) ? 1 : -1]; +char blsr2u64[_blsr_u64(0x0123456789ABCDEFULL) == (0x0123456789ABCDEFULL & (0x0123456789ABCDEFULL - 1)) ? 1 : -1]; + +char tzcntu64_0[__tzcnt_u64(0x0000000000000000ULL) == 64 ? 1 : -1]; +char tzcntu64_1[__tzcnt_u64(0x0000000000000001ULL) == 0 ? 1 : -1]; +char tzcntu64_2[__tzcnt_u64(0x0000000800000000ULL) == 35 ? 1 : -1]; + +char tzcnt2u64_0[_tzcnt_u64(0x0000000000000000ULL) == 64 ? 1 : -1]; +char tzcnt2u64_1[_tzcnt_u64(0x0000000000000001ULL) == 0 ? 1 : -1]; +char tzcnt2u64_2[_tzcnt_u64(0x0000000800000000ULL) == 35 ? 1 : -1]; + +char tzcnt3u64_0[_mm_tzcnt_64(0x0000000000000000ULL) == 64 ? 1 : -1]; +char tzcnt3u64_1[_mm_tzcnt_64(0x0000000000000001ULL) == 0 ? 1 : -1]; +char tzcnt3u64_2[_mm_tzcnt_64(0x0000000800000000ULL) == 35 ? 1 : -1]; #endif #endif \ No newline at end of file diff --git a/clang/test/CodeGen/X86/bmi2-builtins.c b/clang/test/CodeGen/X86/bmi2-builtins.c index a9e9bc5862a34..e00bac4b51e90 100644 --- a/clang/test/CodeGen/X86/bmi2-builtins.c +++ b/clang/test/CodeGen/X86/bmi2-builtins.c @@ -1,5 +1,7 @@ -// RUN: %clang_cc1 -ffreestanding %s -triple=x86_64-apple-darwin -target-feature +bmi2 -emit-llvm -o - | FileCheck %s -// RUN: %clang_cc1 -ffreestanding %s -triple=i386-apple-darwin -target-feature +bmi2 -emit-llvm -o - | FileCheck %s --check-prefix=B32 +// RUN: %clang_cc1 -x c -ffreestanding %s -triple=x86_64-apple-darwin -target-feature +bmi2 -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 -x c -ffreestanding %s -triple=i386-apple-darwin -target-feature +bmi2 -emit-llvm -o - | FileCheck %s --check-prefix=B32 +// RUN: %clang_cc1 -x c++ -ffreestanding %s -triple=x86_64-apple-darwin -target-feature +bmi2 -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 -x c++ -ffreestanding %s -triple=i386-apple-darwin -target-feature +bmi2 -emit-llvm -o - | FileCheck %s --check-prefix=B32 #include @@ -22,7 +24,6 @@ unsigned int test_pext_u32(unsigned int __X, unsigned int __Y) { #ifdef __i386__ unsigned int test_mulx_u32(unsigned int __X, unsigned int __Y, unsigned int *__P) { - // B32: @test_mulx_u32 // B32: mul i64 return _mulx_u32(__X, __Y, __P); } @@ -46,8 +47,44 @@ unsigned long long test_pext_u64(unsigned long long __X, unsigned long long __Y) unsigned long long test_mulx_u64(unsigned long long __X, unsigned long long __Y, unsigned long long *__P) { - // CHECK: @test_mulx_u64 // CHECK: mul i128 return _mulx_u64(__X, __Y, __P); } #endif + +// Test constexpr handling. +#if defined(__cplusplus) && (__cplusplus >= 201103L) +char bzhi32_0[_bzhi_u32(0x89ABCDEF, 0) == 0x00000000 ? 1 : -1]; +char bzhi32_1[_bzhi_u32(0x89ABCDEF, 16) == 0x0000CDEF ? 1 : -1]; +char bzhi32_2[_bzhi_u32(0x89ABCDEF, 31) == 0x09ABCDEF ? 1 : -1]; +char bzhi32_3[_bzhi_u32(0x89ABCDEF, 32) == 0x89ABCDEF ? 1 : -1]; +char bzhi32_4[_bzhi_u32(0x89ABCDEF, 99) == 0x89ABCDEF ? 1 : -1]; +char bzhi32_5[_bzhi_u32(0x89ABCDEF, 260) == 0x0000000F ? 1 : -1]; + +char pdep32_0[_pdep_u32(0x89ABCDEF, 0x00000000) == 0x00000000 ? 1 : -1]; +char pdep32_1[_pdep_u32(0x89ABCDEF, 0x000000F0) == 0x000000F0 ? 1 : -1]; +char pdep32_2[_pdep_u32(0x89ABCDEF, 0xF00000F0) == 0xE00000F0 ? 1 : -1]; +char pdep32_3[_pdep_u32(0x89ABCDEF, 0xFFFFFFFF) == 0x89ABCDEF ? 1 : -1]; + +char pext32_0[_pext_u32(0x89ABCDEF, 0x00000000) == 0x00000000 ? 1 : -1]; +char pext32_1[_pext_u32(0x89ABCDEF, 0x000000F0) == 0x0000000E ? 1 : -1]; +char pext32_2[_pext_u32(0x89ABCDEF, 0xF00000F0) == 0x0000008E ? 1 : -1]; +char pext32_3[_pext_u32(0x89ABCDEF, 0xFFFFFFFF) == 0x89ABCDEF ? 1 : -1]; + +#ifdef __x86_64__ +char bzhi64_0[_bzhi_u64(0x0123456789ABCDEFULL, 0) == 0x0000000000000000ULL ? 1 : -1]; +char bzhi64_1[_bzhi_u64(0x0123456789ABCDEFULL, 32) == 0x0000000089ABCDEFULL ? 1 : -1]; +char bzhi64_2[_bzhi_u64(0x0123456789ABCDEFULL, 99) == 0x0123456789ABCDEFULL ? 1 : -1]; +char bzhi64_3[_bzhi_u64(0x0123456789ABCDEFULL, 520) == 0x00000000000000EFULL ? 1 : -1]; + +char pdep64_0[_pdep_u64(0x0123456789ABCDEFULL, 0x0000000000000000ULL) == 0x0000000000000000ULL ? 1 : -1]; +char pdep64_1[_pdep_u64(0x0123456789ABCDEFULL, 0x00000000000000F0ULL) == 0x00000000000000F0ULL ? 1 : -1]; +char pdep64_2[_pdep_u64(0x0123456789ABCDEFULL, 0xF00000F0F00000F0ULL) == 0xC00000D0E00000F0ULL ? 1 : -1]; +char pdep64_3[_pdep_u64(0x0123456789ABCDEFULL, 0xFFFFFFFFFFFFFFFFULL) == 0x0123456789ABCDEFULL ? 1 : -1]; + +char pext64_0[_pext_u64(0x0123456789ABCDEFULL, 0x0000000000000000ULL) == 0x0000000000000000ULL ? 1 : -1]; +char pext64_1[_pext_u64(0x0123456789ABCDEFULL, 0x00000000000000F0ULL) == 0x000000000000000EULL ? 1 : -1]; +char pext64_2[_pext_u64(0x0123456789ABCDEFULL, 0xF00000F0F00000F0ULL) == 0x000000000000068EULL ? 1 : -1]; +char pext64_3[_pext_u64(0x0123456789ABCDEFULL, 0xFFFFFFFFFFFFFFFFULL) == 0x0123456789ABCDEFULL ? 1 : -1]; +#endif +#endif \ No newline at end of file diff --git a/clang/test/CodeGen/X86/lzcnt-builtins.c b/clang/test/CodeGen/X86/lzcnt-builtins.c index 9255207ffaef4..18ced89fc79b1 100644 --- a/clang/test/CodeGen/X86/lzcnt-builtins.c +++ b/clang/test/CodeGen/X86/lzcnt-builtins.c @@ -1,4 +1,5 @@ -// RUN: %clang_cc1 -ffreestanding %s -triple=x86_64-apple-darwin -target-feature +lzcnt -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 -x c -ffreestanding %s -triple=x86_64-apple-darwin -target-feature +lzcnt -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 -x c++ -std=c++11 -ffreestanding %s -triple=x86_64-apple-darwin -target-feature +lzcnt -emit-llvm -o - | FileCheck %s #include @@ -32,3 +33,27 @@ unsigned long long test__lzcnt_u64(unsigned long long __X) // CHECK: @llvm.ctlz.i64(i64 %{{.*}}, i1 false) return _lzcnt_u64(__X); } + + +// Test constexpr handling. +#if defined(__cplusplus) && (__cplusplus >= 201103L) +char lzcnt16_0[__lzcnt16(0x0000) == 16 ? 1 : -1]; +char lzcnt16_1[__lzcnt16(0x8000) == 0 ? 1 : -1]; +char lzcnt16_2[__lzcnt16(0x0010) == 11 ? 1 : -1]; + +char lzcnt32_0[__lzcnt32(0x00000000) == 32 ? 1 : -1]; +char lzcnt32_1[__lzcnt32(0x80000000) == 0 ? 1 : -1]; +char lzcnt32_2[__lzcnt32(0x00000010) == 27 ? 1 : -1]; + +char lzcnt64_0[__lzcnt64(0x0000000000000000ULL) == 64 ? 1 : -1]; +char lzcnt64_1[__lzcnt64(0x8000000000000000ULL) == 0 ? 1 : -1]; +char lzcnt64_2[__lzcnt64(0x0000000100000000ULL) == 31 ? 1 : -1]; + +char lzcntu32_0[_lzcnt_u32(0x00000000) == 32 ? 1 : -1]; +char lzcntu32_1[_lzcnt_u32(0x80000000) == 0 ? 1 : -1]; +char lzcntu32_2[_lzcnt_u32(0x00000010) == 27 ? 1 : -1]; + +char lzcntu64_0[_lzcnt_u64(0x0000000000000000ULL) == 64 ? 1 : -1]; +char lzcntu64_1[_lzcnt_u64(0x8000000000000000ULL) == 0 ? 1 : -1]; +char lzcntu64_2[_lzcnt_u64(0x0000000100000000ULL) == 31 ? 1 : -1]; +#endif \ No newline at end of file diff --git a/clang/test/CodeGen/X86/tbm-builtins.c b/clang/test/CodeGen/X86/tbm-builtins.c index ef5e1657521f9..d916627a23f57 100644 --- a/clang/test/CodeGen/X86/tbm-builtins.c +++ b/clang/test/CodeGen/X86/tbm-builtins.c @@ -185,9 +185,27 @@ char bextri32_0[__bextri_u32(0x00000000, 0x00000000) == 0x00000000 ? 1 : -1]; char bextri32_1[__bextri_u32(0x000003F0, 0xFFFF1004) == 0x0000003F ? 1 : -1]; char bextri32_2[__bextri_u32(0x000003F0, 0xFFFF3008) == 0x00000003 ? 1 : -1]; +char blcfill32[__blcfill_u32(0x89ABCDEF) == (0x89ABCDEF & (0x89ABCDEF + 1)) ? 1 : -1]; +char blci32[__blci_u32(0x89ABCDEF) == (0x89ABCDEF | ~(0x89ABCDEF + 1)) ? 1 : -1]; +char blcmsk32[__blcmsk_u32(0x89ABCDEF) == (0x89ABCDEF ^ (0x89ABCDEF + 1)) ? 1 : -1]; +char blcs32[__blcs_u32(0x89ABCDEF) == (0x89ABCDEF | (0x89ABCDEF + 1)) ? 1 : -1]; +char blsfill32[__blsfill_u32(0x89ABCDEF) == (0x89ABCDEF | (0x89ABCDEF - 1)) ? 1 : -1]; +char blsic32[__blsic_u32(0x89ABCDEF) == (~0x89ABCDEF | (0x89ABCDEF - 1)) ? 1 : -1]; +char t1mskc32[__t1mskc_u32(0x89ABCDEF) == (~0x89ABCDEF | (0x89ABCDEF + 1)) ? 1 : -1]; +char tzmsk32[__tzmsk_u32(0x89ABCDEF) == (~0x89ABCDEF & (0x89ABCDEF - 1)) ? 1 : -1]; + #ifdef __x86_64__ char bextri64_0[__bextri_u64(0x0000000000000000ULL, 0x0000000000000000ULL) == 0x0000000000000000ULL ? 1 : -1]; char bextri64_1[__bextri_u64(0xF000000000000001ULL, 0x0000000000004001ULL) == 0x7800000000000000ULL ? 1 : -1]; char bextri64_2[__bextri_u64(0xF000000000000001ULL, 0xFFFFFFFFFFFF1001ULL) == 0x0000000000000000ULL ? 1 : -1]; + +char blcfill64[__blcfill_u64(0xFEDCBA9876543210) == (0xFEDCBA9876543210 & (0xFEDCBA9876543210 + 1)) ? 1 : -1]; +char blci64[__blci_u64(0xFEDCBA9876543210) == (0xFEDCBA9876543210 | ~(0xFEDCBA9876543210 + 1)) ? 1 : -1]; +char blcmsk64[__blcmsk_u64(0xFEDCBA9876543210) == (0xFEDCBA9876543210 ^ (0xFEDCBA9876543210 + 1)) ? 1 : -1]; +char blcs64[__blcs_u64(0xFEDCBA9876543210) == (0xFEDCBA9876543210 | (0xFEDCBA9876543210 + 1)) ? 1 : -1]; +char blsfill64[__blsfill_u64(0xFEDCBA9876543210) == (0xFEDCBA9876543210 | (0xFEDCBA9876543210 - 1)) ? 1 : -1]; +char blsic64[__blsic_u64(0xFEDCBA9876543210) == (~0xFEDCBA9876543210 | (0xFEDCBA9876543210 - 1)) ? 1 : -1]; +char t1mskc64[__t1mskc_u64(0xFEDCBA9876543210) == (~0xFEDCBA9876543210 | (0xFEDCBA9876543210 + 1)) ? 1 : -1]; +char tzmsk64[__tzmsk_u64(0xFEDCBA9876543210) == (~0xFEDCBA9876543210 & (0xFEDCBA9876543210 - 1)) ? 1 : -1]; #endif #endif diff --git a/clang/test/CodeGen/aarch64-sme2-intrinsics/acle_sme2_luti4_zt.c b/clang/test/CodeGen/aarch64-sme2-intrinsics/acle_sme2_luti4_zt.c new file mode 100644 index 0000000000000..a2f87aed3187c --- /dev/null +++ b/clang/test/CodeGen/aarch64-sme2-intrinsics/acle_sme2_luti4_zt.c @@ -0,0 +1,42 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5 + +// REQUIRES: aarch64-registered-target + +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sme -target-feature +sme2 -target-feature +sme-lutv2 -disable-O0-optnone -Werror -Wall -emit-llvm -o - %s | opt -S -p mem2reg,instcombine,tailcallelim | FileCheck %s +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sme -target-feature +sme2 -target-feature +sme-lutv2 -disable-O0-optnone -Werror -Wall -emit-llvm -o - -x c++ %s | opt -S -p mem2reg,instcombine,tailcallelim | FileCheck %s -check-prefix=CPP-CHECK +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sme -target-feature +sme2 -target-feature +sme-lutv2 -disable-O0-optnone -Werror -Wall -o /dev/null %s + + +#include + +// CHECK-LABEL: define dso_local { , , , } @test_luti4_zt_u8_x4( +// CHECK-SAME: [[OP_COERCE0:%.*]], [[OP_COERCE1:%.*]]) #[[ATTR0:[0-9]+]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[TMP0:%.*]] = tail call { , , , } @llvm.aarch64.sme.luti4.zt.x4.nxv16i8(i32 0, [[OP_COERCE0]], [[OP_COERCE1]]) +// CHECK-NEXT: ret { , , , } [[TMP0]] +// +// CPP-CHECK-LABEL: define dso_local { , , , } @_Z19test_luti4_zt_u8_x411svuint8x2_t( +// CPP-CHECK-SAME: [[OP_COERCE0:%.*]], [[OP_COERCE1:%.*]]) #[[ATTR0:[0-9]+]] { +// CPP-CHECK-NEXT: [[ENTRY:.*:]] +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call { , , , } @llvm.aarch64.sme.luti4.zt.x4.nxv16i8(i32 0, [[OP_COERCE0]], [[OP_COERCE1]]) +// CPP-CHECK-NEXT: ret { , , , } [[TMP0]] +// +svuint8x4_t test_luti4_zt_u8_x4(svuint8x2_t op) __arm_streaming __arm_in("zt0") { + return svluti4_zt_u8_x4(0, op); +} + +// CHECK-LABEL: define dso_local { , , , } @test_luti4_zt_s8_x4( +// CHECK-SAME: [[OP_COERCE0:%.*]], [[OP_COERCE1:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[TMP0:%.*]] = tail call { , , , } @llvm.aarch64.sme.luti4.zt.x4.nxv16i8(i32 0, [[OP_COERCE0]], [[OP_COERCE1]]) +// CHECK-NEXT: ret { , , , } [[TMP0]] +// +// CPP-CHECK-LABEL: define dso_local { , , , } @_Z19test_luti4_zt_s8_x411svuint8x2_t( +// CPP-CHECK-SAME: [[OP_COERCE0:%.*]], [[OP_COERCE1:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: [[ENTRY:.*:]] +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call { , , , } @llvm.aarch64.sme.luti4.zt.x4.nxv16i8(i32 0, [[OP_COERCE0]], [[OP_COERCE1]]) +// CPP-CHECK-NEXT: ret { , , , } [[TMP0]] +// +svint8x4_t test_luti4_zt_s8_x4(svuint8x2_t op) __arm_streaming __arm_in("zt0") { + return svluti4_zt_s8_x4(0, op); +} diff --git a/clang/test/CodeGen/aarch64-sme2-intrinsics/acle_sme2_write_lane_zt.c b/clang/test/CodeGen/aarch64-sme2-intrinsics/acle_sme2_write_lane_zt.c new file mode 100644 index 0000000000000..e73697a569473 --- /dev/null +++ b/clang/test/CodeGen/aarch64-sme2-intrinsics/acle_sme2_write_lane_zt.c @@ -0,0 +1,402 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5 + +// RUN: %clang_cc1 -triple aarch64 -target-feature +bf16 -target-feature +sme -target-feature +sme2 -target-feature +sme-lutv2 -disable-O0-optnone -Werror -Wall -emit-llvm -o - %s | opt -S -p mem2reg,instcombine,tailcallelim | FileCheck %s +// RUN: %clang_cc1 -triple aarch64 -target-feature +bf16 -target-feature +sme -target-feature +sme2 -target-feature +sme-lutv2 -disable-O0-optnone -Werror -Wall -emit-llvm -o - -x c++ %s | opt -S -p mem2reg,instcombine,tailcallelim | FileCheck %s -check-prefix=CPP-CHECK +// RUN: %clang_cc1 -DSVE_OVERLOADED_FORMS -triple aarch64 -target-feature +bf16 -target-feature +sme -target-feature +sme2 -target-feature +sme-lutv2 -disable-O0-optnone -Werror -Wall -emit-llvm -o - %s | opt -S -p mem2reg,instcombine,tailcallelim | FileCheck %s +// RUN: %clang_cc1 -DSVE_OVERLOADED_FORMS -triple aarch64 -target-feature +bf16 -target-feature +sme -target-feature +sme2 -target-feature +sme-lutv2 -disable-O0-optnone -Werror -Wall -emit-llvm -o - -x c++ %s | opt -S -p mem2reg,instcombine,tailcallelim | FileCheck %s -check-prefix=CPP-CHECK +// RUN: %clang_cc1 -triple aarch64 -target-feature +bf16 -target-feature +sme -target-feature +sme2 -target-feature +sme-lutv2 -S -disable-O0-optnone -Werror -Wall -o /dev/null %s + +// REQUIRES: aarch64-registered-target + +#ifdef SVE_OVERLOADED_FORMS +#define SVE_ACLE_FUNC(A1,A2_UNUSED) A1 +#else +#define SVE_ACLE_FUNC(A1,A2) A1##A2 +#endif + +#include + +// CHECK-LABEL: define dso_local void @test_write_lane_zt_u8_1( +// CHECK-SAME: [[V:%.*]]) #[[ATTR0:[0-9]+]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.sme.write.lane.zt.nxv16i8(i32 0, [[V]], i32 1) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: define dso_local void @_Z23test_write_lane_zt_u8_1u11__SVUint8_t( +// CPP-CHECK-SAME: [[V:%.*]]) #[[ATTR0:[0-9]+]] { +// CPP-CHECK-NEXT: [[ENTRY:.*:]] +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sme.write.lane.zt.nxv16i8(i32 0, [[V]], i32 1) +// CPP-CHECK-NEXT: ret void +// +void test_write_lane_zt_u8_1(svuint8_t v) __arm_streaming __arm_inout("zt0") { + SVE_ACLE_FUNC(svwrite_lane_zt, _u8)(0, v, 1); +} + +// CHECK-LABEL: define dso_local void @test_write_lane_zt_s8_2( +// CHECK-SAME: [[V:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.sme.write.lane.zt.nxv16i8(i32 0, [[V]], i32 2) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: define dso_local void @_Z23test_write_lane_zt_s8_2u10__SVInt8_t( +// CPP-CHECK-SAME: [[V:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: [[ENTRY:.*:]] +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sme.write.lane.zt.nxv16i8(i32 0, [[V]], i32 2) +// CPP-CHECK-NEXT: ret void +// +void test_write_lane_zt_s8_2(svint8_t v) __arm_streaming __arm_inout("zt0") { + SVE_ACLE_FUNC(svwrite_lane_zt, _s8)(0, v, 2); +} + +// CHECK-LABEL: define dso_local void @test_write_lane_zt_u16_3( +// CHECK-SAME: [[V:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.sme.write.lane.zt.nxv8i16(i32 0, [[V]], i32 1) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: define dso_local void @_Z24test_write_lane_zt_u16_3u12__SVUint16_t( +// CPP-CHECK-SAME: [[V:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: [[ENTRY:.*:]] +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sme.write.lane.zt.nxv8i16(i32 0, [[V]], i32 1) +// CPP-CHECK-NEXT: ret void +// +void test_write_lane_zt_u16_3(svuint16_t v) __arm_streaming __arm_inout("zt0") { + SVE_ACLE_FUNC(svwrite_lane_zt, _u16)(0, v, 1); +} + +// CHECK-LABEL: define dso_local void @test_write_lane_zt_s16_1( +// CHECK-SAME: [[V:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.sme.write.lane.zt.nxv8i16(i32 0, [[V]], i32 1) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: define dso_local void @_Z24test_write_lane_zt_s16_1u11__SVInt16_t( +// CPP-CHECK-SAME: [[V:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: [[ENTRY:.*:]] +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sme.write.lane.zt.nxv8i16(i32 0, [[V]], i32 1) +// CPP-CHECK-NEXT: ret void +// +void test_write_lane_zt_s16_1(svint16_t v) __arm_streaming __arm_inout("zt0") { + SVE_ACLE_FUNC(svwrite_lane_zt, _s16)(0, v, 1); +} + +// CHECK-LABEL: define dso_local void @test_write_lane_zt_u32_2( +// CHECK-SAME: [[V:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.sme.write.lane.zt.nxv4i32(i32 0, [[V]], i32 2) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: define dso_local void @_Z24test_write_lane_zt_u32_2u12__SVUint32_t( +// CPP-CHECK-SAME: [[V:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: [[ENTRY:.*:]] +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sme.write.lane.zt.nxv4i32(i32 0, [[V]], i32 2) +// CPP-CHECK-NEXT: ret void +// +void test_write_lane_zt_u32_2(svuint32_t v) __arm_streaming __arm_inout("zt0") { + SVE_ACLE_FUNC(svwrite_lane_zt, _u32)(0, v, 2); +} + +// CHECK-LABEL: define dso_local void @test_write_lane_zt_s32_3( +// CHECK-SAME: [[V:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.sme.write.lane.zt.nxv4i32(i32 0, [[V]], i32 3) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: define dso_local void @_Z24test_write_lane_zt_s32_3u11__SVInt32_t( +// CPP-CHECK-SAME: [[V:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: [[ENTRY:.*:]] +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sme.write.lane.zt.nxv4i32(i32 0, [[V]], i32 3) +// CPP-CHECK-NEXT: ret void +// +void test_write_lane_zt_s32_3(svint32_t v) __arm_streaming __arm_inout("zt0") { + SVE_ACLE_FUNC(svwrite_lane_zt, _s32)(0, v, 3); +} + +// CHECK-LABEL: define dso_local void @test_write_lane_zt_u64_0( +// CHECK-SAME: [[V:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.sme.write.lane.zt.nxv2i64(i32 0, [[V]], i32 1) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: define dso_local void @_Z24test_write_lane_zt_u64_0u12__SVUint64_t( +// CPP-CHECK-SAME: [[V:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: [[ENTRY:.*:]] +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sme.write.lane.zt.nxv2i64(i32 0, [[V]], i32 1) +// CPP-CHECK-NEXT: ret void +// +void test_write_lane_zt_u64_0(svuint64_t v) __arm_streaming __arm_inout("zt0") { + SVE_ACLE_FUNC(svwrite_lane_zt, _u64)(0, v, 1); +} + +// CHECK-LABEL: define dso_local void @test_write_lane_zt_s64_1( +// CHECK-SAME: [[V:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.sme.write.lane.zt.nxv2i64(i32 0, [[V]], i32 1) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: define dso_local void @_Z24test_write_lane_zt_s64_1u11__SVInt64_t( +// CPP-CHECK-SAME: [[V:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: [[ENTRY:.*:]] +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sme.write.lane.zt.nxv2i64(i32 0, [[V]], i32 1) +// CPP-CHECK-NEXT: ret void +// +void test_write_lane_zt_s64_1(svint64_t v) __arm_streaming __arm_inout("zt0") { + SVE_ACLE_FUNC(svwrite_lane_zt, _s64)(0, v, 1); +} + +// CHECK-LABEL: define dso_local void @test_write_lane_zt_f16_2( +// CHECK-SAME: [[V:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.sme.write.lane.zt.nxv8f16(i32 0, [[V]], i32 2) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: define dso_local void @_Z24test_write_lane_zt_f16_2u13__SVFloat16_t( +// CPP-CHECK-SAME: [[V:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: [[ENTRY:.*:]] +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sme.write.lane.zt.nxv8f16(i32 0, [[V]], i32 2) +// CPP-CHECK-NEXT: ret void +// +void test_write_lane_zt_f16_2(svfloat16_t v) __arm_streaming __arm_inout("zt0") { + SVE_ACLE_FUNC(svwrite_lane_zt, _f16)(0, v, 2); +} + +// CHECK-LABEL: define dso_local void @test_write_lane_zt_bf16_3( +// CHECK-SAME: [[V:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.sme.write.lane.zt.nxv8bf16(i32 0, [[V]], i32 3) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: define dso_local void @_Z25test_write_lane_zt_bf16_3u14__SVBfloat16_t( +// CPP-CHECK-SAME: [[V:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: [[ENTRY:.*:]] +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sme.write.lane.zt.nxv8bf16(i32 0, [[V]], i32 3) +// CPP-CHECK-NEXT: ret void +// +void test_write_lane_zt_bf16_3(svbfloat16_t v) __arm_streaming __arm_inout("zt0") { + SVE_ACLE_FUNC(svwrite_lane_zt, _bf16)(0, v, 3); +} + +// CHECK-LABEL: define dso_local void @test_write_lane_zt_f32_0( +// CHECK-SAME: [[V:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.sme.write.lane.zt.nxv4f32(i32 0, [[V]], i32 2) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: define dso_local void @_Z24test_write_lane_zt_f32_0u13__SVFloat32_t( +// CPP-CHECK-SAME: [[V:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: [[ENTRY:.*:]] +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sme.write.lane.zt.nxv4f32(i32 0, [[V]], i32 2) +// CPP-CHECK-NEXT: ret void +// +void test_write_lane_zt_f32_0(svfloat32_t v) __arm_streaming __arm_inout("zt0") { + SVE_ACLE_FUNC(svwrite_lane_zt, _f32)(0, v, 2); +} + +// CHECK-LABEL: define dso_local void @test_write_lane_zt_f64_1( +// CHECK-SAME: [[V:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.sme.write.lane.zt.nxv2f64(i32 0, [[V]], i32 1) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: define dso_local void @_Z24test_write_lane_zt_f64_1u13__SVFloat64_t( +// CPP-CHECK-SAME: [[V:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: [[ENTRY:.*:]] +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sme.write.lane.zt.nxv2f64(i32 0, [[V]], i32 1) +// CPP-CHECK-NEXT: ret void +// +void test_write_lane_zt_f64_1(svfloat64_t v) __arm_streaming __arm_inout("zt0") { + SVE_ACLE_FUNC(svwrite_lane_zt, _f64)(0, v, 1); +} + +//ALIAS +// CHECK-LABEL: define dso_local void @test_write_zt_u8( +// CHECK-SAME: [[V:%.*]]) #[[ATTR2:[0-9]+]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.sme.write.zt.nxv16i8(i32 0, [[V]]) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: define dso_local void @_Z16test_write_zt_u8u11__SVUint8_t( +// CPP-CHECK-SAME: [[V:%.*]]) #[[ATTR2:[0-9]+]] { +// CPP-CHECK-NEXT: [[ENTRY:.*:]] +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sme.write.zt.nxv16i8(i32 0, [[V]]) +// CPP-CHECK-NEXT: ret void +// +void test_write_zt_u8(svuint8_t v) __arm_streaming __arm_out("zt0") { + SVE_ACLE_FUNC(svwrite_zt, _u8)(0, v); +} + +// CHECK-LABEL: define dso_local void @test_write_zt_s8( +// CHECK-SAME: [[V:%.*]]) #[[ATTR2]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.sme.write.zt.nxv16i8(i32 0, [[V]]) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: define dso_local void @_Z16test_write_zt_s8u10__SVInt8_t( +// CPP-CHECK-SAME: [[V:%.*]]) #[[ATTR2]] { +// CPP-CHECK-NEXT: [[ENTRY:.*:]] +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sme.write.zt.nxv16i8(i32 0, [[V]]) +// CPP-CHECK-NEXT: ret void +// +void test_write_zt_s8(svint8_t v) __arm_streaming __arm_out("zt0") { + SVE_ACLE_FUNC(svwrite_zt, _s8)(0, v); +} + +// CHECK-LABEL: define dso_local void @test_write_zt_u16( +// CHECK-SAME: [[V:%.*]]) #[[ATTR2]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.sme.write.zt.nxv8i16(i32 0, [[V]]) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: define dso_local void @_Z17test_write_zt_u16u12__SVUint16_t( +// CPP-CHECK-SAME: [[V:%.*]]) #[[ATTR2]] { +// CPP-CHECK-NEXT: [[ENTRY:.*:]] +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sme.write.zt.nxv8i16(i32 0, [[V]]) +// CPP-CHECK-NEXT: ret void +// +void test_write_zt_u16(svuint16_t v) __arm_streaming __arm_out("zt0") { + SVE_ACLE_FUNC(svwrite_zt, _u16)(0, v); +} + +// CHECK-LABEL: define dso_local void @test_write_zt_s16( +// CHECK-SAME: [[V:%.*]]) #[[ATTR2]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.sme.write.zt.nxv8i16(i32 0, [[V]]) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: define dso_local void @_Z17test_write_zt_s16u11__SVInt16_t( +// CPP-CHECK-SAME: [[V:%.*]]) #[[ATTR2]] { +// CPP-CHECK-NEXT: [[ENTRY:.*:]] +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sme.write.zt.nxv8i16(i32 0, [[V]]) +// CPP-CHECK-NEXT: ret void +// +void test_write_zt_s16(svint16_t v) __arm_streaming __arm_out("zt0") { + SVE_ACLE_FUNC(svwrite_zt, _s16)(0, v); +} + +// CHECK-LABEL: define dso_local void @test_write_zt_u32( +// CHECK-SAME: [[V:%.*]]) #[[ATTR2]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.sme.write.zt.nxv4i32(i32 0, [[V]]) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: define dso_local void @_Z17test_write_zt_u32u12__SVUint32_t( +// CPP-CHECK-SAME: [[V:%.*]]) #[[ATTR2]] { +// CPP-CHECK-NEXT: [[ENTRY:.*:]] +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sme.write.zt.nxv4i32(i32 0, [[V]]) +// CPP-CHECK-NEXT: ret void +// +void test_write_zt_u32(svuint32_t v) __arm_streaming __arm_out("zt0") { + SVE_ACLE_FUNC(svwrite_zt, _u32)(0, v); +} + +// CHECK-LABEL: define dso_local void @test_write_zt_s32( +// CHECK-SAME: [[V:%.*]]) #[[ATTR2]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.sme.write.zt.nxv4i32(i32 0, [[V]]) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: define dso_local void @_Z17test_write_zt_s32u11__SVInt32_t( +// CPP-CHECK-SAME: [[V:%.*]]) #[[ATTR2]] { +// CPP-CHECK-NEXT: [[ENTRY:.*:]] +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sme.write.zt.nxv4i32(i32 0, [[V]]) +// CPP-CHECK-NEXT: ret void +// +void test_write_zt_s32(svint32_t v) __arm_streaming __arm_out("zt0") { + SVE_ACLE_FUNC(svwrite_zt, _s32)(0, v); +} + +// CHECK-LABEL: define dso_local void @test_write_zt_u64( +// CHECK-SAME: [[V:%.*]]) #[[ATTR2]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.sme.write.zt.nxv2i64(i32 0, [[V]]) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: define dso_local void @_Z17test_write_zt_u64u12__SVUint64_t( +// CPP-CHECK-SAME: [[V:%.*]]) #[[ATTR2]] { +// CPP-CHECK-NEXT: [[ENTRY:.*:]] +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sme.write.zt.nxv2i64(i32 0, [[V]]) +// CPP-CHECK-NEXT: ret void +// +void test_write_zt_u64(svuint64_t v) __arm_streaming __arm_out("zt0") { + SVE_ACLE_FUNC(svwrite_zt, _u64)(0, v); +} + +// CHECK-LABEL: define dso_local void @test_write_zt_s64( +// CHECK-SAME: [[V:%.*]]) #[[ATTR2]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.sme.write.zt.nxv2i64(i32 0, [[V]]) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: define dso_local void @_Z17test_write_zt_s64u11__SVInt64_t( +// CPP-CHECK-SAME: [[V:%.*]]) #[[ATTR2]] { +// CPP-CHECK-NEXT: [[ENTRY:.*:]] +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sme.write.zt.nxv2i64(i32 0, [[V]]) +// CPP-CHECK-NEXT: ret void +// +void test_write_zt_s64(svint64_t v) __arm_streaming __arm_out("zt0") { + SVE_ACLE_FUNC(svwrite_zt, _s64)(0, v); +} + +// CHECK-LABEL: define dso_local void @test_write_zt_f16( +// CHECK-SAME: [[V:%.*]]) #[[ATTR2]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.sme.write.zt.nxv8f16(i32 0, [[V]]) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: define dso_local void @_Z17test_write_zt_f16u13__SVFloat16_t( +// CPP-CHECK-SAME: [[V:%.*]]) #[[ATTR2]] { +// CPP-CHECK-NEXT: [[ENTRY:.*:]] +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sme.write.zt.nxv8f16(i32 0, [[V]]) +// CPP-CHECK-NEXT: ret void +// +void test_write_zt_f16(svfloat16_t v) __arm_streaming __arm_out("zt0") { + SVE_ACLE_FUNC(svwrite_zt, _f16)(0, v); +} + +// CHECK-LABEL: define dso_local void @test_write_zt_bf16( +// CHECK-SAME: [[V:%.*]]) #[[ATTR2]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.sme.write.zt.nxv8bf16(i32 0, [[V]]) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: define dso_local void @_Z18test_write_zt_bf16u14__SVBfloat16_t( +// CPP-CHECK-SAME: [[V:%.*]]) #[[ATTR2]] { +// CPP-CHECK-NEXT: [[ENTRY:.*:]] +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sme.write.zt.nxv8bf16(i32 0, [[V]]) +// CPP-CHECK-NEXT: ret void +// +void test_write_zt_bf16(svbfloat16_t v) __arm_streaming __arm_out("zt0") { + SVE_ACLE_FUNC(svwrite_zt, _bf16)(0, v); +} + +// CHECK-LABEL: define dso_local void @test_write_zt_f32( +// CHECK-SAME: [[V:%.*]]) #[[ATTR2]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.sme.write.zt.nxv4f32(i32 0, [[V]]) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: define dso_local void @_Z17test_write_zt_f32u13__SVFloat32_t( +// CPP-CHECK-SAME: [[V:%.*]]) #[[ATTR2]] { +// CPP-CHECK-NEXT: [[ENTRY:.*:]] +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sme.write.zt.nxv4f32(i32 0, [[V]]) +// CPP-CHECK-NEXT: ret void +// +void test_write_zt_f32(svfloat32_t v) __arm_streaming __arm_out("zt0") { + SVE_ACLE_FUNC(svwrite_zt, _f32)(0, v); +} + +// CHECK-LABEL: define dso_local void @test_write__zt_f64( +// CHECK-SAME: [[V:%.*]]) #[[ATTR2]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: tail call void @llvm.aarch64.sme.write.zt.nxv2f64(i32 0, [[V]]) +// CHECK-NEXT: ret void +// +// CPP-CHECK-LABEL: define dso_local void @_Z18test_write__zt_f64u13__SVFloat64_t( +// CPP-CHECK-SAME: [[V:%.*]]) #[[ATTR2]] { +// CPP-CHECK-NEXT: [[ENTRY:.*:]] +// CPP-CHECK-NEXT: tail call void @llvm.aarch64.sme.write.zt.nxv2f64(i32 0, [[V]]) +// CPP-CHECK-NEXT: ret void +// +void test_write__zt_f64(svfloat64_t v) __arm_streaming __arm_out("zt0") { + SVE_ACLE_FUNC(svwrite_zt, _f64)(0, v); +} diff --git a/clang/test/CodeGen/tbaa-pointers.c b/clang/test/CodeGen/tbaa-pointers.c index 75d8c3d501750..8860b7042d0a2 100644 --- a/clang/test/CodeGen/tbaa-pointers.c +++ b/clang/test/CodeGen/tbaa-pointers.c @@ -116,17 +116,43 @@ void p2struct(struct S1 **ptr) { // COMMON-LABEL: define void @p2struct( // COMMON-SAME: ptr noundef [[PTR:%.+]]) // COMMON: [[PTR_ADDR:%.+]] = alloca ptr, align 8 - // ENABLED-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8, !tbaa [[P2S1_0:!.+]] - // ENABLED-NEXT: [[BASE:%.+]] = load ptr, ptr [[PTR_ADDR]], align 8, !tbaa [[P2S1_0]] - // ENABLED-NEXT: store ptr null, ptr [[BASE]], align 8, !tbaa [[P1S1_:!.+]] - // DEFAULT-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8, !tbaa [[ANYPTR]] - // DEFAULT-NEXT: [[BASE:%.+]] = load ptr, ptr [[PTR_ADDR]], align 8, !tbaa [[ANYPTR]] - // DEFAULT-NEXT: store ptr null, ptr [[BASE]], align 8, !tbaa [[ANYPTR]] + // ENABLED-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8, !tbaa [[ANYPTR:!.+]] + // DEFAULT-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8, !tbaa [[ANYPTR]] + // COMMON-NEXT: [[BASE:%.+]] = load ptr, ptr [[PTR_ADDR]], align 8, !tbaa [[ANYPTR]] + // COMMON-NEXT: store ptr null, ptr [[BASE]], align 8, !tbaa [[ANYPTR]] + // COMMON-NEXT: ret void + // + *ptr = 0; +} + +void p2struct_const(struct S1 const **ptr) { + // COMMON-LABEL: define void @p2struct_const( + // COMMON-SAME: ptr noundef [[PTR:%.+]]) + // COMMON: [[PTR_ADDR:%.+]] = alloca ptr, align 8 + // COMMON-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8, !tbaa [[ANYPTR]] + // COMMON-NEXT: [[BASE:%.+]] = load ptr, ptr [[PTR_ADDR]], align 8, !tbaa [[ANYPTR]] + // COMMON-NEXT: store ptr null, ptr [[BASE]], align 8, !tbaa [[ANYPTR]] // COMMON-NEXT: ret void // *ptr = 0; } +struct S2 { + struct S1 *s; +}; + +void p2struct2(struct S2 *ptr) { + // COMMON-LABEL: define void @p2struct2( + // COMMON-SAME: ptr noundef [[PTR:%.+]]) + // COMMON: [[PTR_ADDR:%.+]] = alloca ptr, align 8 + // COMMON-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8, !tbaa [[ANYPTR]] + // COMMON-NEXT: [[BASE:%.+]] = load ptr, ptr [[PTR_ADDR]], align 8, !tbaa [[ANYPTR]] + // COMMON-NEXT: [[S:%.+]] = getelementptr inbounds nuw %struct.S2, ptr [[BASE]], i32 0, i32 0 + // COMMON-NEXT: store ptr null, ptr [[S]], align 8, !tbaa [[S2_S_TAG:!.+]] + // COMMON-NEXT: ret void + ptr->s = 0; +} + // ENABLED: [[P2INT_0]] = !{[[P2INT:!.+]], [[P2INT]], i64 0} // ENABLED: [[P2INT]] = !{!"p2 int", [[ANY_POINTER:!.+]], i64 0} // DEFAULT: [[ANYPTR]] = !{[[ANY_POINTER:!.+]], [[ANY_POINTER]], i64 0} @@ -145,3 +171,5 @@ void p2struct(struct S1 **ptr) { // ENABLED: [[P2CHAR]] = !{!"p2 omnipotent char", [[ANY_POINTER]], i64 0} // ENABLED: [[P1CHAR_0]] = !{[[P1CHAR:!.+]], [[P1CHAR]], i64 0} // ENABLED: [[P1CHAR]] = !{!"p1 omnipotent char", [[ANY_POINTER]], i64 0} +// COMMON: [[S2_S_TAG]] = !{[[S2_TY:!.+]], [[ANY_POINTER]], i64 0} +// COMMON: [[S2_TY]] = !{!"S2", [[ANY_POINTER]], i64 0} diff --git a/clang/test/CodeGen/tbaa-reference.cpp b/clang/test/CodeGen/tbaa-reference.cpp index c4d9e70a8b07f..d22cd90b43ae9 100644 --- a/clang/test/CodeGen/tbaa-reference.cpp +++ b/clang/test/CodeGen/tbaa-reference.cpp @@ -1,5 +1,7 @@ // RUN: %clang_cc1 -triple x86_64-linux -O1 -disable-llvm-passes %s -emit-llvm -o - | FileCheck %s -check-prefixes=CHECK,OLD-PATH +// RUN: %clang_cc1 -triple x86_64-linux -O1 -disable-llvm-passes -pointer-tbaa %s -emit-llvm -o - | FileCheck %s -check-prefixes=CHECK,OLD-PATH // RUN: %clang_cc1 -triple x86_64-linux -O1 -disable-llvm-passes %s -emit-llvm -new-struct-path-tbaa -o - | FileCheck %s -check-prefixes=CHECK,NEW-PATH +// RUN: %clang_cc1 -triple x86_64-linux -O1 -disable-llvm-passes %s -pointer-tbaa -emit-llvm -new-struct-path-tbaa -o - | FileCheck %s -check-prefixes=CHECK,NEW-PATH // // Check that we generate correct TBAA information for reference accesses. diff --git a/clang/test/CodeGenHLSL/builtins/wave_get_lane_index_do_while.hlsl b/clang/test/CodeGenHLSL/builtins/wave_get_lane_index_do_while.hlsl index 9481b0d60a272..6b053dc6add1f 100644 --- a/clang/test/CodeGenHLSL/builtins/wave_get_lane_index_do_while.hlsl +++ b/clang/test/CodeGenHLSL/builtins/wave_get_lane_index_do_while.hlsl @@ -1,7 +1,7 @@ // RUN: %clang_cc1 -std=hlsl2021 -finclude-default-header -x hlsl -triple \ // RUN: spirv-pc-vulkan-library %s -emit-llvm -disable-llvm-passes -o - | FileCheck %s -// CHECK: define spir_func void @main() [[A0:#[0-9]+]] { +// CHECK: define spir_func void @{{.*main.*}}() [[A0:#[0-9]+]] { void main() { // CHECK: entry: // CHECK: %[[CT_ENTRY:[0-9]+]] = call token @llvm.experimental.convergence.entry() diff --git a/clang/test/CodeGenHLSL/entry.hlsl b/clang/test/CodeGenHLSL/entry.hlsl index ec4254e76fb66..cd3bf948df48c 100644 --- a/clang/test/CodeGenHLSL/entry.hlsl +++ b/clang/test/CodeGenHLSL/entry.hlsl @@ -2,6 +2,10 @@ // RUN: dxil-pc-shadermodel6.3-compute %s -hlsl-entry foo \ // RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s +// RUN: %clang_cc1 -std=hlsl2021 -finclude-default-header -x hlsl -triple \ +// RUN: spirv-unknown-vulkan-compute %s -hlsl-entry foo \ +// RUN: -emit-llvm -disable-llvm-passes -o - | FileCheck %s + // Make sure not mangle entry. // CHECK:define void @foo() // Make sure add function attribute and numthreads attribute. diff --git a/clang/test/CodeGenHLSL/semantics/DispatchThreadID.hlsl b/clang/test/CodeGenHLSL/semantics/DispatchThreadID.hlsl index 59c1620334d0e..975a7264fd3f0 100644 --- a/clang/test/CodeGenHLSL/semantics/DispatchThreadID.hlsl +++ b/clang/test/CodeGenHLSL/semantics/DispatchThreadID.hlsl @@ -6,7 +6,8 @@ // CHECK: define void @foo() // CHECK-DXIL: %[[#ID:]] = call i32 @llvm.[[TARGET]].thread.id(i32 0) // CHECK-SPIRV: %[[#ID:]] = call i32 @llvm.[[TARGET]].thread.id(i32 0) -// CHECK: call void @{{.*}}foo{{.*}}(i32 %[[#ID]]) +// CHECK-DXIL: call void @{{.*}}foo{{.*}}(i32 %[[#ID]]) +// CHECK-SPIRV: call spir_func void @{{.*}}foo{{.*}}(i32 %[[#ID]]) [shader("compute")] [numthreads(8,8,1)] void foo(uint Idx : SV_DispatchThreadID) {} @@ -17,6 +18,7 @@ void foo(uint Idx : SV_DispatchThreadID) {} // CHECK: %[[#ID_Y:]] = call i32 @llvm.[[TARGET]].thread.id(i32 1) // CHECK: %[[#ID_XY:]] = insertelement <2 x i32> %[[#ID_X_]], i32 %[[#ID_Y]], i64 1 // CHECK-DXIL: call void @{{.*}}bar{{.*}}(<2 x i32> %[[#ID_XY]]) +// CHECK-SPIRV: call spir_func void @{{.*}}bar{{.*}}(<2 x i32> %[[#ID_XY]]) [shader("compute")] [numthreads(8,8,1)] void bar(uint2 Idx : SV_DispatchThreadID) {} diff --git a/clang/test/Driver/dxc_E.hlsl b/clang/test/Driver/dxc_E.hlsl index 05cfca685c9a6..07715a2e2259a 100644 --- a/clang/test/Driver/dxc_E.hlsl +++ b/clang/test/Driver/dxc_E.hlsl @@ -1,4 +1,5 @@ // RUN: not %clang_dxc -Efoo -Tlib_6_7 foo.hlsl -### %s 2>&1 | FileCheck %s +// RUN: not %clang_dxc -Efoo -Tlib_6_7 -spirv foo.hlsl -### %s 2>&1 | FileCheck %s // Make sure E option flag which translated into "-hlsl-entry". // CHECK:"-hlsl-entry" "foo" diff --git a/clang/test/Frontend/amdgcn-machine-analysis-remarks.cl b/clang/test/Frontend/amdgcn-machine-analysis-remarks.cl index a05e21b37b912..f15130d5f8b61 100644 --- a/clang/test/Frontend/amdgcn-machine-analysis-remarks.cl +++ b/clang/test/Frontend/amdgcn-machine-analysis-remarks.cl @@ -2,7 +2,7 @@ // RUN: %clang_cc1 -triple amdgcn-amd-amdhsa -target-cpu gfx908 -Rpass-analysis=kernel-resource-usage -S -O0 -verify %s -o /dev/null // expected-remark@+10 {{Function Name: foo}} -// expected-remark@+9 {{ SGPRs: 13}} +// expected-remark@+9 {{ TotalSGPRs: 13}} // expected-remark@+8 {{ VGPRs: 10}} // expected-remark@+7 {{ AGPRs: 12}} // expected-remark@+6 {{ ScratchSize [bytes/lane]: 0}} diff --git a/clang/test/Frontend/fixed_point_comparisons.c b/clang/test/Frontend/fixed_point_comparisons.c index 59c4405e41c03..39e62bce51e2b 100644 --- a/clang/test/Frontend/fixed_point_comparisons.c +++ b/clang/test/Frontend/fixed_point_comparisons.c @@ -1,6 +1,9 @@ // RUN: %clang_cc1 -ffixed-point -triple x86_64-unknown-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefixes=CHECK,UNPADDED // RUN: %clang_cc1 -ffixed-point -triple x86_64-unknown-linux-gnu -fpadding-on-unsigned-fixed-point -emit-llvm %s -o - | FileCheck %s --check-prefixes=CHECK,PADDED +// RUN: %clang_cc1 -ffixed-point -triple x86_64-unknown-linux-gnu -emit-llvm %s -o - -fexperimental-new-constant-interpreter | FileCheck %s --check-prefixes=CHECK,UNPADDED +// RUN: %clang_cc1 -ffixed-point -triple x86_64-unknown-linux-gnu -fpadding-on-unsigned-fixed-point -emit-llvm %s -o - -fexperimental-new-constant-interpreter | FileCheck %s --check-prefixes=CHECK,PADDED + // Fixed point against other fixed point _Bool b_eq_true = 2.5hk == 2.5uhk; // CHECK-DAG: @b_eq_true = {{.*}}global i8 1, align 1 _Bool b_eq_false = 2.5hk == 2.4uhk; // CHECK-DAG: @b_eq_false = {{.*}}global i8 0, align 1 diff --git a/clang/test/Frontend/fixed_point_crash.c b/clang/test/Frontend/fixed_point_crash.c index 3b3911117400c..9cfe6ba64c519 100644 --- a/clang/test/Frontend/fixed_point_crash.c +++ b/clang/test/Frontend/fixed_point_crash.c @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -verify -ffixed-point %s +// RUN: %clang_cc1 -verify -ffixed-point %s -fexperimental-new-constant-interpreter union a { _Accum x; diff --git a/clang/test/Frontend/fixed_point_div_const.c b/clang/test/Frontend/fixed_point_div_const.c index 46935207d186a..66c028e608db6 100644 --- a/clang/test/Frontend/fixed_point_div_const.c +++ b/clang/test/Frontend/fixed_point_div_const.c @@ -1,6 +1,9 @@ // RUN: %clang_cc1 -ffixed-point -triple x86_64-unknown-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefixes=CHECK,SIGNED // RUN: %clang_cc1 -ffixed-point -triple x86_64-unknown-linux-gnu -fpadding-on-unsigned-fixed-point -emit-llvm %s -o - | FileCheck %s --check-prefixes=CHECK,UNSIGNED +// RUN: %clang_cc1 -ffixed-point -triple x86_64-unknown-linux-gnu -emit-llvm %s -o - -fexperimental-new-constant-interpreter | FileCheck %s --check-prefixes=CHECK,SIGNED +// RUN: %clang_cc1 -ffixed-point -triple x86_64-unknown-linux-gnu -fpadding-on-unsigned-fixed-point -emit-llvm %s -o - -fexperimental-new-constant-interpreter | FileCheck %s --check-prefixes=CHECK,UNSIGNED + // Division between different fixed point types short _Accum sa_const = 1.0hk / 2.0hk; // CHECK-DAG: @sa_const = {{.*}}global i16 64, align 2 diff --git a/clang/test/Options/enable_16bit_types_validation_spirv.hlsl b/clang/test/Options/enable_16bit_types_validation_spirv.hlsl index aeb7a8369f403..aad8836db1062 100644 --- a/clang/test/Options/enable_16bit_types_validation_spirv.hlsl +++ b/clang/test/Options/enable_16bit_types_validation_spirv.hlsl @@ -4,7 +4,7 @@ // SPIRV: error: '-fnative-half-type' option requires target HLSL Version >= 2018, but HLSL Version is 'hlsl2016' // valid: "spirv-unknown-vulkan-library" -// valid: define spir_func void @main() #0 { +// valid: define spir_func void @{{.*main.*}}() #0 { [numthreads(1,1,1)] void main() diff --git a/clang/test/ParserOpenACC/parse-clauses.c b/clang/test/ParserOpenACC/parse-clauses.c index 15c4554a31922..6c9ce4ad5e196 100644 --- a/clang/test/ParserOpenACC/parse-clauses.c +++ b/clang/test/ParserOpenACC/parse-clauses.c @@ -105,17 +105,14 @@ void func() { #pragma acc loop collapse(force:) for(;;){} - // expected-error@+2{{invalid tag 'unknown' on 'collapse' clause}} - // expected-warning@+1{{OpenACC clause 'collapse' not yet implemented, clause ignored}} -#pragma acc loop collapse(unknown:5) + // expected-error@+1{{invalid tag 'unknown' on 'collapse' clause}} +#pragma acc loop collapse(unknown:1) for(;;){} - // expected-warning@+1{{OpenACC clause 'collapse' not yet implemented, clause ignored}} -#pragma acc loop collapse(force:5) +#pragma acc loop collapse(force:1) for(;;){} - // expected-warning@+1{{OpenACC clause 'collapse' not yet implemented, clause ignored}} -#pragma acc loop collapse(5) +#pragma acc loop collapse(1) for(;;){} // expected-error@+2{{expected ')'}} diff --git a/clang/test/ParserOpenACC/parse-clauses.cpp b/clang/test/ParserOpenACC/parse-clauses.cpp index b7e252e892bea..9613530db77dd 100644 --- a/clang/test/ParserOpenACC/parse-clauses.cpp +++ b/clang/test/ParserOpenACC/parse-clauses.cpp @@ -2,13 +2,23 @@ template void templ() { - // expected-warning@+1{{OpenACC clause 'collapse' not yet implemented, clause ignored}} #pragma acc loop collapse(I) - for(;;){} + for(;;) + for(;;) + for(;;) + for(;;) + for(;;) + for(;;) + for(;;); - // expected-warning@+1{{OpenACC clause 'collapse' not yet implemented, clause ignored}} #pragma acc loop collapse(T::value) - for(;;){} + for(;;) + for(;;) + for(;;) + for(;;) + for(;;) + for(;;) + for(;;); #pragma acc parallel vector_length(T::value) for(;;){} diff --git a/clang/test/Sema/aarch64-sme2-intrinsics/acle_sme2_imm.cpp b/clang/test/Sema/aarch64-sme2-intrinsics/acle_sme2_imm.cpp index 5de97649af5d3..6f64bbf22dc66 100644 --- a/clang/test/Sema/aarch64-sme2-intrinsics/acle_sme2_imm.cpp +++ b/clang/test/Sema/aarch64-sme2-intrinsics/acle_sme2_imm.cpp @@ -1,5 +1,5 @@ // RUN: %clang_cc1 -triple aarch64-none-linux-gnu \ -// RUN: -target-feature +bf16 -target-feature +sve -target-feature +sme -target-feature +sve2 -target-feature +sme2 -target-feature +sme-i16i64 -target-feature +sme-f64f64 -fsyntax-only -verify %s +// RUN: -target-feature +bf16 -target-feature +sve -target-feature +sme -target-feature +sve2 -target-feature +sme2 -target-feature +sme-i16i64 -target-feature +sme-f64f64 -target-feature +sme-lutv2 -fsyntax-only -verify %s // REQUIRES: aarch64-registered-target @@ -350,3 +350,17 @@ void test_svdot_multi_za32_bad_lane(uint32_t slice_base, svuint16_t z_u16, svsudot_lane_za32_s8_vg1x2(slice_base, z_s8x2, z_u8, 4); // expected-error {{argument value 4 is outside the valid range [0, 3]}} svsudot_lane_za32_s8_vg1x4(slice_base, z_s8x4, z_u8, 4); // expected-error {{argument value 4 is outside the valid range [0, 3]}} } + +void test_write_zt() __arm_streaming __arm_inout("zt0") { + // Check Zt tile 0 + svwrite_lane_zt(1, svundef_s8(), 1); // expected-error {{argument value 1 is outside the valid range [0, 0]}} + svwrite_zt(1, svundef_s8()); // expected-error {{argument value 1 is outside the valid range [0, 0]}} + // Check index + svwrite_lane_zt(0, svundef_s8(), 0); // expected-error {{argument value 0 is outside the valid range [1, 3]}} + svwrite_lane_zt(0, svundef_s8(), 4); // expected-error {{argument value 4 is outside the valid range [1, 3]}} +} + +void test_luti4_zt_x4(svuint8x2_t op) __arm_streaming __arm_in("zt0") { + // Check Zt tile 0 + svluti4_zt_u8_x4(1, op); // expected-error {{argument value 1 is outside the valid range [0, 0]}} +} diff --git a/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp b/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp index c6272a775a28f..731639ab16a73 100644 --- a/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp +++ b/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp @@ -713,7 +713,7 @@ struct [[gsl::Pointer]] Span { // Pointer from Owner std::string_view test5() { std::string_view a = StatusOr().valueLB(); // expected-warning {{object backing the pointer will be dest}} -return StatusOr().valueLB(); // expected-warning {{returning address of local temporary}} + return StatusOr().valueLB(); // expected-warning {{returning address of local temporary}} // No dangling diagnostics on non-lifetimebound methods. std::string_view b = StatusOr().valueNoLB(); @@ -724,6 +724,7 @@ return StatusOr().valueLB(); // expected-warning {{returning a // Prevent regression GH108463 Span test6(std::vector v) { Span dangling = std::vector(); // expected-warning {{object backing the pointer}} + dangling = std::vector(); // expected-warning {{object backing the pointer}} return v; // expected-warning {{address of stack memory}} } diff --git a/clang/test/SemaCXX/fold_lambda_with_variadics.cpp b/clang/test/SemaCXX/fold_lambda_with_variadics.cpp index 14e242f009dc5..2257a4c2d975a 100644 --- a/clang/test/SemaCXX/fold_lambda_with_variadics.cpp +++ b/clang/test/SemaCXX/fold_lambda_with_variadics.cpp @@ -179,3 +179,57 @@ void foo() { } } // namespace GH99877 + +namespace GH101754 { + +template struct Overloaded : Ts... { + using Ts::operator()...; +}; + +template Overloaded(Ts...) -> Overloaded; + +template +concept same_as = __is_same(T, U); // #same_as + +template constexpr auto foo() { + return Overloaded{[](same_as auto value) { return value; }...}; // #lambda +} + +static_assert(foo()(123) == 123); +static_assert(foo()(2.718) == 2.718); + +static_assert(foo()('c')); +// expected-error@-1 {{no matching function}} + +// expected-note@#lambda {{constraints not satisfied}} +// expected-note@#lambda {{'same_as' evaluated to false}} +// expected-note@#same_as {{evaluated to false}} + +// expected-note@#lambda {{constraints not satisfied}} +// expected-note@#lambda {{'same_as' evaluated to false}} +// expected-note@#same_as {{evaluated to false}} + +template +concept C = same_as && same_as; // #C + +template constexpr auto bar() { + return ([]() { + return Overloaded{[](C auto value) { // #bar + return value; + }...}; + }.template operator()(), ...); +} +static_assert(bar()(3.14f)); // OK, bar() returns the last overload i.e. . + +static_assert(bar()(123)); +// expected-error@-1 {{no matching function}} +// expected-note@#bar {{constraints not satisfied}} +// expected-note@#bar {{'C' evaluated to false}} +// expected-note@#C {{evaluated to false}} + +// expected-note@#bar {{constraints not satisfied}} +// expected-note@#bar {{'C' evaluated to false}} +// expected-note@#C {{evaluated to false}} +// expected-note@#same_as 2{{evaluated to false}} + +} // namespace GH101754 diff --git a/clang/test/SemaOpenACC/compute-construct-device_type-clause.c b/clang/test/SemaOpenACC/compute-construct-device_type-clause.c index b300abe577801..26f0315fb86f1 100644 --- a/clang/test/SemaOpenACC/compute-construct-device_type-clause.c +++ b/clang/test/SemaOpenACC/compute-construct-device_type-clause.c @@ -188,8 +188,7 @@ void uses() { // expected-note@+1{{previous clause is here}} #pragma acc serial device_type(*) reduction(+:Var) while(1); - // expected-error@+2{{OpenACC clause 'collapse' may not follow a 'device_type' clause in a compute construct}} - // expected-note@+1{{previous clause is here}} + // expected-error@+1{{OpenACC 'collapse' clause is not valid on 'kernels' directive}} #pragma acc kernels device_type(*) collapse(1) while(1); // expected-error@+2{{OpenACC clause 'bind' may not follow a 'device_type' clause in a compute construct}} diff --git a/clang/test/SemaOpenACC/loop-construct-auto_seq_independent-clauses.c b/clang/test/SemaOpenACC/loop-construct-auto_seq_independent-clauses.c index ac61976ff620d..3212c19d089fc 100644 --- a/clang/test/SemaOpenACC/loop-construct-auto_seq_independent-clauses.c +++ b/clang/test/SemaOpenACC/loop-construct-auto_seq_independent-clauses.c @@ -138,7 +138,6 @@ void uses() { // expected-warning@+1{{OpenACC clause 'reduction' not yet implemented}} #pragma acc loop auto reduction(+:Var) for(;;); - // expected-warning@+1{{OpenACC clause 'collapse' not yet implemented}} #pragma acc loop auto collapse(1) for(;;); // expected-warning@+1{{OpenACC clause 'bind' not yet implemented}} @@ -277,7 +276,6 @@ void uses() { // expected-warning@+1{{OpenACC clause 'reduction' not yet implemented}} #pragma acc loop reduction(+:Var) auto for(;;); - // expected-warning@+1{{OpenACC clause 'collapse' not yet implemented}} #pragma acc loop collapse(1) auto for(;;); // expected-warning@+1{{OpenACC clause 'bind' not yet implemented}} @@ -417,7 +415,6 @@ void uses() { // expected-warning@+1{{OpenACC clause 'reduction' not yet implemented}} #pragma acc loop independent reduction(+:Var) for(;;); - // expected-warning@+1{{OpenACC clause 'collapse' not yet implemented}} #pragma acc loop independent collapse(1) for(;;); // expected-warning@+1{{OpenACC clause 'bind' not yet implemented}} @@ -556,7 +553,6 @@ void uses() { // expected-warning@+1{{OpenACC clause 'reduction' not yet implemented}} #pragma acc loop reduction(+:Var) independent for(;;); - // expected-warning@+1{{OpenACC clause 'collapse' not yet implemented}} #pragma acc loop collapse(1) independent for(;;); // expected-warning@+1{{OpenACC clause 'bind' not yet implemented}} @@ -705,7 +701,6 @@ void uses() { // expected-warning@+1{{OpenACC clause 'reduction' not yet implemented}} #pragma acc loop seq reduction(+:Var) for(;;); - // expected-warning@+1{{OpenACC clause 'collapse' not yet implemented}} #pragma acc loop seq collapse(1) for(;;); // expected-warning@+1{{OpenACC clause 'bind' not yet implemented}} @@ -853,7 +848,6 @@ void uses() { // expected-warning@+1{{OpenACC clause 'reduction' not yet implemented}} #pragma acc loop reduction(+:Var) seq for(;;); - // expected-warning@+1{{OpenACC clause 'collapse' not yet implemented}} #pragma acc loop collapse(1) seq for(;;); // expected-warning@+1{{OpenACC clause 'bind' not yet implemented}} diff --git a/clang/test/SemaOpenACC/loop-construct-collapse-ast.cpp b/clang/test/SemaOpenACC/loop-construct-collapse-ast.cpp new file mode 100644 index 0000000000000..3bdcfbf95b96c --- /dev/null +++ b/clang/test/SemaOpenACC/loop-construct-collapse-ast.cpp @@ -0,0 +1,158 @@ +// RUN: %clang_cc1 %s -fopenacc -ast-dump | FileCheck %s + +// Test this with PCH. +// RUN: %clang_cc1 %s -fopenacc -emit-pch -o %t %s +// RUN: %clang_cc1 %s -fopenacc -include-pch %t -ast-dump-all | FileCheck %s +#ifndef PCH_HELPER +#define PCH_HELPER + +struct S { + constexpr S(){}; + constexpr operator auto() {return 1;} +}; + +void NormalUses() { + // CHECK: FunctionDecl{{.*}}NormalUses + // CHECK-NEXT: CompoundStmt + +#pragma acc loop collapse(1) + for(;;); + // CHECK-NEXT: OpenACCLoopConstruct + // CHECK-NEXT: collapse clause + // CHECK-NEXT: ConstantExpr{{.*}}'int' + // CHECK-NEXT: value: Int 1 + // CHECK-NEXT: IntegerLiteral{{.*}} 'int' 1 + // CHECK-NEXT: ForStmt + // CHECK-NEXT: <<>> + // CHECK-NEXT: <<>> + // CHECK-NEXT: <<>> + // CHECK-NEXT: <<>> + // CHECK-NEXT: NullStmt + +#pragma acc loop collapse(force:S{}) + for(;;); + // CHECK-NEXT: OpenACCLoopConstruct + // CHECK-NEXT: collapse clause + // CHECK-NEXT: ConstantExpr{{.*}}'int' + // CHECK-NEXT: value: Int 1 + // CHECK-NEXT: ImplicitCastExpr{{.*}} 'int' + // CHECK-NEXT: CXXMemberCallExpr{{.*}} 'int' + // CHECK-NEXT: MemberExpr{{.*}} .operator auto + // CHECK-NEXT: MaterializeTemporaryExpr{{.*}}'S' lvalue + // CHECK-NEXT: CXXTemporaryObjectExpr{{.*}}'S' 'void ()' list + // CHECK-NEXT: ForStmt + // CHECK-NEXT: <<>> + // CHECK-NEXT: <<>> + // CHECK-NEXT: <<>> + // CHECK-NEXT: <<>> + // CHECK-NEXT: NullStmt +} + +template +void TemplUses() { + // CHECK: FunctionTemplateDecl{{.*}}TemplUses + // CHECK-NEXT: TemplateTypeParmDecl {{.*}} referenced typename depth 0 index 0 T + // CHECK-NEXT: NonTypeTemplateParmDecl{{.*}} referenced 'unsigned int' depth 0 index 1 Value + // CHECK-NEXT: FunctionDecl{{.*}} TemplUses 'void ()' + // CHECK-NEXT: CompoundStmt + +#pragma acc loop collapse(Value) + for(;;) + for(;;); + // CHECK-NEXT: OpenACCLoopConstruct + // CHECK-NEXT: collapse clause + // CHECK-NEXT: DeclRefExpr{{.*}} 'unsigned int' NonTypeTemplateParm{{.*}} 'Value' + // CHECK-NEXT: ForStmt + // CHECK-NEXT: <<>> + // CHECK-NEXT: <<>> + // CHECK-NEXT: <<>> + // CHECK-NEXT: <<>> + // CHECK-NEXT: ForStmt + // CHECK-NEXT: <<>> + // CHECK-NEXT: <<>> + // CHECK-NEXT: <<>> + // CHECK-NEXT: <<>> + // CHECK-NEXT: NullStmt + +#pragma acc loop collapse(force:T{} + S{}) + for(;;) + for(;;); + // CHECK-NEXT: OpenACCLoopConstruct + // CHECK-NEXT: collapse clause + // CHECK-NEXT: BinaryOperator {{.*}}'+' + // CHECK-NEXT: CXXUnresolvedConstructExpr{{.*}}'T' 'T' list + // CHECK-NEXT: InitListExpr + // CHECK-NEXT: CXXTemporaryObjectExpr{{.*}}'S' 'void ()' list + // CHECK-NEXT: ForStmt + // CHECK-NEXT: <<>> + // CHECK-NEXT: <<>> + // CHECK-NEXT: <<>> + // CHECK-NEXT: <<>> + // CHECK-NEXT: ForStmt + // CHECK-NEXT: <<>> + // CHECK-NEXT: <<>> + // CHECK-NEXT: <<>> + // CHECK-NEXT: <<>> + // CHECK-NEXT: NullStmt + + // Instantiation: + // CHECK-NEXT: FunctionDecl{{.*}} used TemplUses 'void ()' implicit_instantiation + // CHECK-NEXT: TemplateArgument type 'S' + // CHECK-NEXT: RecordType{{.*}} 'S' + // CHECK-NEXT: CXXRecord{{.*}} 'S' + // CHECK-NEXT: TemplateArgument integral '2U' + // CHECK-NEXT: CompoundStmt + + // CHECK-NEXT: OpenACCLoopConstruct + // CHECK-NEXT: collapse clause + // CHECK-NEXT: ConstantExpr{{.*}}'unsigned int' + // CHECK-NEXT: value: Int 2 + // CHECK-NEXT: SubstNonTypeTemplateParmExpr{{.*}} 'unsigned int' + // CHECK-NEXT: NonTypeTemplateParmDecl + // CHECK-NEXT: IntegerLiteral {{.*}} 'unsigned int' 2 + // CHECK-NEXT: ForStmt + // CHECK-NEXT: <<>> + // CHECK-NEXT: <<>> + // CHECK-NEXT: <<>> + // CHECK-NEXT: <<>> + // CHECK-NEXT: ForStmt + // CHECK-NEXT: <<>> + // CHECK-NEXT: <<>> + // CHECK-NEXT: <<>> + // CHECK-NEXT: <<>> + // CHECK-NEXT: NullStmt + + // CHECK-NEXT: OpenACCLoopConstruct + // CHECK-NEXT: collapse clause + // CHECK-NEXT: ConstantExpr{{.*}}'int' + // CHECK-NEXT: value: Int 2 + // CHECK-NEXT: BinaryOperator {{.*}}'+' + // CHECK-NEXT: ImplicitCastExpr{{.*}} 'int' + // CHECK-NEXT: CXXMemberCallExpr{{.*}} 'int' + // CHECK-NEXT: MemberExpr{{.*}} .operator auto + // CHECK-NEXT: MaterializeTemporaryExpr{{.*}}'S' lvalue + // CHECK-NEXT: CXXTemporaryObjectExpr{{.*}}'S' 'void ()' list + // CHECK-NEXT: ImplicitCastExpr{{.*}} 'int' + // CHECK-NEXT: CXXMemberCallExpr{{.*}} 'int' + // CHECK-NEXT: MemberExpr{{.*}} .operator auto + // CHECK-NEXT: MaterializeTemporaryExpr{{.*}}'S' lvalue + // CHECK-NEXT: CXXTemporaryObjectExpr{{.*}}'S' 'void ()' list + // CHECK-NEXT: ForStmt + // CHECK-NEXT: <<>> + // CHECK-NEXT: <<>> + // CHECK-NEXT: <<>> + // CHECK-NEXT: <<>> + // CHECK-NEXT: ForStmt + // CHECK-NEXT: <<>> + // CHECK-NEXT: <<>> + // CHECK-NEXT: <<>> + // CHECK-NEXT: <<>> + // CHECK-NEXT: NullStmt + +} + +void Inst() { + TemplUses(); +} + +#endif // PCH_HELPER diff --git a/clang/test/SemaOpenACC/loop-construct-collapse-clause.cpp b/clang/test/SemaOpenACC/loop-construct-collapse-clause.cpp new file mode 100644 index 0000000000000..9c1e577773e8f --- /dev/null +++ b/clang/test/SemaOpenACC/loop-construct-collapse-clause.cpp @@ -0,0 +1,117 @@ +// RUN: %clang_cc1 %s -fopenacc -verify + + +void only_for_loops() { + // expected-error@+3{{OpenACC 'loop' construct can only be applied to a 'for' loop}} + // expected-note@+1{{'loop' construct is here}} +#pragma acc loop collapse(1) + while(true); + + // expected-error@+3{{OpenACC 'loop' construct can only be applied to a 'for' loop}} + // expected-note@+1{{'loop' construct is here}} +#pragma acc loop collapse(1) + do{}while(true); + +} + +void only_one_on_loop() { + // expected-error@+2{{OpenACC 'collapse' clause cannot appear more than once on a 'loop' directive}} + // expected-note@+1{{previous clause is here}} +#pragma acc loop collapse(1) collapse(1) + for(;;); +} + +constexpr int three() { return 3; } +constexpr int one() { return 1; } +constexpr int neg() { return -1; } +constexpr int zero() { return 0; } + +struct NotConstexpr { + constexpr NotConstexpr(){}; + + operator int(){ return 1; } +}; +struct ConvertsNegative { + constexpr ConvertsNegative(){}; + + constexpr operator int(){ return -1; } +}; +struct ConvertsOne{ + constexpr ConvertsOne(){}; + + constexpr operator int(){ return 1; } +}; + +struct ConvertsThree{ + constexpr ConvertsThree(){}; + + constexpr operator int(){ return 3; } +}; + +template +void negative_constexpr_templ() { + // expected-error@+3 2{{OpenACC 'collapse' clause loop count must be a positive integer value, evaluated to 0}} + // expected-note@#NCETN1{{in instantiation of function template specialization 'negative_constexpr_templ'}} + // expected-note@#NCET1{{in instantiation of function template specialization 'negative_constexpr_templ'}} +#pragma acc loop collapse(T{}) + for(;;) + for(;;); + + // expected-error@+1{{OpenACC 'collapse' clause loop count must be a positive integer value, evaluated to -1}} +#pragma acc loop collapse(Val) + for(;;) + for(;;); +} + +void negative_constexpr(int i) { +#pragma acc loop collapse(2) + for(;;) + for(;;); + +#pragma acc loop collapse(1) + for(;;) + for(;;); + + // expected-error@+1{{OpenACC 'collapse' clause loop count must be a positive integer value, evaluated to 0}} +#pragma acc loop collapse(0) + for(;;) + for(;;); + + // expected-error@+1{{OpenACC 'collapse' clause loop count must be a positive integer value, evaluated to -1}} +#pragma acc loop collapse(-1) + for(;;) + for(;;); + +#pragma acc loop collapse(one()) + for(;;) + for(;;); + + // expected-error@+1{{OpenACC 'collapse' clause loop count must be a positive integer value, evaluated to 0}} +#pragma acc loop collapse(zero()) + for(;;) + for(;;); + + // expected-error@+1{{OpenACC 'collapse' clause loop count must be a positive integer value, evaluated to -1}} +#pragma acc loop collapse(neg()) + for(;;) + for(;;); + + // expected-error@+1{{OpenACC 'collapse' clause loop count must be a constant expression}} +#pragma acc loop collapse(NotConstexpr{}) + for(;;) + for(;;); + + // expected-error@+1{{OpenACC 'collapse' clause loop count must be a positive integer value, evaluated to -1}} +#pragma acc loop collapse(ConvertsNegative{}) + for(;;) + for(;;); + +#pragma acc loop collapse(ConvertsOne{}) + for(;;) + for(;;); + + negative_constexpr_templ(); // #NCETN1 + + negative_constexpr_templ(); // #NCET1 +} + diff --git a/clang/test/SemaOpenACC/loop-construct-device_type-clause.c b/clang/test/SemaOpenACC/loop-construct-device_type-clause.c index 520ba45aaebf4..47c9239f4f0e9 100644 --- a/clang/test/SemaOpenACC/loop-construct-device_type-clause.c +++ b/clang/test/SemaOpenACC/loop-construct-device_type-clause.c @@ -162,7 +162,6 @@ void uses() { // expected-note@+1{{previous clause is here}} #pragma acc loop device_type(*) reduction(+:Var) for(;;); - // expected-warning@+1{{OpenACC clause 'collapse' not yet implemented, clause ignored}} #pragma acc loop device_type(*) collapse(1) for(;;); // expected-error@+2{{OpenACC clause 'bind' may not follow a 'device_type' clause in a 'loop' construct}} diff --git a/clang/test/SemaTemplate/concepts-out-of-line-def.cpp b/clang/test/SemaTemplate/concepts-out-of-line-def.cpp index 5450d105a6f54..8ca399a0f729a 100644 --- a/clang/test/SemaTemplate/concepts-out-of-line-def.cpp +++ b/clang/test/SemaTemplate/concepts-out-of-line-def.cpp @@ -666,3 +666,37 @@ int foo() { } } // namespace eve + +namespace GH93099 { + +// Issues with sizeof...(expr) + +template struct C { + template + requires(sizeof...(N) > 0) + friend class NTTP; + + template + requires(sizeof...(Tp) > 0) + friend class TP; + + template