diff --git a/clang-tools-extra/clang-tidy/misc/ExplicitConstructorCheck.cpp b/clang-tools-extra/clang-tidy/misc/ExplicitConstructorCheck.cpp index 8c6f8ef978991..23261fe5af61b 100644 --- a/clang-tools-extra/clang-tidy/misc/ExplicitConstructorCheck.cpp +++ b/clang-tools-extra/clang-tidy/misc/ExplicitConstructorCheck.cpp @@ -8,6 +8,7 @@ #include "ExplicitConstructorCheck.h" #include "../utils/LexerUtils.h" +#include "../utils/TypeTraits.h" #include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/ASTMatchers/ASTMatchers.h" @@ -31,27 +32,6 @@ void ExplicitConstructorCheck::registerMatchers(MatchFinder *Finder) { this); } -static bool declIsStdInitializerList(const NamedDecl *D) { - // First use the fast getName() method to avoid unnecessary calls to the - // slow getQualifiedNameAsString(). - return D->getName() == "initializer_list" && - D->getQualifiedNameAsString() == "std::initializer_list"; -} - -static bool isStdInitializerList(QualType Type) { - Type = Type.getCanonicalType(); - if (const auto *TS = Type->getAs()) { - if (const TemplateDecl *TD = TS->getTemplateName().getAsTemplateDecl()) - return declIsStdInitializerList(TD); - } - if (const auto *RT = Type->getAs()) { - if (const auto *Specialization = - dyn_cast(RT->getDecl())) - return declIsStdInitializerList(Specialization->getSpecializedTemplate()); - } - return false; -} - void ExplicitConstructorCheck::check(const MatchFinder::MatchResult &Result) { constexpr char NoExpressionWarningMessage[] = "%0 must be marked explicit to avoid unintentional implicit conversions"; @@ -79,7 +59,7 @@ void ExplicitConstructorCheck::check(const MatchFinder::MatchResult &Result) { const ExplicitSpecifier ExplicitSpec = Ctor->getExplicitSpecifier(); - const bool TakesInitializerList = isStdInitializerList( + const bool TakesInitializerList = utils::type_traits::isStdInitializerList( Ctor->getParamDecl(0)->getType().getNonReferenceType()); if (ExplicitSpec.isExplicit() && (Ctor->isCopyOrMoveConstructor() || TakesInitializerList)) { diff --git a/clang-tools-extra/clang-tidy/utils/TypeTraits.cpp b/clang-tools-extra/clang-tidy/utils/TypeTraits.cpp index c15d90b19d359..136a7b2ed26a8 100644 --- a/clang-tools-extra/clang-tidy/utils/TypeTraits.cpp +++ b/clang-tools-extra/clang-tidy/utils/TypeTraits.cpp @@ -9,6 +9,7 @@ #include "TypeTraits.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclTemplate.h" #include namespace clang::tidy::utils::type_traits { @@ -146,4 +147,22 @@ bool hasNonTrivialMoveAssignment(QualType Type) { Record->hasNonTrivialMoveAssignment(); } +static bool declIsStdInitializerList(const NamedDecl *D) { + return D->isInStdNamespace() && D->getName() == "initializer_list"; +} + +bool isStdInitializerList(QualType Type) { + Type = Type.getCanonicalType(); + if (const auto *TS = Type->getAs()) { + if (const TemplateDecl *TD = TS->getTemplateName().getAsTemplateDecl()) + return declIsStdInitializerList(TD); + } + if (const auto *RT = Type->getAs()) { + if (const auto *Specialization = + dyn_cast_if_present(RT->getDecl())) + return declIsStdInitializerList(Specialization->getSpecializedTemplate()); + } + return false; +} + } // namespace clang::tidy::utils::type_traits diff --git a/clang-tools-extra/clang-tidy/utils/TypeTraits.h b/clang-tools-extra/clang-tidy/utils/TypeTraits.h index 98a4a99bf8d4d..03711461b51ac 100644 --- a/clang-tools-extra/clang-tidy/utils/TypeTraits.h +++ b/clang-tools-extra/clang-tidy/utils/TypeTraits.h @@ -34,6 +34,9 @@ bool hasNonTrivialMoveConstructor(QualType Type); /// Return true if `Type` has a non-trivial move assignment operator. bool hasNonTrivialMoveAssignment(QualType Type); +/// Returns `true` if `Type` is a `std::initializer_list<...>` specialization. +bool isStdInitializerList(QualType Type); + } // namespace clang::tidy::utils::type_traits #endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_UTILS_TYPETRAITS_H diff --git a/clang-tools-extra/clangd/CodeCompletionStrings.cpp b/clang-tools-extra/clangd/CodeCompletionStrings.cpp index 9c4241b54057a..dc86be60a876f 100644 --- a/clang-tools-extra/clangd/CodeCompletionStrings.cpp +++ b/clang-tools-extra/clangd/CodeCompletionStrings.cpp @@ -127,11 +127,12 @@ std::string getDeclComment(const ASTContext &Ctx, const NamedDecl &Decl) { // not write them into PCH, because they are racy and slow to load. assert(!Ctx.getSourceManager().isLoadedSourceLocation(RC->getBeginLoc())); - comments::FullComment *FC = RC->parse(Ctx, /*PP=*/nullptr, ND); - if (!FC) + std::string DeclDoc = + RC->getFormattedText(Ctx.getSourceManager(), Ctx.getDiagnostics()); + if (!looksLikeDocComment(DeclDoc)) return ""; - SymbolDocCommentVisitor V(FC, Ctx.getLangOpts().CommentOpts); + SymbolDocCommentVisitor V(DeclDoc, Ctx.getLangOpts().CommentOpts); std::string RawDoc; llvm::raw_string_ostream OS(RawDoc); diff --git a/clang-tools-extra/clangd/SymbolDocumentation.cpp b/clang-tools-extra/clangd/SymbolDocumentation.cpp index a50d7a565b1bc..c54f752f04196 100644 --- a/clang-tools-extra/clangd/SymbolDocumentation.cpp +++ b/clang-tools-extra/clangd/SymbolDocumentation.cpp @@ -34,9 +34,10 @@ void commandToMarkup(markup::Paragraph &Out, StringRef Command, comments::CommandMarkerKind CommandMarker, StringRef Args) { Out.appendBoldText(commandMarkerAsString(CommandMarker) + Command.str()); - Out.appendSpace(); - if (!Args.empty()) + if (!Args.empty()) { + Out.appendSpace(); Out.appendCode(Args.str()); + } } template std::string getArgText(const T *Command) { @@ -108,6 +109,7 @@ class ParagraphToMarkupDocument commandToMarkup(Out, C->getCommandName(Traits), C->getCommandMarker(), ""); + LastChunkEndsWithNewline = false; } } @@ -159,7 +161,11 @@ class ParagraphToString } } - void visitTextComment(const comments::TextComment *C) { Out << C->getText(); } + void visitTextComment(const comments::TextComment *C) { + Out << C->getText(); + if (C->hasTrailingNewline()) + Out << "\n"; + } void visitInlineCommandComment(const comments::InlineCommandComment *C) { Out << commandMarkerAsString(C->getCommandMarker()); @@ -167,7 +173,6 @@ class ParagraphToString std::string ArgText = getArgText(C); if (!ArgText.empty()) Out << " " << ArgText; - Out << " "; } void visitHTMLStartTagComment(const comments::HTMLStartTagComment *STC) { @@ -251,10 +256,7 @@ class BlockCommentToMarkupDocument commandToMarkup(P, B->getCommandName(Traits), B->getCommandMarker(), ArgText); if (B->getParagraph() && !B->getParagraph()->isWhitespace()) { - // For commands with arguments, the paragraph starts after the first - // space. Therefore we need to append a space manually in this case. - if (!ArgText.empty()) - P.appendSpace(); + P.appendSpace(); ParagraphToMarkupDocument(P, Traits).visit(B->getParagraph()); } } diff --git a/clang-tools-extra/clangd/SymbolDocumentation.h b/clang-tools-extra/clangd/SymbolDocumentation.h index 88c7ade633516..95787ae6c92b9 100644 --- a/clang-tools-extra/clangd/SymbolDocumentation.h +++ b/clang-tools-extra/clangd/SymbolDocumentation.h @@ -31,17 +31,6 @@ namespace clangd { class SymbolDocCommentVisitor : public comments::ConstCommentVisitor { public: - SymbolDocCommentVisitor(comments::FullComment *FC, - const CommentOptions &CommentOpts) - : Traits(Allocator, CommentOpts), Allocator() { - if (!FC) - return; - - for (auto *Block : FC->getBlocks()) { - visit(Block); - } - } - SymbolDocCommentVisitor(llvm::StringRef Documentation, const CommentOptions &CommentOpts) : Traits(Allocator, CommentOpts), Allocator() { diff --git a/clang-tools-extra/clangd/support/Markup.cpp b/clang-tools-extra/clangd/support/Markup.cpp index 9ba993a04709c..8ecaa823eb280 100644 --- a/clang-tools-extra/clangd/support/Markup.cpp +++ b/clang-tools-extra/clangd/support/Markup.cpp @@ -537,16 +537,28 @@ void Paragraph::renderEscapedMarkdown(llvm::raw_ostream &OS) const { void Paragraph::renderMarkdown(llvm::raw_ostream &OS) const { bool NeedsSpace = false; bool HasChunks = false; + bool TextEndsWithNewline = false; std::string ParagraphText; ParagraphText.reserve(EstimatedStringSize); llvm::raw_string_ostream ParagraphTextOS(ParagraphText); for (auto &C : Chunks) { + + if (TextEndsWithNewline) { + ParagraphTextOS << "\n"; + TextEndsWithNewline = false; + } + if (C.SpaceBefore || NeedsSpace) ParagraphTextOS << " "; + switch (C.Kind) { case ChunkKind::PlainText: ParagraphTextOS << renderText(C.Contents, !HasChunks, /*EscapeMarkdown=*/false); + // renderText removes trailing newlines, but in case there are additional + // chunks to process, we need to keep track of the trailing newline and + // add it in the next iteration. + TextEndsWithNewline = llvm::StringRef(C.Contents).ends_with("\n"); break; case ChunkKind::InlineCode: ParagraphTextOS << renderInlineBlock(C.Contents); diff --git a/clang-tools-extra/clangd/unittests/CodeCompletionStringsTests.cpp b/clang-tools-extra/clangd/unittests/CodeCompletionStringsTests.cpp index de5f533d31645..6b8b003a4fe18 100644 --- a/clang-tools-extra/clangd/unittests/CodeCompletionStringsTests.cpp +++ b/clang-tools-extra/clangd/unittests/CodeCompletionStringsTests.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "CodeCompletionStrings.h" +#include "Config.h" #include "TestTU.h" #include "clang/Sema/CodeCompleteConsumer.h" #include "gmock/gmock.h" @@ -69,6 +70,59 @@ TEST_F(CompletionStringTest, GetDeclCommentBadUTF8) { getDeclComment(AST.getASTContext(), findDecl(AST, "X"))); } +TEST_F(CompletionStringTest, GetDeclCommentForParam) { + auto TU = + TestTU::withCode("/** @param a this is param a */\nvoid func(int a);"); + auto AST = TU.build(); + Config Cfg; + Cfg.Documentation.CommentFormat = Config::CommentFormatPolicy::Doxygen; + WithContextValue WithCfg(Config::Key, std::move(Cfg)); + const auto &FD = llvm::cast(findDecl(AST, "func")); + EXPECT_EQ(FD.getNumParams(), 1UL); + EXPECT_EQ("this is param a", + getDeclComment(AST.getASTContext(), *FD.parameters()[0])); +} + +TEST_F(CompletionStringTest, GetDeclCommentForMultipleParams) { + auto TU = TestTU::withCode("/** @param a this is param a\n * @param b this " + "is param b\n */\nvoid func(int a, int b);"); + auto AST = TU.build(); + Config Cfg; + Cfg.Documentation.CommentFormat = Config::CommentFormatPolicy::Doxygen; + WithContextValue WithCfg(Config::Key, std::move(Cfg)); + const auto &FD = llvm::cast(findDecl(AST, "func")); + EXPECT_EQ(FD.getNumParams(), 2UL); + EXPECT_EQ("this is param a", + getDeclComment(AST.getASTContext(), *FD.parameters()[0])); + EXPECT_EQ("this is param b", + getDeclComment(AST.getASTContext(), *FD.parameters()[1])); +} + +TEST_F(CompletionStringTest, GetDeclCommentForUndocumentedParam) { + auto TU = + TestTU::withCode("/** @param c this is param c */\nvoid func(int a);"); + auto AST = TU.build(); + Config Cfg; + Cfg.Documentation.CommentFormat = Config::CommentFormatPolicy::Doxygen; + WithContextValue WithCfg(Config::Key, std::move(Cfg)); + const auto &FD = llvm::cast(findDecl(AST, "func")); + EXPECT_EQ(FD.getNumParams(), 1UL); + EXPECT_EQ("", getDeclComment(AST.getASTContext(), *FD.parameters()[0])); +} + +TEST_F(CompletionStringTest, GetDeclCommentForParamWithUnknownDoxygenCommand) { + auto TU = TestTU::withCode("/** @param a this is param a and an\n * @unknown " + "command\n */\nvoid func(int a);"); + auto AST = TU.build(); + Config Cfg; + Cfg.Documentation.CommentFormat = Config::CommentFormatPolicy::Doxygen; + WithContextValue WithCfg(Config::Key, std::move(Cfg)); + const auto &FD = llvm::cast(findDecl(AST, "func")); + EXPECT_EQ(FD.getNumParams(), 1UL); + EXPECT_EQ("this is param a and an\n@unknown command", + getDeclComment(AST.getASTContext(), *FD.parameters()[0])); +} + TEST_F(CompletionStringTest, MultipleAnnotations) { Builder.AddAnnotation("Ano1"); Builder.AddAnnotation("Ano2"); diff --git a/clang-tools-extra/clangd/unittests/HoverTests.cpp b/clang-tools-extra/clangd/unittests/HoverTests.cpp index 7b168b0bdca60..476494cdd3e6d 100644 --- a/clang-tools-extra/clangd/unittests/HoverTests.cpp +++ b/clang-tools-extra/clangd/unittests/HoverTests.cpp @@ -4431,6 +4431,56 @@ brief doc ### Details longer doc)"}, + {[](HoverInfo &HI) { + HI.Kind = index::SymbolKind::Function; + HI.Documentation = "@brief brief doc\n" + "@unknown command is treated as an inline command"; + HI.Definition = "int foo(int a)"; + HI.ReturnType = "int"; + HI.Name = "foo"; + HI.Parameters.emplace(); + HI.Parameters->emplace_back(); + HI.Parameters->back().Type = "int"; + HI.Parameters->back().Name = "a"; + }, + R"(### function `foo` + +--- +→ `int` + +Parameters: + +- `int a` + +@brief brief doc +@unknown command is treated as an inline command + +--- +```cpp +int foo(int a) +```)", + R"(### function + +--- +```cpp +int foo(int a) +``` + +--- +### Brief + +brief doc +**@unknown** command is treated as an inline command + +--- +### Parameters + +- `int a` + +--- +### Returns + +`int`)"}, }; for (const auto &C : Cases) { @@ -5203,6 +5253,22 @@ TEST(Hover, FunctionParameters) { "### param\n\n---\n```cpp\n// In foo\nint b\n```\n\n---\nthis is " "\\doc\\ \\ \\for\\ `b`\n\n---\nType: `int`"}, + {R"cpp(/// Function doc + /// @param a the next command is an + /// @unknown command. + void foo(int [[^a]]); + )cpp", + [](HoverInfo &HI) { + HI.Name = "a"; + HI.Kind = index::SymbolKind::Parameter; + HI.NamespaceScope = ""; + HI.LocalScope = "foo::"; + HI.Type = "int"; + HI.Definition = "int a"; + HI.Documentation = "the next command is an\n @unknown command."; + }, + "### param\n\n---\n```cpp\n// In foo\nint a\n```\n\n---\nthe next " + "command is an\n**@unknown** command.\n\n---\nType: `int`"}, }; // Create a tiny index, so tests above can verify documentation is fetched. diff --git a/clang-tools-extra/clangd/unittests/SymbolDocumentationTests.cpp b/clang-tools-extra/clangd/unittests/SymbolDocumentationTests.cpp index 676f7dfc74483..d140ab00a175f 100644 --- a/clang-tools-extra/clangd/unittests/SymbolDocumentationTests.cpp +++ b/clang-tools-extra/clangd/unittests/SymbolDocumentationTests.cpp @@ -10,6 +10,7 @@ #include "support/Markup.h" #include "clang/Basic/CommentOptions.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Support/raw_ostream.h" #include "gtest/gtest.h" namespace clang { @@ -732,5 +733,104 @@ line } } +TEST(SymbolDocumentation, ParameterDocToString) { + CommentOptions CommentOpts; + + struct Case { + llvm::StringRef Documentation; + llvm::StringRef ExpectedOutputString; + llvm::StringRef ParameterName; + } Cases[] = { + {"This documentation does not contain parameter docs", "", "a"}, + {"@param a this is a parameter", "", "not_exists"}, + {"@param a this is a parameter", " this is a parameter", "a"}, + {R"(@param a parameter doc with an \p inline command)", + R"( parameter doc with an \p inline command)", "a"}, + {R"(@param a parameter doc with an \unknown command)", + R"( parameter doc with an \unknown command)", "a"}, + {"@param a parameter doc with an @unknown command", + " parameter doc with an @unknown command", "a"}, + {R"(@param a parameter doc with +multiple lines)", + R"( parameter doc with +multiple lines)", + "a"}, + {R"(@param a parameter doc with an +@unknown command starting a new line)", + R"( parameter doc with an +@unknown command starting a new line)", + "a"}, + {R"(@param a parameter doc with a +@note command which is a new block command and therefore ends the parameter doc paragraph)", + R"( parameter doc with a +)", + "a"}, + {R"(Unrelated docs +@param a parameter doc + +New paragraph with unrelated docs)", + " parameter doc", "a"}, + }; + for (const auto &C : Cases) { + std::string Result; + llvm::raw_string_ostream OS(Result); + SymbolDocCommentVisitor SymbolDoc(C.Documentation, CommentOpts); + + SymbolDoc.parameterDocToString(C.ParameterName, OS); + + EXPECT_EQ(Result, C.ExpectedOutputString); + } +} + +TEST(SymbolDocumentation, TemplateParameterDocToString) { + CommentOptions CommentOpts; + + struct Case { + llvm::StringRef Documentation; + llvm::StringRef ExpectedOutputString; + llvm::StringRef TemplateParameterName; + } Cases[] = { + {"This documentation does not contain parameter docs", "", "a"}, + {"@tparam a this is a template type parameter", "", "not_exists"}, + {"@tparam a this is a template type parameter", + " this is a template type parameter", "a"}, + {R"(@tparam a template type parameter doc with an \p inline command)", + R"( template type parameter doc with an \p inline command)", "a"}, + {R"(@tparam a template type parameter doc with an \unknown command)", + R"( template type parameter doc with an \unknown command)", "a"}, + {"@tparam a template type parameter doc with an @unknown command", + " template type parameter doc with an @unknown command", "a"}, + {R"(@tparam a template type parameter doc with +multiple lines)", + R"( template type parameter doc with +multiple lines)", + "a"}, + {R"(@tparam a template type parameter doc with an +@unknown command starting a new line)", + R"( template type parameter doc with an +@unknown command starting a new line)", + "a"}, + {R"(@tparam a template type parameter doc with a +@note command which is a new block command and therefore ends the template type parameter doc paragraph)", + R"( template type parameter doc with a +)", + "a"}, + {R"(Unrelated docs +@tparam a template type parameter doc + +New paragraph with unrelated docs)", + " template type parameter doc", "a"}, + }; + for (const auto &C : Cases) { + std::string Result; + llvm::raw_string_ostream OS(Result); + SymbolDocCommentVisitor SymbolDoc(C.Documentation, CommentOpts); + + SymbolDoc.templateTypeParmDocToString(C.TemplateParameterName, OS); + + EXPECT_EQ(Result, C.ExpectedOutputString); + } +} + } // namespace clangd } // namespace clang diff --git a/clang-tools-extra/unittests/clang-tidy/CMakeLists.txt b/clang-tools-extra/unittests/clang-tidy/CMakeLists.txt index 26ceb977d27a6..00498813d1e52 100644 --- a/clang-tools-extra/unittests/clang-tidy/CMakeLists.txt +++ b/clang-tools-extra/unittests/clang-tidy/CMakeLists.txt @@ -35,6 +35,7 @@ add_extra_unittest(ClangTidyTests UsingInserterTest.cpp ReadabilityModuleTest.cpp TransformerClangTidyCheckTest.cpp + TypeTraitsTest.cpp ) clang_target_link_libraries(ClangTidyTests diff --git a/clang-tools-extra/unittests/clang-tidy/TypeTraitsTest.cpp b/clang-tools-extra/unittests/clang-tidy/TypeTraitsTest.cpp new file mode 100644 index 0000000000000..13261c3aa9e52 --- /dev/null +++ b/clang-tools-extra/unittests/clang-tidy/TypeTraitsTest.cpp @@ -0,0 +1,60 @@ +//===----------------------------------------------------------------------===// +// +// 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 "../clang-tidy/utils/TypeTraits.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/Tooling/Tooling.h" +#include "gtest/gtest.h" + +namespace clang::tidy::test { +namespace { + +using namespace ast_matchers; + +// Returns whether the type of the declaration named `DeclName` in `Code` is a +// std::initializer_list specialization. +bool declTypeIsStdInitializerList(StringRef Code, StringRef DeclName) { + std::unique_ptr AST = + tooling::buildASTFromCodeWithArgs(Code, {"-std=c++17"}); + EXPECT_NE(AST, nullptr); + auto Matches = + match(valueDecl(hasName(DeclName)).bind("d"), AST->getASTContext()); + EXPECT_EQ(Matches.size(), 1u); + const auto *D = Matches[0].getNodeAs("d"); + return utils::type_traits::isStdInitializerList(D->getType()); +} + +constexpr char InitializerListDecl[] = + "namespace std { template class initializer_list {}; }\n"; + +TEST(IsStdInitializerListTest, MatchesSpecialization) { + EXPECT_TRUE(declTypeIsStdInitializerList( + std::string(InitializerListDecl) + "std::initializer_list v;", "v")); +} + +TEST(IsStdInitializerListTest, MatchesDependentSpecialization) { + EXPECT_TRUE(declTypeIsStdInitializerList( + std::string(InitializerListDecl) + + "template void f(std::initializer_list p);", + "p")); +} + +TEST(IsStdInitializerListTest, RejectsBuiltin) { + EXPECT_FALSE(declTypeIsStdInitializerList("int v;", "v")); +} + +TEST(IsStdInitializerListTest, RejectsNonStdInitializerList) { + EXPECT_FALSE(declTypeIsStdInitializerList( + "template class initializer_list {}; " + "initializer_list v;", + "v")); +} + +} // namespace +} // namespace clang::tidy::test diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 09d56e0640b89..a9196f0f877c5 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -523,7 +523,11 @@ Attribute Changes in Clang about pointer lifetimes. It may be used to power optimizations in the future, however there are no concrete plans to do so at the moment. -* The ``modular_format`` attribute now supports the ``fixed`` aspect for C +- The attributes ``[[clang::opencl_global_device]]`` and ``[[clang::opencl_global_host]]`` + are now deprecated. Clang emits a ``-Wdeprecated-attributes`` warning when + they are used. + +- The ``modular_format`` attribute now supports the ``fixed`` aspect for C ISO 18037 fixed-point ``printf`` specifiers. Improvements to Clang's diagnostics diff --git a/clang/include/clang/AST/Comment.h b/clang/include/clang/AST/Comment.h index 9ea86089373d5..84e5444675ae1 100644 --- a/clang/include/clang/AST/Comment.h +++ b/clang/include/clang/AST/Comment.h @@ -344,15 +344,6 @@ class InlineCommandComment : public InlineContentComment { ArrayRef Args; public: - InlineCommandComment(SourceLocation LocBegin, SourceLocation LocEnd, - unsigned CommandID, InlineCommandRenderKind RK, - ArrayRef Args) - : InlineContentComment(CommentKind::InlineCommandComment, LocBegin, - LocEnd), - Args(Args) { - InlineCommandCommentBits.RenderKind = llvm::to_underlying(RK); - InlineCommandCommentBits.CommandID = CommandID; - } InlineCommandComment(SourceLocation LocBegin, SourceLocation LocEnd, unsigned CommandID, InlineCommandRenderKind RK, CommandMarkerKind CommandMarker, ArrayRef Args) diff --git a/clang/include/clang/AST/CommentLexer.h b/clang/include/clang/AST/CommentLexer.h index 9aa1681cb2c5c..194a31cb7b934 100644 --- a/clang/include/clang/AST/CommentLexer.h +++ b/clang/include/clang/AST/CommentLexer.h @@ -33,9 +33,12 @@ enum TokenKind { eof, newline, text, - unknown_command, // Command that does not have an ID. - backslash_command, // Command with an ID, that used backslash marker. - at_command, // Command with an ID, that used 'at' marker. + unknown_backslash_command, // Command that does not have an ID, that used + // backslash marker. + unknown_at_command, // Command that does not have an ID, that used 'at' + // marker. + backslash_command, // Command with an ID, that used backslash marker. + at_command, // Command with an ID, that used 'at' marker. verbatim_block_begin, verbatim_block_line, verbatim_block_end, @@ -107,12 +110,12 @@ class Token { } StringRef getUnknownCommandName() const LLVM_READONLY { - assert(is(tok::unknown_command)); + assert(is(tok::unknown_backslash_command) || is(tok::unknown_at_command)); return StringRef(TextPtr, IntVal); } void setUnknownCommandName(StringRef Name) { - assert(is(tok::unknown_command)); + assert(is(tok::unknown_backslash_command) || is(tok::unknown_at_command)); TextPtr = Name.data(); IntVal = Name.size(); } diff --git a/clang/include/clang/AST/CommentSema.h b/clang/include/clang/AST/CommentSema.h index 8dc6e50763dc5..3a7eda6538cbe 100644 --- a/clang/include/clang/AST/CommentSema.h +++ b/clang/include/clang/AST/CommentSema.h @@ -136,11 +136,13 @@ class Sema { InlineContentComment *actOnUnknownCommand(SourceLocation LocBegin, SourceLocation LocEnd, - StringRef CommandName); + StringRef CommandName, + CommandMarkerKind CommandMarker); InlineContentComment *actOnUnknownCommand(SourceLocation LocBegin, SourceLocation LocEnd, - unsigned CommandID); + unsigned CommandID, + CommandMarkerKind CommandMarker); TextComment *actOnText(SourceLocation LocBegin, SourceLocation LocEnd, diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Checker.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Checker.h index 1ad3f9da61f60..99ad816311e74 100644 --- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/Checker.h +++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/Checker.h @@ -29,7 +29,8 @@ void runLifetimeChecker(const LoanPropagationAnalysis &LoanPropagation, const MovedLoansAnalysis &MovedLoans, const LiveOriginsAnalysis &LiveOrigins, FactManager &FactMgr, AnalysisDeclContext &ADC, - LifetimeSafetySemaHelper *SemaHelper); + LifetimeSafetySemaHelper *SemaHelper, + const LifetimeSafetyOpts &LSOpts); } // namespace clang::lifetimes::internal diff --git a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h index 28886b826f72f..80a23f18baebd 100644 --- a/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h +++ b/clang/include/clang/Analysis/Analyses/LifetimeSafety/LifetimeSafety.h @@ -38,6 +38,9 @@ struct LifetimeSafetyOpts { /// Maximum number of CFG blocks to analyze. Functions with larger CFGs will /// be skipped. size_t MaxCFGBlocks; + + /// Whether to suggest lifetime annotations. + bool SuggestAnnotations; }; /// Enum to track functions visible across or within TU. @@ -157,6 +160,7 @@ class LifetimeSafetySemaHelper { /// The main entry point for the analysis. void runLifetimeSafetyAnalysis(AnalysisDeclContext &AC, LifetimeSafetySemaHelper *SemaHelper, + const LifetimeSafetyOpts &Opts, LifetimeSafetyStats &Stats, bool CollectStats); namespace internal { diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index 7c1c88241aaa8..d806adb4be4b8 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -5214,6 +5214,8 @@ As ``global_device`` and ``global_host`` are a subset of ``global_device`` and ``global_host`` address spaces to ``__global/opencl_global`` address spaces (following ISO/IEC TR 18037 5.1.3 "Address space nesting and rules for pointers"). + +These attributes are deprecated and may be removed in a future version of Clang. }]; } diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 34ea29f153474..dc7842846e5da 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -11878,6 +11878,9 @@ def err_opencl_type_not_found : Error< "%0 type %1 not found; include the base header with -finclude-default-header">; def warn_opencl_attr_deprecated_ignored : Warning < "%0 attribute is deprecated and ignored in %1">, InGroup; +def warn_deprecated_attribute : Warning< + "'%0' attribute is deprecated and may be removed in a future version of Clang">, + InGroup; def err_opencl_variadic_function : Error< "invalid prototype, variadic arguments are not allowed in OpenCL">; def err_opencl_requires_extension : Error< diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp index cadb040048384..20b110b38ff78 100644 --- a/clang/lib/AST/ByteCode/Compiler.cpp +++ b/clang/lib/AST/ByteCode/Compiler.cpp @@ -5398,10 +5398,11 @@ bool Compiler::visitDtorCall(const VarDecl *VD, const APValue &Value) { DeclScope LocalScope(this, VD); // Create a local variable to use as the instance. QualType Ty = VD->getType(); - Descriptor *D = P.createDescriptor( - VD, Ty.getTypePtr(), Descriptor::InlineDescMD, /*IsConst=*/false, - /*IsTemporary=*/false, /*IsMutable=*/false, - /*IsVolatile=*/Ty.isVolatileQualified(), nullptr); + Descriptor *D = + P.createDescriptor(VD, Ty.getTypePtr(), Descriptor::InlineDescMD, + /*IsConst=*/Ty.isConstQualified(), + /*IsTemporary=*/false, /*IsMutable=*/false, + /*IsVolatile=*/Ty.isVolatileQualified(), nullptr); if (!D) return false; @@ -7671,16 +7672,21 @@ bool Compiler::VisitVectorUnaryOperator(const UnaryOperator *E) { template bool Compiler::visitDeclRef(const ValueDecl *D, const Expr *E) { - if (DiscardResult) - return true; - - if (const auto *ECD = dyn_cast(D)) + if (const auto *ECD = dyn_cast(D)) { + if (DiscardResult) + return true; return this->emitConst(ECD->getInitVal(), E); + } if (const auto *FuncDecl = dyn_cast(D)) { + if (DiscardResult) + return true; const Function *F = getFunction(FuncDecl); return F && this->emitGetFnPtr(F, E); } if (const auto *TPOD = dyn_cast(D)) { + if (DiscardResult) + return true; + if (UnsignedOrNone Index = P.getOrCreateGlobal(D)) { if (OptPrimType T = classify(D->getType())) { if (!this->visitAPValue(TPOD->getValue(), *T, E)) @@ -7704,10 +7710,19 @@ bool Compiler::visitDeclRef(const ValueDecl *D, const Expr *E) { QualType DeclType = D->getType(); bool IsReference = DeclType->isReferenceType(); + auto maybePopPtr = [&]() -> bool { + if (DiscardResult) + return this->emitPopPtr(E); + return true; + }; + // Function parameters. // Note that it's important to check them first since we might have a local // variable created for a ParmVarDecl as well. if (const auto *PVD = dyn_cast(D)) { + if (DiscardResult) + return true; + if (Ctx.getLangOpts().CPlusPlus && !Ctx.getLangOpts().CPlusPlus11 && !DeclType->isIntegralOrEnumerationType()) { return this->emitInvalidDeclRef(cast(E), @@ -7729,9 +7744,9 @@ bool Compiler::visitDeclRef(const ValueDecl *D, const Expr *E) { const unsigned Offset = It->second.Offset; if (IsReference) { assert(classifyPrim(E) == PT_Ptr); - return this->emitGetRefLocal(Offset, E); + return this->emitGetRefLocal(Offset, E) && maybePopPtr(); } - return this->emitGetPtrLocal(Offset, E); + return this->emitGetPtrLocal(Offset, E) && maybePopPtr(); } // Global variables. if (auto GlobalIndex = P.getGlobal(D)) { @@ -7740,10 +7755,11 @@ bool Compiler::visitDeclRef(const ValueDecl *D, const Expr *E) { return this->emitGetGlobal(classifyPrim(E), *GlobalIndex, E); if (!Ctx.getLangOpts().CPlusPlus23) return this->emitGetGlobalUnchecked(classifyPrim(E), *GlobalIndex, E); - return this->emitGetRefGlobal(*GlobalIndex, E); + + return this->emitGetRefGlobal(*GlobalIndex, E) && maybePopPtr(); } - return this->emitGetPtrGlobal(*GlobalIndex, E); + return this->emitGetPtrGlobal(*GlobalIndex, E) && maybePopPtr(); } // In case we need to re-visit a declaration. @@ -7773,8 +7789,8 @@ bool Compiler::visitDeclRef(const ValueDecl *D, const Expr *E) { auto [Offset, IsPtr] = It->second; if (IsPtr) - return this->emitGetThisFieldPtr(Offset, E); - return this->emitGetPtrThisField(Offset, E); + return this->emitGetThisFieldPtr(Offset, E) && maybePopPtr(); + return this->emitGetPtrThisField(Offset, E) && maybePopPtr(); } } @@ -7785,11 +7801,14 @@ bool Compiler::visitDeclRef(const ValueDecl *D, const Expr *E) { } if (const auto *BD = dyn_cast(D)) - return this->visit(BD->getBinding()); + return this->delegate(BD->getBinding()); // Avoid infinite recursion. - if (D == InitializingDecl) + if (D == InitializingDecl) { + if (DiscardResult) + return true; return this->emitDummyPtr(D, E); + } // Try to lazily visit (or emit dummy pointers for) declarations // we haven't seen yet. @@ -7803,6 +7822,9 @@ bool Compiler::visitDeclRef(const ValueDecl *D, const Expr *E) { DeclType.isConstant(Ctx.getASTContext()) && !VD->isWeak() && VD->evaluateValue()) return revisit(VD, /*IsConstexprUnknown=*/false); + + if (DiscardResult) + return true; return this->emitDummyPtr(D, E); } @@ -7848,6 +7870,8 @@ bool Compiler::visitDeclRef(const ValueDecl *D, const Expr *E) { /*InitializerFailed=*/true, E); } + if (DiscardResult) + return true; return this->emitDummyPtr( D, E, Ctx.getLangOpts().CPlusPlus23 && DeclType->isReferenceType()); } diff --git a/clang/lib/AST/ByteCode/Context.cpp b/clang/lib/AST/ByteCode/Context.cpp index 4beb35a9a7b43..40cf29efcfb4f 100644 --- a/clang/lib/AST/ByteCode/Context.cpp +++ b/clang/lib/AST/ByteCode/Context.cpp @@ -174,6 +174,8 @@ bool Context::evaluateDestruction(State &Parent, const VarDecl *VD, return false; } + assert(Stk.empty()); + return true; } diff --git a/clang/lib/AST/ByteCode/EvalEmitter.cpp b/clang/lib/AST/ByteCode/EvalEmitter.cpp index 7aeac16b9639e..83dac57353944 100644 --- a/clang/lib/AST/ByteCode/EvalEmitter.cpp +++ b/clang/lib/AST/ByteCode/EvalEmitter.cpp @@ -77,11 +77,14 @@ EvaluationResult EvalEmitter::interpretDestructor(const VarDecl *VD, const APValue &Value) { assert(VD); S.setEvalLocation(VD->getLocation()); + S.EvaluatingDecl = VD; + S.EvalKind = EvaluationKind::Dtor; EvalResult.setSource(VD); if (!this->visitDtorCall(VD, Value)) EvalResult.setInvalid(); + S.EvaluatingDecl = nullptr; return std::move(this->EvalResult); } @@ -278,7 +281,17 @@ template <> bool EvalEmitter::emitRet(SourceInfo Info) { if (!Ptr.isLive() && !Ptr.isTemporary()) return false; - EvalResult.takeValue(Ptr.toAPValue(Ctx.getASTContext())); + // If the variable of this pointer is being evaluated when returning + // its value, mark it as constexpr-unknown. + APValue V = Ptr.toAPValue(Ctx.getASTContext()); + if (const Descriptor *DeclDesc = Ptr.getDeclDesc(); + DeclDesc && S.EvaluatingDecl && + DeclDesc->asVarDecl() == S.EvaluatingDecl && + S.getLangOpts().CPlusPlus23 && + S.EvaluatingDecl->getType()->isReferenceType()) { + V.setConstexprUnknown(true); + } + EvalResult.takeValue(std::move(V)); } return true; diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp index 3d5fda7ddf3c7..71021815baeef 100644 --- a/clang/lib/AST/ByteCode/Interp.cpp +++ b/clang/lib/AST/ByteCode/Interp.cpp @@ -205,14 +205,16 @@ static bool CheckTemporary(InterpState &S, CodePtr OpPC, const Block *B, // FIXME(perf): Since we do this check on every Load from a static // temporary, it might make sense to cache the value of the // isUsableInConstantExpressions call. - if (B->getEvalID() != S.EvalID && - !MTE->isUsableInConstantExpressions(S.getASTContext())) { + if (S.checkingConstantDestruction() || + (B->getEvalID() != S.EvalID && + !MTE->isUsableInConstantExpressions(S.getASTContext()))) { const SourceInfo &E = S.Current->getSource(OpPC); S.FFDiag(E, diag::note_constexpr_access_static_temporary, 1) << AK; noteValueLocation(S, B); return false; } } + return true; } @@ -459,7 +461,12 @@ bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc, assert(Desc); const auto *D = Desc->asVarDecl(); - if (!D || D == S.EvaluatingDecl || D->isConstexpr()) + if (S.checkingConstantDestruction(D)) { + // If we're checking for a constant destructor for this variable, we can + // only read from it if it is constant. + if (D->getType().isConstQualified()) + return true; + } else if (!D || D == S.EvaluatingDecl || D->isConstexpr()) return true; // If we're evaluating the initializer for a constexpr variable in C23, we may @@ -509,6 +516,9 @@ bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc, static bool CheckConstant(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK = AK_Read) { + if (S.checkingConstantDestruction(Ptr)) + return CheckConstant(S, OpPC, Ptr.getDeclDesc(), AK); + if (!Ptr.isStatic() || !Ptr.isBlockPointer()) return true; if (!Ptr.getDeclID()) @@ -648,10 +658,24 @@ bool CheckMutable(InterpState &S, CodePtr OpPC, PtrView Ptr, AccessKinds AK) { if (!Ptr.isMutable()) return true; - // In C++14 onwards, it is permitted to read a mutable member whose - // lifetime began within the evaluation. - if (S.getLangOpts().CPlusPlus14 && Ptr.getEvalID() == S.EvalID) + if (S.checkingConstantDestruction()) { + // Never allowed when checking for constant destruction. + // Find the reason this pointer is mutable. + PtrView MutablePtr = Ptr; + while (!MutablePtr.isRoot() && MutablePtr.getBase().isMutable()) + MutablePtr = MutablePtr.getBase(); + + const FieldDecl *Field = MutablePtr.getField(); + S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_access_mutable, 1) + << AK << Field; + S.Note(Field->getLocation(), diag::note_declared_at); + return false; + } else if (S.getLangOpts().CPlusPlus14 && + S.lifetimeStartedInEvaluation(Ptr.block())) { + // In C++14 onwards, it is permitted to read a mutable member whose + // lifetime began within the evaluation. return true; + } const SourceInfo &Loc = S.Current->getSource(OpPC); const FieldDecl *Field = Ptr.getField(); @@ -985,21 +1009,23 @@ bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr, return false; if (!CheckVolatile(S, OpPC, Ptr, AK_Assign)) return false; + if (!CheckMutable(S, OpPC, Ptr, AK_Assign)) + return false; if (isConstexprUnknown(Ptr)) return false; return true; } static bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr, - bool IsCtorDtor = false) { + bool IsCtor, bool IsDtor) { if (!Ptr.isDummy() && !isConstexprUnknown(Ptr)) { if (!CheckLive(S, OpPC, Ptr, AK_MemberCall)) return false; if (!CheckRange(S, OpPC, Ptr, AK_MemberCall)) return false; - if (!IsCtorDtor && !CheckLifetime(S, OpPC, Ptr, AK_MemberCall)) + if (!(IsCtor || IsDtor) && !CheckLifetime(S, OpPC, Ptr, AK_MemberCall)) return false; - if (!CheckMutable(S, OpPC, Ptr)) + if (!IsDtor && !CheckMutable(S, OpPC, Ptr)) return false; } return true; @@ -1708,6 +1734,11 @@ bool CheckDestructor(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { if (Ptr.getLifetime() == Lifetime::Ended) return CheckLifetime(S, OpPC, Ptr, AK_Destroy); + // We _can_ call the destructor on the global variable we're checking constant + // destruction for. + if (S.checkingConstantDestruction(Ptr)) + return true; + // Can't call a dtor on a global variable. if (Ptr.block()->isStatic()) { const SourceInfo &E = S.Current->getSource(OpPC); @@ -1803,8 +1834,8 @@ bool CallVar(InterpState &S, CodePtr OpPC, const Function *Func, if (!(S.Current->getFunction() && S.Current->getFunction()->isLambdaStaticInvoker() && Func->isLambdaCallOperator())) { - if (!CheckInvoke(S, OpPC, ThisPtr, - Func->isConstructor() || Func->isDestructor())) + if (!CheckInvoke(S, OpPC, ThisPtr, Func->isConstructor(), + Func->isDestructor())) return false; } @@ -1873,14 +1904,14 @@ bool Call(InterpState &S, CodePtr OpPC, const Function *Func, Func->isLambdaCallOperator()) { assert(ThisPtr.isZero()); } else { - if (!CheckInvoke(S, OpPC, ThisPtr, - Func->isConstructor() || Func->isDestructor())) + if (!CheckInvoke(S, OpPC, ThisPtr, Func->isConstructor(), + Func->isDestructor())) return cleanup(); if (Func->isCopyOrMoveOperator() || Func->isCopyOrMoveConstructor()) { const Pointer &RVOPtr = S.Stk.peek(ThisOffset - align(sizeof(Pointer))); - if (!CheckInvoke(S, OpPC, RVOPtr, /*IsCtorDtor=*/true)) + if (!CheckInvoke(S, OpPC, RVOPtr, /*IsCtor=*/true, /*IsDtor=*/false)) return cleanup(); } diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h index ed640f7325f7e..aa2dffc2b982a 100644 --- a/clang/lib/AST/ByteCode/Interp.h +++ b/clang/lib/AST/ByteCode/Interp.h @@ -2052,6 +2052,14 @@ inline bool GetRefLocal(InterpState &S, CodePtr OpPC, uint32_t I) { inline bool GetRefGlobal(InterpState &S, CodePtr OpPC, uint32_t I) { Block *B = S.P.getGlobal(I); + // If we're currently evaluating this variable, use that in-flight value. + // It will otherwise be diagnosed as non-initialized reference and we will + // complain about a missing initializer. + if (S.EvaluatingDecl && B->getDescriptor()->asVarDecl() == S.EvaluatingDecl) { + S.Stk.push(B); + return true; + } + if (isConstexprUnknown(B)) { S.Stk.push(B); return true; diff --git a/clang/lib/AST/ByteCode/InterpFrame.cpp b/clang/lib/AST/ByteCode/InterpFrame.cpp index 5eb8273af17f2..7366aca114ca0 100644 --- a/clang/lib/AST/ByteCode/InterpFrame.cpp +++ b/clang/lib/AST/ByteCode/InterpFrame.cpp @@ -287,6 +287,7 @@ SourceInfo InterpFrame::getSource(CodePtr PC) const { SourceInfo Result = S.getSource(Func, PC); if (Result.getLoc().isInvalid() && Caller) return Caller->getSource(RetPC); + return Result; } diff --git a/clang/lib/AST/ByteCode/InterpState.h b/clang/lib/AST/ByteCode/InterpState.h index 92073cebcd490..4e4a053d6bbed 100644 --- a/clang/lib/AST/ByteCode/InterpState.h +++ b/clang/lib/AST/ByteCode/InterpState.h @@ -32,6 +32,13 @@ struct StdAllocatorCaller { explicit operator bool() { return Call; } }; +// FIXME: Create one for the "checking potential constant expression" +// evaluation. +enum class EvaluationKind : uint8_t { + None, + Dtor, /// We're checking for constant destruction of a global variable. +}; + /// Interpreter context. class InterpState final : public State, public SourceMapper { public: @@ -132,6 +139,31 @@ class InterpState final : public State, public SourceMapper { return false; } + bool lifetimeStartedInEvaluation(const Block *B) const { + if (EvalKind == EvaluationKind::None) + return B->getEvalID() == EvalID; + + if (EvalKind == EvaluationKind::Dtor) { + assert(EvaluatingDecl); + if (B->getDescriptor()->asVarDecl() == EvaluatingDecl) + return EvaluatingDecl->getType().isConstQualified(); + } + return false; + } + + /// Return if we're checking if a global variable has a constant destructor. + bool checkingConstantDestruction() const { + return EvalKind == EvaluationKind::Dtor; + } + /// Return if we're checking if a global variable has a constant destructor + /// and the given pointer is pointing to the variable we're checking that for. + bool checkingConstantDestruction(const Pointer &Ptr) const { + return checkingConstantDestruction(Ptr.getDeclDesc()->asVarDecl()); + } + bool checkingConstantDestruction(const VarDecl *VD) const { + return EvalKind == EvaluationKind::Dtor && VD == EvaluatingDecl; + } + private: friend class EvaluationResult; friend class InterpStateCCOverride; @@ -167,6 +199,8 @@ class InterpState final : public State, public SourceMapper { /// ID identifying this evaluation. const unsigned EvalID; + EvaluationKind EvalKind = EvaluationKind::None; + /// Things needed to do speculative execution. SmallVectorImpl *PrevDiags = nullptr; bool PrevDiagsEmitted = false; diff --git a/clang/lib/AST/CommentLexer.cpp b/clang/lib/AST/CommentLexer.cpp index a0903d0903dd8..a8ac08c90c630 100644 --- a/clang/lib/AST/CommentLexer.cpp +++ b/clang/lib/AST/CommentLexer.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "clang/AST/CommentLexer.h" +#include "clang/AST/Comment.h" #include "clang/AST/CommentCommandTraits.h" #include "clang/Basic/CharInfo.h" #include "clang/Basic/DiagnosticComment.h" @@ -420,7 +421,10 @@ void Lexer::lexCommentText(Token &T) { << FullRange << CommandName << CorrectedName << FixItHint::CreateReplacement(CommandRange, CorrectedName); } else { - formTokenWithChars(T, TokenPtr, tok::unknown_command); + formTokenWithChars(T, TokenPtr, + CommandKind == tok::backslash_command + ? tok::unknown_backslash_command + : tok::unknown_at_command); T.setUnknownCommandName(CommandName); Diag(T.getLocation(), diag::warn_unknown_comment_command_name) << SourceRange(T.getLocation(), T.getEndLocation()); diff --git a/clang/lib/AST/CommentParser.cpp b/clang/lib/AST/CommentParser.cpp index 68f18cfb5173e..87f8c870919d1 100644 --- a/clang/lib/AST/CommentParser.cpp +++ b/clang/lib/AST/CommentParser.cpp @@ -726,10 +726,12 @@ BlockContentComment *Parser::parseParagraphOrBlockCommand() { case tok::eof: break; // Block content or EOF ahead, finish this parapgaph. - case tok::unknown_command: - Content.push_back(S.actOnUnknownCommand(Tok.getLocation(), - Tok.getEndLocation(), - Tok.getUnknownCommandName())); + case tok::unknown_backslash_command: + case tok::unknown_at_command: + Content.push_back(S.actOnUnknownCommand( + Tok.getLocation(), Tok.getEndLocation(), Tok.getUnknownCommandName(), + Tok.getKind() == tok::unknown_backslash_command ? CMK_Backslash + : CMK_At)); consumeToken(); continue; @@ -751,9 +753,9 @@ BlockContentComment *Parser::parseParagraphOrBlockCommand() { continue; } if (Info->IsUnknownCommand) { - Content.push_back(S.actOnUnknownCommand(Tok.getLocation(), - Tok.getEndLocation(), - Info->getID())); + Content.push_back(S.actOnUnknownCommand( + Tok.getLocation(), Tok.getEndLocation(), Info->getID(), + Tok.getKind() == tok::backslash_command ? CMK_Backslash : CMK_At)); consumeToken(); continue; } @@ -892,7 +894,8 @@ VerbatimLineComment *Parser::parseVerbatimLine() { BlockContentComment *Parser::parseBlockContent() { switch (Tok.getKind()) { case tok::text: - case tok::unknown_command: + case tok::unknown_backslash_command: + case tok::unknown_at_command: case tok::backslash_command: case tok::at_command: case tok::html_start_tag: diff --git a/clang/lib/AST/CommentSema.cpp b/clang/lib/AST/CommentSema.cpp index e74c7cb5ce605..bc7884f1ffd52 100644 --- a/clang/lib/AST/CommentSema.cpp +++ b/clang/lib/AST/CommentSema.cpp @@ -376,19 +376,21 @@ Sema::actOnInlineCommand(SourceLocation CommandLocBegin, getInlineCommandRenderKind(CommandName), CommandMarker, Args); } -InlineContentComment *Sema::actOnUnknownCommand(SourceLocation LocBegin, - SourceLocation LocEnd, - StringRef CommandName) { +InlineContentComment * +Sema::actOnUnknownCommand(SourceLocation LocBegin, SourceLocation LocEnd, + StringRef CommandName, + CommandMarkerKind CommandMarker) { unsigned CommandID = Traits.registerUnknownCommand(CommandName)->getID(); - return actOnUnknownCommand(LocBegin, LocEnd, CommandID); + return actOnUnknownCommand(LocBegin, LocEnd, CommandID, CommandMarker); } -InlineContentComment *Sema::actOnUnknownCommand(SourceLocation LocBegin, - SourceLocation LocEnd, - unsigned CommandID) { +InlineContentComment * +Sema::actOnUnknownCommand(SourceLocation LocBegin, SourceLocation LocEnd, + unsigned CommandID, CommandMarkerKind CommandMarker) { ArrayRef Args; - return new (Allocator) InlineCommandComment( - LocBegin, LocEnd, CommandID, InlineCommandRenderKind::Normal, Args); + return new (Allocator) InlineCommandComment(LocBegin, LocEnd, CommandID, + InlineCommandRenderKind::Normal, + CommandMarker, Args); } TextComment *Sema::actOnText(SourceLocation LocBegin, diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 28ac44edd800c..1d359339b9104 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -21748,8 +21748,6 @@ bool VarDecl::evaluateDestruction( EvalInfo Info(Ctx, EStatus, IsConstantDestruction ? EvaluationMode::ConstantExpression : EvaluationMode::ConstantFold); - Info.setEvaluatingDecl(this, DestroyedValue, - EvalInfo::EvaluatingDeclKind::Dtor); Info.InConstantContext = IsConstantDestruction; if (!Ctx.getInterpContext().evaluateDestruction(Info, this, std::move(DestroyedValue))) diff --git a/clang/lib/Analysis/FlowSensitive/WatchedLiteralsSolver.cpp b/clang/lib/Analysis/FlowSensitive/WatchedLiteralsSolver.cpp index a39f0e0b29ad1..98109faff222a 100644 --- a/clang/lib/Analysis/FlowSensitive/WatchedLiteralsSolver.cpp +++ b/clang/lib/Analysis/FlowSensitive/WatchedLiteralsSolver.cpp @@ -162,9 +162,11 @@ class WatchedLiteralsSolverImpl { // FIXME: Consider replacing these with test cases that fail if the any // of the invariants is broken. That might not be easy due to the // transformations performed by `buildCNF`. +#ifdef EXPENSIVE_CHECKS assert(activeVarsAreUnassigned()); assert(activeVarsFormWatchedLiterals()); assert(unassignedVarsFormingWatchedLiteralsAreActive()); +#endif const Variable ActiveVar = ActiveVars[I]; diff --git a/clang/lib/Analysis/LifetimeSafety/Checker.cpp b/clang/lib/Analysis/LifetimeSafety/Checker.cpp index c258a1dc3596c..746ebbfb15c39 100644 --- a/clang/lib/Analysis/LifetimeSafety/Checker.cpp +++ b/clang/lib/Analysis/LifetimeSafety/Checker.cpp @@ -68,6 +68,7 @@ class LifetimeChecker { LifetimeSafetySemaHelper *SemaHelper; ASTContext &AST; const Decl *FD; + const LifetimeSafetyOpts &LSOpts; static SourceLocation GetFactLoc(llvm::PointerUnion F) { @@ -87,10 +88,11 @@ class LifetimeChecker { const MovedLoansAnalysis &MovedLoans, const LiveOriginsAnalysis &LiveOrigins, FactManager &FM, AnalysisDeclContext &ADC, - LifetimeSafetySemaHelper *SemaHelper) + LifetimeSafetySemaHelper *SemaHelper, + const LifetimeSafetyOpts &LSOpts) : LoanPropagation(LoanPropagation), MovedLoans(MovedLoans), LiveOrigins(LiveOrigins), FactMgr(FM), SemaHelper(SemaHelper), - AST(ADC.getASTContext()), FD(ADC.getDecl()) { + AST(ADC.getASTContext()), FD(ADC.getDecl()), LSOpts(LSOpts) { for (const CFGBlock *B : *ADC.getAnalysis()) for (const Fact *F : FactMgr.getFacts(B)) if (const auto *EF = F->getAs()) @@ -398,6 +400,9 @@ class LifetimeChecker { void suggestAnnotations() { if (!SemaHelper) return; + if (!LSOpts.SuggestAnnotations) + return; + llvm::TimeTraceScope TimeTrace("SuggestAnnotations"); for (auto [Target, EscapeTarget] : AnnotationWarningsMap) { if (const auto *PVD = Target.dyn_cast()) suggestWithScopeForParmVar(PVD, EscapeTarget); @@ -535,9 +540,10 @@ void runLifetimeChecker(const LoanPropagationAnalysis &LP, const MovedLoansAnalysis &MovedLoans, const LiveOriginsAnalysis &LO, FactManager &FactMgr, AnalysisDeclContext &ADC, - LifetimeSafetySemaHelper *SemaHelper) { + LifetimeSafetySemaHelper *SemaHelper, + const LifetimeSafetyOpts &LSOpts) { llvm::TimeTraceScope TimeProfile("LifetimeChecker"); - LifetimeChecker Checker(LP, MovedLoans, LO, FactMgr, ADC, SemaHelper); + LifetimeChecker Checker(LP, MovedLoans, LO, FactMgr, ADC, SemaHelper, LSOpts); } } // namespace clang::lifetimes::internal diff --git a/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp b/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp index 714f979fa5ee7..680095a54177c 100644 --- a/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp +++ b/clang/lib/Analysis/LifetimeSafety/LifetimeSafety.cpp @@ -96,7 +96,7 @@ void LifetimeSafetyAnalysis::run() { Factory.MovedLoansMapFactory); runLifetimeChecker(*LoanPropagation, *MovedLoans, *LiveOrigins, *FactMgr, AC, - SemaHelper); + SemaHelper, LSOpts); DEBUG_WITH_TYPE("PrintCFG", Cfg.dump(AC.getASTContext().getLangOpts(), /*ShowColors=*/true)); @@ -122,11 +122,8 @@ void collectLifetimeStats(AnalysisDeclContext &AC, OriginManager &OM, void runLifetimeSafetyAnalysis(AnalysisDeclContext &AC, LifetimeSafetySemaHelper *SemaHelper, + const LifetimeSafetyOpts &LSOpts, LifetimeSafetyStats &Stats, bool CollectStats) { - LifetimeSafetyOpts LSOpts; - LSOpts.MaxCFGBlocks = - AC.getASTContext().getLangOpts().LifetimeSafetyMaxCFGBlocks; - internal::LifetimeSafetyAnalysis Analysis(AC, SemaHelper, LSOpts); Analysis.run(); if (CollectStats) diff --git a/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp b/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp index 1a565b077a2eb..df60005d77259 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp @@ -1068,10 +1068,10 @@ void CIRGenFunction::emitNewArrayInitializer( remainingSize = builder.createSub(loc, remainingSize, initSizeOp); } - // Create the memset. - mlir::Value castOp = - builder.createPtrBitcast(curPtr.getPointer(), cgm.voidTy); - builder.createMemSet(loc, castOp, builder.getConstInt(loc, cgm.uInt8Ty, 0), + // Create the memset. Use the Address overload so the destination + // alignment from curPtr is carried onto the memset. + Address voidPtr = curPtr.withElementType(builder, cgm.voidTy); + builder.createMemSet(loc, voidPtr, builder.getConstInt(loc, cgm.uInt8Ty, 0), remainingSize); return true; }; @@ -1228,12 +1228,11 @@ void CIRGenFunction::emitNewArrayInitializer( if (ctor->isTrivial()) { // If new expression did not specify value-initialization, then there // is no initialization. - if (!cce->requiresZeroInitialization()) + if (!cce->requiresZeroInitialization() || ctor->getParent()->isEmpty()) return; - cgm.errorNYI(cce->getSourceRange(), - "emitNewArrayInitializer: trivial ctor zero-init"); - return; + if (tryMemsetInitialization()) + return; } // Store the new Cleanup position for irregular Cleanups. diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h index b6a4a277fab92..0ce6005ccac88 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.h +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h @@ -2566,10 +2566,6 @@ class CIRGenFunction : public CIRGenTypeCache { void emitOMPDeclareMapper(const OMPDeclareMapperDecl &d); void emitOMPRequiresDecl(const OMPRequiresDecl &d); -private: - template - void emitOpenMPClauses(Op &op, ArrayRef clauses); - //===--------------------------------------------------------------------===// // OpenACC Emission //===--------------------------------------------------------------------===// diff --git a/clang/lib/CIR/CodeGen/CIRGenOpenMPClause.cpp b/clang/lib/CIR/CodeGen/CIRGenOpenMPClause.cpp index a0f0ea9299c8d..16ac4440660b5 100644 --- a/clang/lib/CIR/CodeGen/CIRGenOpenMPClause.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenOpenMPClause.cpp @@ -6,90 +6,140 @@ // //===----------------------------------------------------------------------===// // -// Emit OpenMP clause nodes as CIR code. +// OpenMP clause emitter implementation. // //===----------------------------------------------------------------------===// +#include "CIRGenOpenMPClause.h" #include "CIRGenFunction.h" #include "mlir/Dialect/OpenMP/OpenMPDialect.h" +#include "clang/Basic/OpenMPKinds.h" using namespace clang; using namespace clang::CIRGen; -namespace { -template -class OpenMPClauseCIREmitter final - : public ConstOMPClauseVisitor> { - OpTy &operation; - CIRGen::CIRGenFunction &cgf; - CIRGen::CIRGenBuilderTy &builder; - -public: - OpenMPClauseCIREmitter(OpTy &operation, CIRGen::CIRGenFunction &cgf, - CIRGen::CIRGenBuilderTy &builder) - : operation(operation), cgf(cgf), builder(builder) {} - - void VisitOMPClause(const OMPClause *clause) { - cgf.cgm.errorNYI(clause->getBeginLoc(), "OpenMPClause ", - llvm::omp::getOpenMPClauseName(clause->getClauseKind())); +static mlir::omp::ClauseMapFlags +mapClauseKindToFlags(OpenMPMapClauseKind kind) { + switch (kind) { + case OMPC_MAP_to: + return mlir::omp::ClauseMapFlags::to; + case OMPC_MAP_from: + return mlir::omp::ClauseMapFlags::from; + case OMPC_MAP_tofrom: + return mlir::omp::ClauseMapFlags::to | mlir::omp::ClauseMapFlags::from; + case OMPC_MAP_alloc: + case OMPC_MAP_release: + return mlir::omp::ClauseMapFlags::storage; + case OMPC_MAP_delete: + return mlir::omp::ClauseMapFlags::del; + default: + return mlir::omp::ClauseMapFlags::none; } +} - void VisitOMPProcBindClause(const OMPProcBindClause *clause) { - if constexpr (std::is_same_v) { - mlir::omp::ClauseProcBindKind kind; - switch (clause->getProcBindKind()) { - case llvm::omp::ProcBindKind::OMP_PROC_BIND_master: - kind = mlir::omp::ClauseProcBindKind::Master; - break; - case llvm::omp::ProcBindKind::OMP_PROC_BIND_close: - kind = mlir::omp::ClauseProcBindKind::Close; - break; - case llvm::omp::ProcBindKind::OMP_PROC_BIND_spread: - kind = mlir::omp::ClauseProcBindKind::Spread; - break; - case llvm::omp::ProcBindKind::OMP_PROC_BIND_primary: - kind = mlir::omp::ClauseProcBindKind::Primary; - break; - case llvm::omp::ProcBindKind::OMP_PROC_BIND_default: - // 'default' in the classic-codegen does no runtime call/doesn't - // really do anything. So this is a no-op, and thus shouldn't change - // the IR. - return; - case llvm::omp::ProcBindKind::OMP_PROC_BIND_unknown: - llvm_unreachable("unknown proc-bind kind"); - } - operation.setProcBindKind(kind); - } else { - cgf.cgm.errorNYI( - clause->getBeginLoc(), - "OMPProcBindClause unimplemented on this directive kind"); - } - } +static mlir::Value emitMapInfoForVar(CIRGenFunction &cgf, + mlir::OpBuilder &builder, + mlir::Location loc, const VarDecl *vd, + mlir::omp::ClauseMapFlags mapFlags) { + Address addr = cgf.getAddrOfLocalVar(vd); + mlir::Value varPtr = addr.getPointer(); + auto varPtrType = mlir::cast(varPtr.getType()); + mlir::Type elementType = varPtrType.getPointee(); - void emitClauses(ArrayRef clauses) { - for (const auto *c : clauses) - this->Visit(c); + // Cast to generic pointer if needed. + if (varPtrType.getAddrSpace()) { + auto genericPtrType = + cir::PointerType::get(builder.getContext(), elementType); + varPtr = cir::CastOp::create(builder, loc, genericPtrType, + cir::CastKind::address_space, varPtr); + varPtrType = genericPtrType; } -}; -template -auto makeClauseEmitter(OpTy &op, CIRGen::CIRGenFunction &cgf, - CIRGen::CIRGenBuilderTy &builder) { - return OpenMPClauseCIREmitter(op, cgf, builder); + + return mlir::omp::MapInfoOp::create( + builder, loc, + /*omp_ptr=*/varPtrType, + /*var_ptr=*/varPtr, + /*var_ptr_type=*/mlir::TypeAttr::get(elementType), + /*map_type=*/builder.getAttr(mapFlags), + /*map_capture_type=*/ + builder.getAttr( + mlir::omp::VariableCaptureKind::ByRef), + /*var_ptr_ptr=*/mlir::Value{}, + /*var_ptr_ptr_type=*/mlir::TypeAttr{}, + /*members=*/mlir::ValueRange{}, + /*members_index=*/mlir::ArrayAttr{}, + /*bounds=*/mlir::ValueRange{}, + /*mapper_id=*/mlir::FlatSymbolRefAttr{}, + /*name=*/builder.getStringAttr(vd->getName()), + /*partial_map=*/builder.getBoolAttr(false)); } -} // namespace - -template -void CIRGenFunction::emitOpenMPClauses(Op &op, - ArrayRef clauses) { - mlir::OpBuilder::InsertionGuard guardCase(builder); - builder.setInsertionPoint(op); - makeClauseEmitter(op, *this, builder).emitClauses(clauses); + +bool OpenMPClauseEmitter::emitProcBind( + mlir::omp::ProcBindClauseOps &result) const { + for (const OMPClause *clause : clauses) { + const auto *pbc = dyn_cast(clause); + if (!pbc) + continue; + + llvm::omp::ProcBindKind kind = pbc->getProcBindKind(); + assert(kind != llvm::omp::ProcBindKind::OMP_PROC_BIND_unknown && + "unknown proc-bind kind"); + // The 'default' kind has no dialect counterpart; leave the attribute unset. + if (kind != llvm::omp::ProcBindKind::OMP_PROC_BIND_default) + result.procBindKind = mlir::omp::ClauseProcBindKindAttr::get( + builder.getContext(), mlir::omp::convertProcBindKind(kind)); + return true; + } + return false; } -// We're defining the template for this in a .cpp file, so we have to explicitly -// specialize the templates. -#define EXPL_SPEC(N) \ - template void CIRGenFunction::emitOpenMPClauses( \ - N &, ArrayRef); -EXPL_SPEC(mlir::omp::ParallelOp) -#undef EXPL_SPEC +bool OpenMPClauseEmitter::emitMap( + mlir::omp::MapClauseOps &result, + llvm::SmallVectorImpl *mapSyms) const { + bool found = false; + for (const OMPClause *clause : clauses) { + const auto *mc = dyn_cast(clause); + if (!mc) + continue; + + found = true; + + for (OpenMPMapModifierKind mod : mc->getMapTypeModifiers()) { + if (mod != OMPC_MAP_MODIFIER_unknown) + cgm.errorNYI(mc->getBeginLoc(), + std::string("OpenMP map modifier '") + + getOpenMPSimpleClauseTypeName( + llvm::omp::Clause::OMPC_map, mod) + + "'"); + } + + if (mc->isImplicit()) { + cgm.errorNYI(mc->getBeginLoc(), "OpenMP implicit map clause"); + continue; + } + + mlir::omp::ClauseMapFlags mapFlags = mapClauseKindToFlags(mc->getMapType()); + + for (const Expr *varExpr : mc->varlist()) { + const auto *refExpr = dyn_cast(varExpr->IgnoreImplicit()); + if (!refExpr) { + cgm.errorNYI(varExpr->getExprLoc(), + "OpenMP map clause with non-DeclRefExpr variable"); + continue; + } + + const auto *vd = dyn_cast(refExpr->getDecl()); + if (!vd) { + cgm.errorNYI(varExpr->getExprLoc(), + "OpenMP map clause with non-VarDecl variable"); + continue; + } + + result.mapVars.push_back( + emitMapInfoForVar(cgf, builder, loc, vd, mapFlags)); + if (mapSyms) + mapSyms->push_back(vd); + } + } + return found; +} diff --git a/clang/lib/CIR/CodeGen/CIRGenOpenMPClause.h b/clang/lib/CIR/CodeGen/CIRGenOpenMPClause.h new file mode 100644 index 0000000000000..54c7366b1d769 --- /dev/null +++ b/clang/lib/CIR/CodeGen/CIRGenOpenMPClause.h @@ -0,0 +1,88 @@ +//===--- CIRGenOpenMPClause.h - OpenMP clause emitter -----------*- 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_LIB_CIR_CODEGEN_CIRGENOPENMPCLAUSE_H +#define LLVM_CLANG_LIB_CIR_CODEGEN_CIRGENOPENMPCLAUSE_H + +#include "CIRGenBuilder.h" +#include "CIRGenModule.h" +#include "mlir/Dialect/OpenMP/OpenMPClauseOperands.h" +#include "clang/AST/OpenMPClause.h" +#include "clang/AST/StmtOpenMP.h" +#include "llvm/Frontend/OpenMP/OMPConstants.h" + +#include + +namespace clang::CIRGen { + +class CIRGenFunction; + +/// A type-only list of OpenMP clause AST node types. +template struct OpenMPNYIClauseList {}; + +/// Emits OpenMP clauses for a directive, writing results into the +/// auto-generated ClauseOps from the OMP dialect. +class OpenMPClauseEmitter { + CIRGenFunction &cgf; + CIRGenModule &cgm; + CIRGenBuilderTy &builder; + mlir::Location loc; + llvm::ArrayRef clauses; + +public: + OpenMPClauseEmitter(CIRGenFunction &cgf, CIRGenModule &cgm, + CIRGenBuilderTy &builder, mlir::Location loc, + llvm::ArrayRef clauses) + : cgf(cgf), cgm(cgm), builder(builder), loc(loc), clauses(clauses) {} + + bool emitProcBind(mlir::omp::ProcBindClauseOps &result) const; + + /// Emit map clauses. The optional \p mapSyms parameter collects the + /// VarDecls corresponding to each map operand. + bool emitMap(mlir::omp::MapClauseOps &result, + llvm::SmallVectorImpl *mapSyms = nullptr) const; + + /// Verify the clauses of a directive to make sure all legal cases are either + /// implemented or give a NYI error. The \p SupportedClauses and \p + /// NYIClauses type lists must be disjoint and cover all clauses eligible for + /// the directive being processed. + template + void emitNYI(OpenMPNYIClauseList nyi, + llvm::omp::Directive directive) const; + +private: + /// True if T is the same type as any of Ts. + template + static constexpr bool isAnyOf = (std::is_same_v || ...); +}; + +template +void OpenMPClauseEmitter::emitNYI(OpenMPNYIClauseList, + llvm::omp::Directive directive) const { + static_assert( + (!isAnyOf && ...), + "the supported and not-yet-implemented clause lists must be disjoint"); + + for (const OMPClause *c : clauses) { + if (isa(c)) { + std::string msg = + (llvm::Twine("OpenMP ") + + llvm::omp::getOpenMPDirectiveName(directive).upper() + " '" + + llvm::omp::getOpenMPClauseName(c->getClauseKind()) + "' clause") + .str(); + cgm.errorNYI(c->getBeginLoc(), msg); + } else if (!isa(c)) { + // Unknown/illegal clause encountered. + llvm_unreachable("unexpected OpenMP clause"); + } + } +} + +} // namespace clang::CIRGen + +#endif // LLVM_CLANG_LIB_CIR_CODEGEN_CIRGENOPENMPCLAUSE_H diff --git a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp index 47c94cb4ec535..a2c999f584399 100644 --- a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp @@ -421,7 +421,6 @@ mlir::LogicalResult CIRGenFunction::emitStmt(const Stmt *s, case Stmt::CaseStmtClass: case Stmt::SEHLeaveStmtClass: case Stmt::SYCLKernelCallStmtClass: - case Stmt::CapturedStmtClass: case Stmt::ObjCAtTryStmtClass: case Stmt::ObjCAtThrowStmtClass: case Stmt::ObjCAtSynchronizedStmtClass: @@ -434,6 +433,8 @@ mlir::LogicalResult CIRGenFunction::emitStmt(const Stmt *s, cgm.errorNYI(s->getSourceRange(), std::string("emitStmt: ") + s->getStmtClassName()); return mlir::failure(); + case Stmt::CapturedStmtClass: + llvm_unreachable("CapturedStmt must be handled by the parent directive"); } llvm_unreachable("Unexpected statement class"); diff --git a/clang/lib/CIR/CodeGen/CIRGenStmtOpenMP.cpp b/clang/lib/CIR/CodeGen/CIRGenStmtOpenMP.cpp index eb4934644b519..17a1fb8090f5c 100644 --- a/clang/lib/CIR/CodeGen/CIRGenStmtOpenMP.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenStmtOpenMP.cpp @@ -12,7 +12,9 @@ #include "CIRGenBuilder.h" #include "CIRGenFunction.h" +#include "CIRGenOpenMPClause.h" #include "mlir/Dialect/OpenMP/OpenMPDialect.h" +#include "clang/AST/OpenMPClause.h" #include "clang/AST/StmtOpenMP.h" #include "llvm/Frontend/OpenMP/OMPConstants.h" using namespace clang; @@ -31,14 +33,20 @@ CIRGenFunction::emitOMPErrorDirective(const OMPErrorDirective &s) { mlir::LogicalResult CIRGenFunction::emitOMPParallelDirective(const OMPParallelDirective &s) { mlir::LogicalResult res = mlir::success(); - llvm::SmallVector retTy; - llvm::SmallVector operands; mlir::Location begin = getLoc(s.getBeginLoc()); mlir::Location end = getLoc(s.getEndLoc()); - auto parallelOp = - mlir::omp::ParallelOp::create(builder, begin, retTy, operands); - emitOpenMPClauses(parallelOp, s.clauses()); + mlir::omp::ParallelOperands clauseOps; + OpenMPClauseEmitter ce(*this, getCIRGenModule(), builder, begin, s.clauses()); + ce.emitProcBind(clauseOps); + ce.emitNYI( + /*nyi=*/OpenMPNYIClauseList< + OMPAllocateClause, OMPCopyinClause, OMPDefaultClause, + OMPFirstprivateClause, OMPIfClause, OMPNumThreadsClause, + OMPPrivateClause, OMPReductionClause, OMPSharedClause>{}, + llvm::omp::Directive::OMPD_parallel); + + auto parallelOp = mlir::omp::ParallelOp::create(builder, begin, clauseOps); { mlir::Block &block = parallelOp.getRegion().emplaceBlock(); @@ -207,10 +215,108 @@ CIRGenFunction::emitOMPAtomicDirective(const OMPAtomicDirective &s) { getCIRGenModule().errorNYI(s.getSourceRange(), "OpenMP OMPAtomicDirective"); return mlir::failure(); } + +/// Check for unsupported implicit captures in a target region. +static void +emitOMPTargetImplicitCaptures(CIRGenFunction &cgf, const OMPTargetDirective &s, + llvm::ArrayRef mapSyms) { + const CapturedStmt *cs = s.getCapturedStmt(llvm::omp::OMPD_target); + for (const auto &capture : cs->captures()) { + if (capture.capturesThis()) { + cgf.getCIRGenModule().errorNYI(s.getBeginLoc(), + "OpenMP target capture of 'this' pointer"); + continue; + } + if (capture.capturesVariableByCopy()) { + cgf.getCIRGenModule().errorNYI(s.getBeginLoc(), + "OpenMP target capture by copy"); + continue; + } + if (capture.capturesVariableArrayType()) { + cgf.getCIRGenModule().errorNYI( + s.getBeginLoc(), + "OpenMP target capture of variable-length array type"); + continue; + } + if (capture.capturesVariable()) { + const VarDecl *vd = capture.getCapturedVar(); + if (llvm::is_contained(mapSyms, vd)) + continue; + + cgf.getCIRGenModule().errorNYI(s.getBeginLoc(), + "OpenMP target implicit by-ref capture"); + } + } +} + +/// Emit the body of an omp.target region, remapping mapped variables to the +/// block arguments of the target op's region. +static mlir::LogicalResult +emitOMPTargetBody(CIRGenFunction &cgf, const OMPTargetDirective &s, + mlir::omp::TargetOp targetOp, + llvm::ArrayRef mapVars, + llvm::ArrayRef mappedVarDecls, + mlir::Location begin, mlir::Location end) { + mlir::Block &block = targetOp.getRegion().emplaceBlock(); + + for (mlir::Value mapVar : mapVars) + block.addArgument(mapVar.getType(), begin); + + mlir::OpBuilder::InsertionGuard guard(cgf.getBuilder()); + cgf.getBuilder().setInsertionPointToEnd(&block); + + CIRGenFunction::LexicalScope ls{cgf, begin, + cgf.getBuilder().getInsertionBlock()}; + + llvm::SmallVector> savedAddrs; + for (auto [idx, vd] : llvm::enumerate(mappedVarDecls)) { + Address origAddr = cgf.getAddrOfLocalVar(vd); + savedAddrs.push_back({vd, origAddr}); + mlir::Value blockArg = block.getArgument(idx); + cgf.replaceAddrOfLocalVar(vd, Address(blockArg, origAddr.getAlignment())); + } + + const CapturedStmt *cs = s.getCapturedStmt(llvm::omp::OMPD_target); + mlir::LogicalResult res = + cgf.emitStmt(cs->getCapturedStmt(), /*useCurrentScope=*/true); + + mlir::omp::TerminatorOp::create(cgf.getBuilder(), end); + + for (auto &[vd, addr] : savedAddrs) + cgf.replaceAddrOfLocalVar(vd, addr); + + return res; +} + mlir::LogicalResult CIRGenFunction::emitOMPTargetDirective(const OMPTargetDirective &s) { - getCIRGenModule().errorNYI(s.getSourceRange(), "OpenMP OMPTargetDirective"); - return mlir::failure(); + mlir::Location begin = getLoc(s.getBeginLoc()); + mlir::Location end = getLoc(s.getEndLoc()); + + mlir::omp::TargetExtOperands clauseOps; + llvm::SmallVector mapSyms; + + OpenMPClauseEmitter ce(*this, getCIRGenModule(), builder, begin, s.clauses()); + ce.emitMap(clauseOps, &mapSyms); + ce.emitNYI( + /*nyi=*/OpenMPNYIClauseList< + OMPAllocateClause, OMPDefaultClause, OMPDefaultmapClause, + OMPDependClause, OMPDeviceClause, OMPFirstprivateClause, + OMPHasDeviceAddrClause, OMPIfClause, OMPInReductionClause, + OMPIsDevicePtrClause, OMPNowaitClause, OMPPrivateClause, + OMPThreadLimitClause, OMPUsesAllocatorsClause, OMPXBareClause>{}, + llvm::omp::Directive::OMPD_target); + + emitOMPTargetImplicitCaptures(*this, s, mapSyms); + + // Use generic for now. + clauseOps.kernelType = mlir::omp::TargetExecModeAttr::get( + &getMLIRContext(), mlir::omp::TargetExecMode::generic); + + auto targetOp = mlir::omp::TargetOp::create(builder, begin, clauseOps); + + return emitOMPTargetBody(*this, s, targetOp, clauseOps.mapVars, mapSyms, + begin, end); } mlir::LogicalResult CIRGenFunction::emitOMPTeamsDirective(const OMPTeamsDirective &s) { diff --git a/clang/lib/Headers/__clang_hip_libdevice_declares.h b/clang/lib/Headers/__clang_hip_libdevice_declares.h index 565c68334023a..ad40e76f5d861 100644 --- a/clang/lib/Headers/__clang_hip_libdevice_declares.h +++ b/clang/lib/Headers/__clang_hip_libdevice_declares.h @@ -29,9 +29,6 @@ __device__ __attribute__((const)) float __ocml_atan2_f32(float, float); __device__ __attribute__((const)) float __ocml_atan_f32(float); __device__ __attribute__((pure)) float __ocml_atanh_f32(float); __device__ __attribute__((pure)) float __ocml_cbrt_f32(float); -__device__ __attribute__((const)) float __ocml_ceil_f32(float); -__device__ __attribute__((const)) __device__ float __ocml_copysign_f32(float, - float); __device__ float __ocml_cos_f32(float); __device__ float __ocml_native_cos_f32(float); __device__ __attribute__((pure)) __device__ float __ocml_cosh_f32(float); @@ -43,40 +40,17 @@ __device__ __attribute__((pure)) float __ocml_erfcinv_f32(float); __device__ __attribute__((pure)) float __ocml_erfcx_f32(float); __device__ __attribute__((pure)) float __ocml_erf_f32(float); __device__ __attribute__((pure)) float __ocml_erfinv_f32(float); -__device__ __attribute__((pure)) float __ocml_exp10_f32(float); -__device__ __attribute__((pure)) float __ocml_native_exp10_f32(float); -__device__ __attribute__((pure)) float __ocml_exp2_f32(float); -__device__ __attribute__((pure)) float __ocml_exp_f32(float); -__device__ __attribute__((pure)) float __ocml_native_exp_f32(float); __device__ __attribute__((pure)) float __ocml_expm1_f32(float); -__device__ __attribute__((const)) float __ocml_fabs_f32(float); __device__ __attribute__((const)) float __ocml_fdim_f32(float, float); -__device__ __attribute__((const)) float __ocml_floor_f32(float); -__device__ __attribute__((const)) float __ocml_fma_f32(float, float, float); -__device__ __attribute__((const)) float __ocml_fmax_f32(float, float); -__device__ __attribute__((const)) float __ocml_fmin_f32(float, float); __device__ __attribute__((const)) __device__ float __ocml_fmod_f32(float, float); -__device__ float __ocml_frexp_f32(float, __PRIVATE_AS int *); __device__ __attribute__((const)) float __ocml_hypot_f32(float, float); __device__ __attribute__((const)) int __ocml_ilogb_f32(float); -__device__ __attribute__((const)) int __ocml_isfinite_f32(float); -__device__ __attribute__((const)) int __ocml_isinf_f32(float); -__device__ __attribute__((const)) int __ocml_isnan_f32(float); __device__ float __ocml_j0_f32(float); __device__ float __ocml_j1_f32(float); -__device__ __attribute__((const)) float __ocml_ldexp_f32(float, int); __device__ float __ocml_lgamma_f32(float); -__device__ __attribute__((pure)) float __ocml_log10_f32(float); -__device__ __attribute__((pure)) float __ocml_native_log10_f32(float); __device__ __attribute__((pure)) float __ocml_log1p_f32(float); -__device__ __attribute__((pure)) float __ocml_log2_f32(float); -__device__ __attribute__((pure)) float __ocml_native_log2_f32(float); -__device__ __attribute__((const)) float __ocml_logb_f32(float); -__device__ __attribute__((pure)) float __ocml_log_f32(float); -__device__ __attribute__((pure)) float __ocml_native_log_f32(float); __device__ float __ocml_modf_f32(float, __PRIVATE_AS float *); -__device__ __attribute__((const)) float __ocml_nearbyint_f32(float); __device__ __attribute__((const)) float __ocml_nextafter_f32(float, float); __device__ __attribute__((const)) float __ocml_len3_f32(float, float, float); __device__ __attribute__((const)) float __ocml_len4_f32(float, float, float, @@ -89,15 +63,10 @@ __device__ __attribute__((pure)) float __ocml_rcbrt_f32(float); __device__ __attribute__((const)) float __ocml_remainder_f32(float, float); __device__ float __ocml_remquo_f32(float, float, __PRIVATE_AS int *); __device__ __attribute__((const)) float __ocml_rhypot_f32(float, float); -__device__ __attribute__((const)) float __ocml_rint_f32(float); __device__ __attribute__((const)) float __ocml_rlen3_f32(float, float, float); __device__ __attribute__((const)) float __ocml_rlen4_f32(float, float, float, float); -__device__ __attribute__((const)) float __ocml_round_f32(float); __device__ __attribute__((pure)) float __ocml_rsqrt_f32(float); -__device__ __attribute__((const)) float __ocml_scalb_f32(float, float); -__device__ __attribute__((const)) float __ocml_scalbn_f32(float, int); -__device__ __attribute__((const)) int __ocml_signbit_f32(float); __device__ float __ocml_sincos_f32(float, __PRIVATE_AS float *); __device__ float __ocml_sincospi_f32(float, __PRIVATE_AS float *); __device__ float __ocml_sin_f32(float); @@ -109,7 +78,6 @@ __device__ __attribute__((const)) float __ocml_native_sqrt_f32(float); __device__ float __ocml_tan_f32(float); __device__ __attribute__((pure)) float __ocml_tanh_f32(float); __device__ float __ocml_tgamma_f32(float); -__device__ __attribute__((const)) float __ocml_trunc_f32(float); __device__ float __ocml_y0_f32(float); __device__ float __ocml_y1_f32(float); @@ -150,8 +118,6 @@ __device__ __attribute__((const)) double __ocml_atan2_f64(double, double); __device__ __attribute__((const)) double __ocml_atan_f64(double); __device__ __attribute__((pure)) double __ocml_atanh_f64(double); __device__ __attribute__((pure)) double __ocml_cbrt_f64(double); -__device__ __attribute__((const)) double __ocml_ceil_f64(double); -__device__ __attribute__((const)) double __ocml_copysign_f64(double, double); __device__ double __ocml_cos_f64(double); __device__ __attribute__((pure)) double __ocml_cosh_f64(double); __device__ double __ocml_cospi_f64(double); @@ -166,30 +132,18 @@ __device__ __attribute__((pure)) double __ocml_exp10_f64(double); __device__ __attribute__((pure)) double __ocml_exp2_f64(double); __device__ __attribute__((pure)) double __ocml_exp_f64(double); __device__ __attribute__((pure)) double __ocml_expm1_f64(double); -__device__ __attribute__((const)) double __ocml_fabs_f64(double); __device__ __attribute__((const)) double __ocml_fdim_f64(double, double); -__device__ __attribute__((const)) double __ocml_floor_f64(double); -__device__ __attribute__((const)) double __ocml_fma_f64(double, double, double); -__device__ __attribute__((const)) double __ocml_fmax_f64(double, double); -__device__ __attribute__((const)) double __ocml_fmin_f64(double, double); __device__ __attribute__((const)) double __ocml_fmod_f64(double, double); -__device__ double __ocml_frexp_f64(double, __PRIVATE_AS int *); __device__ __attribute__((const)) double __ocml_hypot_f64(double, double); __device__ __attribute__((const)) int __ocml_ilogb_f64(double); -__device__ __attribute__((const)) int __ocml_isfinite_f64(double); -__device__ __attribute__((const)) int __ocml_isinf_f64(double); -__device__ __attribute__((const)) int __ocml_isnan_f64(double); __device__ double __ocml_j0_f64(double); __device__ double __ocml_j1_f64(double); -__device__ __attribute__((const)) double __ocml_ldexp_f64(double, int); __device__ double __ocml_lgamma_f64(double); __device__ __attribute__((pure)) double __ocml_log10_f64(double); __device__ __attribute__((pure)) double __ocml_log1p_f64(double); __device__ __attribute__((pure)) double __ocml_log2_f64(double); -__device__ __attribute__((const)) double __ocml_logb_f64(double); __device__ __attribute__((pure)) double __ocml_log_f64(double); __device__ double __ocml_modf_f64(double, __PRIVATE_AS double *); -__device__ __attribute__((const)) double __ocml_nearbyint_f64(double); __device__ __attribute__((const)) double __ocml_nextafter_f64(double, double); __device__ __attribute__((const)) double __ocml_len3_f64(double, double, double); @@ -203,26 +157,19 @@ __device__ __attribute__((pure)) double __ocml_rcbrt_f64(double); __device__ __attribute__((const)) double __ocml_remainder_f64(double, double); __device__ double __ocml_remquo_f64(double, double, __PRIVATE_AS int *); __device__ __attribute__((const)) double __ocml_rhypot_f64(double, double); -__device__ __attribute__((const)) double __ocml_rint_f64(double); __device__ __attribute__((const)) double __ocml_rlen3_f64(double, double, double); __device__ __attribute__((const)) double __ocml_rlen4_f64(double, double, double, double); -__device__ __attribute__((const)) double __ocml_round_f64(double); __device__ __attribute__((pure)) double __ocml_rsqrt_f64(double); -__device__ __attribute__((const)) double __ocml_scalb_f64(double, double); -__device__ __attribute__((const)) double __ocml_scalbn_f64(double, int); -__device__ __attribute__((const)) int __ocml_signbit_f64(double); __device__ double __ocml_sincos_f64(double, __PRIVATE_AS double *); __device__ double __ocml_sincospi_f64(double, __PRIVATE_AS double *); __device__ double __ocml_sin_f64(double); __device__ __attribute__((pure)) double __ocml_sinh_f64(double); __device__ double __ocml_sinpi_f64(double); -__device__ __attribute__((const)) double __ocml_sqrt_f64(double); __device__ double __ocml_tan_f64(double); __device__ __attribute__((pure)) double __ocml_tanh_f64(double); __device__ double __ocml_tgamma_f64(double); -__device__ __attribute__((const)) double __ocml_trunc_f64(double); __device__ double __ocml_y0_f64(double); __device__ double __ocml_y1_f64(double); @@ -256,30 +203,12 @@ __device__ __attribute__((const)) double __ocml_fma_rtp_f64(double, double, __device__ __attribute__((const)) double __ocml_fma_rtz_f64(double, double, double); -__device__ __attribute__((const)) _Float16 __ocml_ceil_f16(_Float16); __device__ _Float16 __ocml_cos_f16(_Float16); __device__ __attribute__((const)) _Float16 __ocml_cvtrtn_f16_f32(float); __device__ __attribute__((const)) _Float16 __ocml_cvtrtp_f16_f32(float); __device__ __attribute__((const)) _Float16 __ocml_cvtrtz_f16_f32(float); -__device__ __attribute__((pure)) _Float16 __ocml_exp_f16(_Float16); -__device__ __attribute__((pure)) _Float16 __ocml_exp10_f16(_Float16); -__device__ __attribute__((pure)) _Float16 __ocml_exp2_f16(_Float16); -__device__ __attribute__((const)) _Float16 __ocml_floor_f16(_Float16); -__device__ __attribute__((const)) _Float16 __ocml_fma_f16(_Float16, _Float16, - _Float16); -__device__ __attribute__((const)) _Float16 __ocml_fmax_f16(_Float16, _Float16); -__device__ __attribute__((const)) _Float16 __ocml_fmin_f16(_Float16, _Float16); -__device__ __attribute__((const)) _Float16 __ocml_fabs_f16(_Float16); -__device__ __attribute__((const)) int __ocml_isinf_f16(_Float16); -__device__ __attribute__((const)) int __ocml_isnan_f16(_Float16); -__device__ __attribute__((pure)) _Float16 __ocml_log_f16(_Float16); -__device__ __attribute__((pure)) _Float16 __ocml_log10_f16(_Float16); -__device__ __attribute__((pure)) _Float16 __ocml_log2_f16(_Float16); -__device__ __attribute__((const)) _Float16 __ocml_rint_f16(_Float16); __device__ __attribute__((const)) _Float16 __ocml_rsqrt_f16(_Float16); __device__ _Float16 __ocml_sin_f16(_Float16); -__device__ __attribute__((const)) _Float16 __ocml_sqrt_f16(_Float16); -__device__ __attribute__((const)) _Float16 __ocml_trunc_f16(_Float16); __device__ __attribute__((pure)) _Float16 __ocml_pown_f16(_Float16, int); typedef _Float16 __2f16 __attribute__((ext_vector_type(2))); @@ -323,6 +252,16 @@ __device__ void __asan_unpoison_memory_region(const void *addr, __device__ int __asan_address_is_poisoned(const void *addr); __device__ void *__asan_region_is_poisoned(void *beg, __SIZE_TYPE__ size); +__device__ __attribute__((pure)) _Float16 __ocml_exp_f16(_Float16); +__device__ __attribute__((pure)) _Float16 __ocml_exp10_f16(_Float16); +__device__ __attribute__((pure)) _Float16 __ocml_exp2_f16(_Float16); +__device__ __attribute__((const)) _Float16 __ocml_fma_f16(_Float16, _Float16, + _Float16); +__device__ __attribute__((pure)) _Float16 __ocml_log_f16(_Float16); +__device__ __attribute__((pure)) _Float16 __ocml_log10_f16(_Float16); +__device__ __attribute__((pure)) _Float16 __ocml_log2_f16(_Float16); + +__device__ __attribute__((const)) _Float16 __ocml_sqrt_f16(_Float16); #if __has_feature(address_sanitizer) #define ASAN_POISON_MEMORY_REGION(addr, size) \ __asan_poison_memory_region((addr), (size)) diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp index 52fe7765c6c6a..e070d9f1a9b85 100644 --- a/clang/lib/Sema/AnalysisBasedWarnings.cpp +++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -2929,7 +2929,9 @@ LifetimeSafetyTUAnalysis(Sema &S, TranslationUnitDecl *TU, AC.getCFGBuildOptions().AddCXXDefaultInitExprInCtors = true; AC.getCFGBuildOptions().setAllAlwaysAdd(); if (AC.getCFG()) - runLifetimeSafetyAnalysis(AC, &SemaHelper, LSStats, S.CollectStats); + runLifetimeSafetyAnalysis(AC, &SemaHelper, + lifetimes::GetLifetimeSafetyOpts(S, FD), + LSStats, S.CollectStats); } } @@ -3159,13 +3161,12 @@ void clang::sema::AnalysisBasedWarnings::IssueWarnings( } } - // TODO: Enable lifetime safety analysis for other languages once it is - // stable. if (EnableLifetimeSafetyAnalysis) { if (AC.getCFG()) { lifetimes::LifetimeSafetySemaHelperImpl LifetimeSafetySemaHelper(S); - lifetimes::runLifetimeSafetyAnalysis(AC, &LifetimeSafetySemaHelper, - LSStats, S.CollectStats); + lifetimes::runLifetimeSafetyAnalysis( + AC, &LifetimeSafetySemaHelper, lifetimes::GetLifetimeSafetyOpts(S, D), + LSStats, S.CollectStats); } } // Check for violations of "called once" parameter properties. diff --git a/clang/lib/Sema/SemaLifetimeSafety.h b/clang/lib/Sema/SemaLifetimeSafety.h index 7c78a6a1e8c31..a3d546792fe41 100644 --- a/clang/lib/Sema/SemaLifetimeSafety.h +++ b/clang/lib/Sema/SemaLifetimeSafety.h @@ -76,6 +76,26 @@ inline bool IsLifetimeSafetyEnabled(Sema &S, const Decl *D) { return false; } +inline bool ShouldSuggestLifetimeAnnotations(Sema &S, const Decl *D) { + DiagnosticsEngine &Diags = S.getDiagnostics(); + constexpr unsigned DiagIDs[] = { + diag::warn_lifetime_safety_intra_tu_param_suggestion, + diag::warn_lifetime_safety_cross_tu_param_suggestion, + diag::warn_lifetime_safety_intra_tu_this_suggestion, + diag::warn_lifetime_safety_cross_tu_this_suggestion}; + for (unsigned DiagID : DiagIDs) + if (!Diags.isIgnored(DiagID, D->getBeginLoc())) + return true; + return false; +} + +inline LifetimeSafetyOpts GetLifetimeSafetyOpts(Sema &S, const Decl *D) { + LifetimeSafetyOpts LSOpts; + LSOpts.MaxCFGBlocks = S.getLangOpts().LifetimeSafetyMaxCFGBlocks; + LSOpts.SuggestAnnotations = ShouldSuggestLifetimeAnnotations(S, D); + return LSOpts; +} + class LifetimeSafetySemaHelperImpl : public LifetimeSafetySemaHelper { public: diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index d2bb312feadc1..7d9fff1051068 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -9109,10 +9109,13 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, // it it breaks large amounts of Linux software. attr.setUsedAsTypeAttr(); break; - case ParsedAttr::AT_OpenCLPrivateAddressSpace: - case ParsedAttr::AT_OpenCLGlobalAddressSpace: case ParsedAttr::AT_OpenCLGlobalDeviceAddressSpace: case ParsedAttr::AT_OpenCLGlobalHostAddressSpace: + state.getSema().Diag(attr.getLoc(), diag::warn_deprecated_attribute) + << attr; + [[fallthrough]]; + case ParsedAttr::AT_OpenCLPrivateAddressSpace: + case ParsedAttr::AT_OpenCLGlobalAddressSpace: case ParsedAttr::AT_OpenCLLocalAddressSpace: case ParsedAttr::AT_OpenCLConstantAddressSpace: case ParsedAttr::AT_OpenCLGenericAddressSpace: diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp index 4cbcaa2721639..97c655c103b0a 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp @@ -384,7 +384,7 @@ void ExprEngine::processCallExit(ExplodedNode *CEBNode) { ExplodedNode *CEENode = Engine.makeNode(Loc, CEEState, N); if (!CEENode) - return; + continue; // Step 5: Perform the post-condition check of the CallExpr and enqueue the // result onto the work list. diff --git a/clang/test/AST/ByteCode/evaluate-dtor.cpp b/clang/test/AST/ByteCode/evaluate-dtor.cpp new file mode 100644 index 0000000000000..da0d1c2d4cafb --- /dev/null +++ b/clang/test/AST/ByteCode/evaluate-dtor.cpp @@ -0,0 +1,56 @@ +// RUN: %clang_cc1 -std=c++23 -verify=both,expected %s -fexperimental-new-constant-interpreter +// RUN: %clang_cc1 -std=c++23 -verify=both,ref %s + +struct MutableConst { + struct HasConstMember { + const int n = 4; + }; + mutable HasConstMember hcm; + constexpr ~MutableConst() { + /// This is _not_ a read. + auto *p = &hcm.n; + } +}; +constexpr MutableConst mc; + + +struct C { + static int m; + bool b; + constexpr C(bool b) : b(b){ + } + constexpr ~C() { + if (b) + m++; // both-note {{a constant expression cannot modify an object that is visible outside that expression}} + } +}; + +int C::m = 0; +constexpr C c1(false); +constexpr C c2(true); // both-error {{must have constant destruction}} \ + // both-note {{in call to}} + + + +namespace LocalVariables { + struct S { + constexpr ~S() { + int a = 0; + ++a; + } + }; + constexpr S s; +} + +namespace GlobalVariables { + struct S {}; + constexpr S s; + + struct K { + constexpr ~K() { + s.~S(); // both-note {{a constant expression cannot modify an object that is visible outside that expression}} + } + }; + constexpr K k{}; // both-error {{must have constant destruction}} \ + // both-note {{in call to}} +} diff --git a/clang/test/CIR/CodeGen/new-array-init.cpp b/clang/test/CIR/CodeGen/new-array-init.cpp new file mode 100644 index 0000000000000..a44131aad87a6 --- /dev/null +++ b/clang/test/CIR/CodeGen/new-array-init.cpp @@ -0,0 +1,75 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --check-prefixes=LLVM,LLVMCIR --input-file=%t-cir.ll %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll +// RUN: FileCheck --check-prefixes=LLVM,OGCG --input-file=%t.ll %s + +struct S { + int a; + int b; +}; + +// Value-init array new of a trivial type: () means zero-init via memset. +S *makeVar(unsigned n) { return new S[n](); } + +// CIR-LABEL: cir.func{{.*}}@_Z7makeVarj +// CIR: cir.call @_Znam( +// CIR: cir.libc.memset {{.*}} bytes at {{.*}} to + +// LLVM-LABEL: @_Z7makeVarj +// LLVM: call {{.*}} ptr @_Znam( +// LLVM: call void @llvm.memset.p0.i64(ptr{{.*}} %{{.*}}, i8 0, i64 %{{.*}}, i1 false) + +// Constant element count: the size is folded to a constant. +S *makeConst() { return new S[4](); } + +// CIR-LABEL: cir.func{{.*}}@_Z9makeConstv +// CIR: cir.call @_Znam( +// CIR: cir.libc.memset + +// LLVM-LABEL: @_Z9makeConstv +// LLVM: call {{.*}} ptr @_Znam(i64 noundef 32) +// LLVM: call void @llvm.memset.p0.i64(ptr{{.*}} %{{.*}}, i8 0, i64 32, i1 false) + +// No parens: default-init of a trivial type is a no-op (no memset). +S *makeNoInit(unsigned n) { return new S[n]; } + +// CIR-LABEL: cir.func{{.*}}@_Z10makeNoInitj +// CIR: cir.call @_Znam( +// CIR-NOT: cir.libc.memset + +// LLVM-LABEL: @_Z10makeNoInitj +// LLVM: call {{.*}} ptr @_Znam( +// LLVM-NOT: memset + +// Braced-empty value-init goes through the InitListExpr path (also memset). +S *makeBraced(unsigned n) { return new S[n]{}; } + +// CIR-LABEL: cir.func{{.*}}@_Z10makeBracedj +// CIR: cir.call @_Znam( +// CIR: cir.libc.memset + +// LLVM-LABEL: @_Z10makeBracedj +// LLVM: call {{.*}} ptr @_Znam( +// LLVM: call void @llvm.memset.p0.i64(ptr{{.*}} %{{.*}}, i8 0, i64 %{{.*}}, i1 false) + +// Non-zero-initializable element (pointer to data member): the null member +// representation is -1, not 0, so memset is not used; the constructor-loop +// path value-initializes each element to {0, -1}. +struct M { + int x; + int M::*p; +}; + +M *makeMember(unsigned n) { return new M[n](); } + +// CIR-LABEL: cir.func{{.*}}@_Z10makeMemberj +// CIR: cir.call @_Znam( +// CIR-NOT: cir.libc.memset +// CIR: cir.const #cir.const_record<{#cir.int<0> : !s32i, #cir.int<-1> : !s64i}> + +// LLVM-LABEL: @_Z10makeMemberj +// LLVM: call {{.*}} ptr @_Znam( +// LLVMCIR: store %struct.M { i32 0, i64 -1 }, ptr %{{.*}} +// OGCG: call void @llvm.memcpy.p0.p0.i64(ptr align 16 %{{.*}}, ptr align 16 @{{.*}} diff --git a/clang/test/CIR/CodeGen/new.cpp b/clang/test/CIR/CodeGen/new.cpp index b198fb1e3d0d0..56f2d1f23179a 100644 --- a/clang/test/CIR/CodeGen/new.cpp +++ b/clang/test/CIR/CodeGen/new.cpp @@ -355,11 +355,11 @@ void t_constant_size_memset_init() { // CHECK: %[[ELEM_PTR:.*]] = cir.cast bitcast %[[ALLOC_PTR]] : !cir.ptr -> !cir.ptr // CHECK: %[[VOID_PTR:.*]] = cir.cast bitcast %[[ELEM_PTR]] : !cir.ptr -> !cir.ptr // CHECK: %[[ZERO:.*]] = cir.const #cir.int<0> : !u8i -// CHECK: cir.libc.memset %[[ALLOCATION_SIZE]] bytes at %[[VOID_PTR]] to %[[ZERO]] : !cir.ptr, !u8i, !u64i +// CHECK: cir.libc.memset %[[ALLOCATION_SIZE]] bytes at %[[VOID_PTR]]{{.*}} to %[[ZERO]] : !cir.ptr, !u8i, !u64i // LLVM: define {{.*}} void @_Z27t_constant_size_memset_initv() // LLVM: %[[P:.*]] = call noundef nonnull ptr @_Znam(i64 noundef 64) -// LLVM: call void @llvm.memset.p0.i64(ptr %[[P]], i8 0, i64 64, i1 false) +// LLVM: call void @llvm.memset.p0.i64(ptr{{.*}} %[[P]], i8 0, i64 64, i1 false) // OGCG: define {{.*}} void @_Z27t_constant_size_memset_initv() // OGCG: %[[P:.*]] = call{{.*}} ptr @_Znam(i64{{.*}} 64) @@ -432,7 +432,7 @@ void t_constant_size_partial_init() { // CHECK: %[[REMAINING_SIZE:.*]] = cir.sub %[[ALLOCATION_SIZE]], %[[INIT_SIZE]] : !u64i // CHECK: %[[VOID_PTR:.*]] = cir.cast bitcast %[[ELEM_3_PTR]] : !cir.ptr -> !cir.ptr // CHECK: %[[ZERO:.*]] = cir.const #cir.int<0> : !u8i -// CHECK: cir.libc.memset %[[REMAINING_SIZE]] bytes at %[[VOID_PTR]] to %[[ZERO]] : !cir.ptr, !u8i, !u64i +// CHECK: cir.libc.memset %[[REMAINING_SIZE]] bytes at %[[VOID_PTR]]{{.*}} to %[[ZERO]] : !cir.ptr, !u8i, !u64i // LLVM: define {{.*}} void @_Z28t_constant_size_partial_initv() // LLVM: %[[P:.*]] = call noundef nonnull ptr @_Znam(i64 {{.*}} 64) @@ -442,7 +442,7 @@ void t_constant_size_partial_init() { // LLVM: %[[ELEM_2:.*]] = getelementptr i32, ptr %[[ELEM_1]], i64 1 // LLVM: store i32 3, ptr %[[ELEM_2]] // LLVM: %[[ELEM_3:.*]] = getelementptr i32, ptr %[[ELEM_2]], i64 1 -// LLVM: call void @llvm.memset.p0.i64(ptr %[[ELEM_3]], i8 0, i64 52, i1 false) +// LLVM: call void @llvm.memset.p0.i64(ptr{{.*}} %[[ELEM_3]], i8 0, i64 52, i1 false) // OGCG: define {{.*}} void @_Z28t_constant_size_partial_initv() // OGCG: %[[P:.*]] = call{{.*}} ptr @_Znam(i64{{.*}} 64) @@ -614,7 +614,7 @@ void t_new_var_size6(int n) { // CHECK: %[[REMAINING_SIZE:.*]] = cir.sub %[[ALLOC_SIZE]], %[[INIT_SIZE]] : !u64i // CHECK: %[[PTR_DOUBLE_3_VOID:.*]] = cir.cast bitcast %[[PTR_DOUBLE_3]] : !cir.ptr -> !cir.ptr // CHECK: %[[ZERO:.*]] = cir.const #cir.int<0> : !u8i -// CHECK: cir.libc.memset{{.*}} bytes at %[[PTR_DOUBLE_3_VOID]] to %[[ZERO]] +// CHECK: cir.libc.memset{{.*}} bytes at %[[PTR_DOUBLE_3_VOID]]{{.*}} to %[[ZERO]] // LLVM: define{{.*}} void @_Z15t_new_var_size6i // LLVM: %[[N:.*]] = load i32, ptr %{{.+}} @@ -633,7 +633,7 @@ void t_new_var_size6(int n) { // LLVM: store double 3.000000e+00, ptr %[[ELEM_2]], align 8 // LLVM: %[[ELEM_3:.*]] = getelementptr double, ptr %[[ELEM_2]], i64 1 // LLVM: %[[REMAINING_SIZE:.*]] = sub i64 %[[ALLOC_SIZE]], 24 -// LLVM: call void @llvm.memset.p0.i64(ptr %[[ELEM_3]], i8 0, i64 %[[REMAINING_SIZE]], i1 false) +// LLVM: call void @llvm.memset.p0.i64(ptr{{.*}} %[[ELEM_3]], i8 0, i64 %[[REMAINING_SIZE]], i1 false) // OGCG: define{{.*}} void @_Z15t_new_var_size6i // OGCG: %[[N:.*]] = load i32, ptr %{{.+}} diff --git a/clang/test/CIR/CodeGen/paren-list-agg-init.cpp b/clang/test/CIR/CodeGen/paren-list-agg-init.cpp index 01e045f376a4f..2b64dd60af9df 100644 --- a/clang/test/CIR/CodeGen/paren-list-agg-init.cpp +++ b/clang/test/CIR/CodeGen/paren-list-agg-init.cpp @@ -875,7 +875,7 @@ namespace gh68198 { // CIR: %[[ALLOC_DIFF:.*]] = cir.sub %[[SIZE]], %[[INIT_SIZE]] : !u64i // CIR: %[[ELT2_DECAY:.*]] = cir.cast bitcast %[[ELT2]] : !cir.ptr> -> !cir.ptr // CIR: %[[ZERO:.*]] = cir.const #cir.int<0> : !u8i - // CIR: cir.libc.memset %[[ALLOC_DIFF]] bytes at %[[ELT2_DECAY]] to %[[ZERO]] : !cir.ptr, !u8i, !u64i + // CIR: cir.libc.memset %[[ALLOC_DIFF]] bytes at %[[ELT2_DECAY]]{{.*}} to %[[ZERO]] : !cir.ptr, !u8i, !u64i // CIR: %[[ARR_TO_VOID:.*]] = cir.cast bitcast %[[ALLOC_TO_ARR]] : !cir.ptr> -> !cir.ptr // CIR: cir.store{{.*}} %[[ARR_TO_VOID]], %[[ARR_ALLOCA]] : !cir.ptr, !cir.ptr> void foo27() { diff --git a/clang/test/CIR/CodeGenCXX/new-array-init.cpp b/clang/test/CIR/CodeGenCXX/new-array-init.cpp index 6e94b8bc275d7..fd595351573cd 100644 --- a/clang/test/CIR/CodeGenCXX/new-array-init.cpp +++ b/clang/test/CIR/CodeGenCXX/new-array-init.cpp @@ -45,7 +45,7 @@ void fn(int n) { // CIR: %[[REST_SIZE:.*]] = cir.sub %[[ADJ_SIZE]], %[[TWELVE]] : !u64i // CIR: %[[REST_ALLOC_AS_VOID:.*]] = cir.cast bitcast %[[NEXT_ELT3]] : !cir.ptr -> !cir.ptr // CIR: %[[ZERO:.*]] = cir.const #cir.int<0> : !u8i - // CIR: cir.libc.memset %[[REST_SIZE]] bytes at %[[REST_ALLOC_AS_VOID]] to %[[ZERO]] : !cir.ptr, !u8i, !u64i + // CIR: cir.libc.memset %[[REST_SIZE]] bytes at %[[REST_ALLOC_AS_VOID]]{{.*}} to %[[ZERO]] : !cir.ptr, !u8i, !u64i // LLVM: %[[N_ALLOCA:.*]] = alloca i32 // LLVM: %[[N_LOAD:.*]] = load i32, ptr %[[N_ALLOCA]] @@ -100,7 +100,7 @@ void fn_paren(int n) { // CIR: %[[REST_SIZE:.*]] = cir.sub %[[ADJ_SIZE]], %[[TWELVE]] : !u64i // CIR: %[[REST_ALLOC_AS_VOID:.*]] = cir.cast bitcast %[[NEXT_ELT3]] : !cir.ptr -> !cir.ptr // CIR: %[[ZERO:.*]] = cir.const #cir.int<0> : !u8i - // CIR: cir.libc.memset %[[REST_SIZE]] bytes at %[[REST_ALLOC_AS_VOID]] to %[[ZERO]] : !cir.ptr, !u8i, !u64i + // CIR: cir.libc.memset %[[REST_SIZE]] bytes at %[[REST_ALLOC_AS_VOID]]{{.*}} to %[[ZERO]] : !cir.ptr, !u8i, !u64i // LLVM: %[[N_ALLOCA:.*]] = alloca i32 // LLVM: %[[N_LOAD:.*]] = load i32, ptr %[[N_ALLOCA]] @@ -206,7 +206,7 @@ void const_sufficient() { // CIR: %[[REST_SIZE:.*]] = cir.sub %[[SIZE]], %[[INIT_SIZE]] : !u64i // CIR: %[[REST_PTR_DECAY:.*]] = cir.cast bitcast %[[ELT3]] : !cir.ptr -> !cir.ptr // CIR: %[[ZERO:.*]] = cir.const #cir.int<0> : !u8i - // CIR: cir.libc.memset %[[REST_SIZE]] bytes at %[[REST_PTR_DECAY]] to %[[ZERO]] : !cir.ptr, !u8i, !u64i + // CIR: cir.libc.memset %[[REST_SIZE]] bytes at %[[REST_PTR_DECAY]]{{.*}} to %[[ZERO]] : !cir.ptr, !u8i, !u64i // CIR: cir.return // LLVM: %[[ALLOC:.*]] = call{{.*}}nonnull ptr @_Znam(i64 noundef 16) @@ -243,7 +243,7 @@ void const_sufficient_paren() { // CIR: %[[REST_SIZE:.*]] = cir.sub %[[SIZE]], %[[INIT_SIZE]] : !u64i // CIR: %[[REST_PTR_DECAY:.*]] = cir.cast bitcast %[[ELT3]] : !cir.ptr -> !cir.ptr // CIR: %[[ZERO:.*]] = cir.const #cir.int<0> : !u8i - // CIR: cir.libc.memset %[[REST_SIZE]] bytes at %[[REST_PTR_DECAY]] to %[[ZERO]] : !cir.ptr, !u8i, !u64i + // CIR: cir.libc.memset %[[REST_SIZE]] bytes at %[[REST_PTR_DECAY]]{{.*}} to %[[ZERO]] : !cir.ptr, !u8i, !u64i // CIR: cir.return // LLVM: %[[ALLOC:.*]] = call{{.*}}nonnull ptr @_Znam(i64 noundef 16) @@ -298,7 +298,7 @@ void string_nonconst(int n) { // CIR: %[[SIZE_LEFT:.*]] = cir.sub %[[SIZE]], %[[CONST_STR_SIZE]] : !u64i // CIR: %[[AFTER_COPY_CAST:.*]] = cir.cast bitcast %[[AFTER_COPY]] : !cir.ptr -> !cir.ptr // CIR: %[[ZERO:.*]] = cir.const #cir.int<0> : !u8i - // CIR: cir.libc.memset %[[SIZE_LEFT]] bytes at %[[AFTER_COPY_CAST]] to %[[ZERO]] : !cir.ptr, !u8i, !u64i + // CIR: cir.libc.memset %[[SIZE_LEFT]] bytes at %[[AFTER_COPY_CAST]]{{.*}} to %[[ZERO]] : !cir.ptr, !u8i, !u64i // LLVM: %[[ARG_ALLOCA:.*]] = alloca i32 // LLVM: %[[ARG_LOAD:.*]] = load i32, ptr %[[ARG_ALLOCA]] @@ -334,7 +334,7 @@ void string_nonconst_paren(int n) { // CIR: %[[SIZE_LEFT:.*]] = cir.sub %[[SIZE]], %[[CONST_STR_SIZE]] : !u64i // CIR: %[[AFTER_COPY_CAST:.*]] = cir.cast bitcast %[[AFTER_COPY]] : !cir.ptr -> !cir.ptr // CIR: %[[ZERO:.*]] = cir.const #cir.int<0> : !u8i - // CIR: cir.libc.memset %[[SIZE_LEFT]] bytes at %[[AFTER_COPY_CAST]] to %[[ZERO]] : !cir.ptr, !u8i, !u64i + // CIR: cir.libc.memset %[[SIZE_LEFT]] bytes at %[[AFTER_COPY_CAST]]{{.*}} to %[[ZERO]] : !cir.ptr, !u8i, !u64i // LLVM: %[[ARG_ALLOCA:.*]] = alloca i32 // LLVM: %[[ARG_LOAD:.*]] = load i32, ptr %[[ARG_ALLOCA]] @@ -370,7 +370,7 @@ void string_nonconst_paren_extra_paren(int n) { // CIR: %[[SIZE_LEFT:.*]] = cir.sub %[[SIZE]], %[[CONST_STR_SIZE]] : !u64i // CIR: %[[AFTER_COPY_CAST:.*]] = cir.cast bitcast %[[AFTER_COPY]] : !cir.ptr -> !cir.ptr // CIR: %[[ZERO:.*]] = cir.const #cir.int<0> : !u8i - // CIR: cir.libc.memset %[[SIZE_LEFT]] bytes at %[[AFTER_COPY_CAST]] to %[[ZERO]] : !cir.ptr, !u8i, !u64i + // CIR: cir.libc.memset %[[SIZE_LEFT]] bytes at %[[AFTER_COPY_CAST]]{{.*}} to %[[ZERO]] : !cir.ptr, !u8i, !u64i // LLVM: %[[ARG_ALLOCA:.*]] = alloca i32 // LLVM: %[[ARG_LOAD:.*]] = load i32, ptr %[[ARG_ALLOCA]] @@ -540,7 +540,7 @@ void aggr_sufficient(int n) { // CIR: %[[REST_SIZE:.*]] = cir.sub %[[SIZE]], %[[TWO_ELTS_SIZE]] : !u64i // CIR: %[[REST_DECAY:.*]] = cir.cast bitcast %[[ELT2]] : !cir.ptr -> !cir.ptr // CIR: %[[ZERO:.*]] = cir.const #cir.int<0> : !u8i - // CIR: cir.libc.memset %[[REST_SIZE]] bytes at %[[REST_DECAY]] to %[[ZERO]] : !cir.ptr, !u8i, !u64i + // CIR: cir.libc.memset %[[REST_SIZE]] bytes at %[[REST_DECAY]]{{.*}} to %[[ZERO]] : !cir.ptr, !u8i, !u64i // LLVM: %[[ARG:.*]] = alloca i32 // LLVM: %[[GET_N:.*]] = load i32, ptr %[[ARG]] diff --git a/clang/test/CIR/CodeGenOpenMP/not-yet-implemented.c b/clang/test/CIR/CodeGenOpenMP/not-yet-implemented.c index 6d59f45d6e5e4..29e280bf262d0 100644 --- a/clang/test/CIR/CodeGenOpenMP/not-yet-implemented.c +++ b/clang/test/CIR/CodeGenOpenMP/not-yet-implemented.c @@ -10,9 +10,7 @@ void do_things() { {} int i; - // TODO(OMP): We might consider overloading operator<< for OMPClauseKind in - // the future if we want to improve this. - // expected-error@+1{{ClangIR code gen Not Yet Implemented: OpenMPClause : if}} + // expected-error@+1{{ClangIR code gen Not Yet Implemented: OpenMP PARALLEL 'if' clause}} #pragma omp parallel if(i) {} } diff --git a/clang/test/CIR/CodeGenOpenMP/target-map-llvm-device.c b/clang/test/CIR/CodeGenOpenMP/target-map-llvm-device.c new file mode 100644 index 0000000000000..b6fa078d143c5 --- /dev/null +++ b/clang/test/CIR/CodeGenOpenMP/target-map-llvm-device.c @@ -0,0 +1,130 @@ +// Two-step host-BC -> device pipeline that mirrors the offloading driver. +// +// Step 1: Host compilation to bitcode (provides offload entry info to device pass). +// RUN: %clang_cc1 -fopenmp -fopenmp-targets=amdgcn-amd-amdhsa \ +// RUN: -fclangir -emit-llvm-bc %s -o %t-cir-host.bc +// RUN: %clang_cc1 -fopenmp -fopenmp-targets=amdgcn-amd-amdhsa \ +// RUN: -emit-llvm-bc %s -o %t-ogcg-host.bc +// +// Step 2: Device compilation using host BC. +// RUN: %clang_cc1 -triple amdgcn-amd-amdhsa -fopenmp -fopenmp-is-target-device \ +// RUN: -fopenmp-host-ir-file-path %t-cir-host.bc \ +// RUN: -fclangir -emit-llvm %s -o - \ +// RUN: | FileCheck %s --check-prefix=LLVM +// RUN: %clang_cc1 -triple amdgcn-amd-amdhsa -fopenmp -fopenmp-is-target-device \ +// RUN: -fopenmp-host-ir-file-path %t-ogcg-host.bc \ +// RUN: -emit-llvm %s -o - \ +// RUN: | FileCheck %s --check-prefix=OGCG + +void use(int); + +void target_map_to(int x) { +#pragma omp target map(to : x) + { + use(x); + } +} + +void target_map_from(int x) { +#pragma omp target map(from : x) + { + x = 42; + } +} + +void target_map_tofrom(int x) { +#pragma omp target map(tofrom : x) + { + x = x + 1; + } +} + +void target_map_multiple(int a, int b) { +#pragma omp target map(to : a) map(from : b) + { + b = a; + } +} + +// LLVM-LABEL: define weak_odr protected amdgpu_kernel void @__omp_offloading_{{.*}}_target_map_to_l +// LLVM-SAME: (ptr %[[ARG:[^,]+]], ptr +// LLVM: %[[SLOT:.*]] = addrspacecast ptr addrspace(5) %{{.*}} to ptr +// LLVM: store ptr %[[ARG]], ptr %[[SLOT]], align 8 +// LLVM: call i32 @__kmpc_target_init( +// LLVM: user_code.entry: +// LLVM: %[[PTR:.*]] = load ptr, ptr %[[SLOT]], align 8 +// LLVM: %[[V:.*]] = load i32, ptr %[[PTR]], align 4 +// LLVM: call void @use(i32 {{.*}} %[[V]]) +// LLVM: call void @__kmpc_target_deinit() +// LLVM: ret void + +// LLVM-LABEL: define weak_odr protected amdgpu_kernel void @__omp_offloading_{{.*}}_target_map_from_l +// LLVM-SAME: (ptr %[[ARG:[^,]+]], ptr +// LLVM: %[[SLOT:.*]] = addrspacecast ptr addrspace(5) %{{.*}} to ptr +// LLVM: store ptr %[[ARG]], ptr %[[SLOT]], align 8 +// LLVM: call i32 @__kmpc_target_init( +// LLVM: user_code.entry: +// LLVM: %[[PTR:.*]] = load ptr, ptr %[[SLOT]], align 8 +// LLVM: store i32 42, ptr %[[PTR]], align 4 +// LLVM: call void @__kmpc_target_deinit() +// LLVM: ret void + +// LLVM-LABEL: define weak_odr protected amdgpu_kernel void @__omp_offloading_{{.*}}_target_map_tofrom_l +// LLVM-SAME: (ptr %[[ARG:[^,]+]], ptr +// LLVM: %[[SLOT:.*]] = addrspacecast ptr addrspace(5) %{{.*}} to ptr +// LLVM: store ptr %[[ARG]], ptr %[[SLOT]], align 8 +// LLVM: call i32 @__kmpc_target_init( +// LLVM: user_code.entry: +// LLVM: %[[PTR:.*]] = load ptr, ptr %[[SLOT]], align 8 +// LLVM: %[[LD:.*]] = load i32, ptr %[[PTR]], align 4 +// LLVM: %[[ADD:.*]] = add nsw i32 %[[LD]], 1 +// LLVM: store i32 %[[ADD]], ptr %[[PTR]], align 4 +// LLVM: call void @__kmpc_target_deinit() +// LLVM: ret void + +// LLVM-LABEL: define weak_odr protected amdgpu_kernel void @__omp_offloading_{{.*}}_target_map_multiple_l +// LLVM-SAME: (ptr %[[ARG_A:[^,]+]], ptr %[[ARG_B:[^,]+]], ptr +// LLVM: %[[SLOT_A:.*]] = addrspacecast ptr addrspace(5) %{{.*}} to ptr +// LLVM: store ptr %[[ARG_A]], ptr %[[SLOT_A]], align 8 +// LLVM: %[[SLOT_B:.*]] = addrspacecast ptr addrspace(5) %{{.*}} to ptr +// LLVM: store ptr %[[ARG_B]], ptr %[[SLOT_B]], align 8 +// LLVM: call i32 @__kmpc_target_init( +// LLVM: user_code.entry: +// LLVM: %[[PTR_A:.*]] = load ptr, ptr %[[SLOT_A]], align 8 +// LLVM: %[[PTR_B:.*]] = load ptr, ptr %[[SLOT_B]], align 8 +// LLVM: %[[A:.*]] = load i32, ptr %[[PTR_A]], align 4 +// LLVM: store i32 %[[A]], ptr %[[PTR_B]], align 4 +// LLVM: call void @__kmpc_target_deinit() +// LLVM: ret void + +// OGCG-LABEL: define weak_odr protected amdgpu_kernel void @__omp_offloading_{{.*}}_target_map_to_l +// OGCG: call i32 @__kmpc_target_init( +// OGCG: user_code.entry: +// OGCG: %[[V:.*]] = load i32, ptr %{{.*}}, align 4 +// OGCG: call void @use(i32 {{.*}} %[[V]]) +// OGCG: call void @__kmpc_target_deinit() +// OGCG: ret void + +// OGCG-LABEL: define weak_odr protected amdgpu_kernel void @__omp_offloading_{{.*}}_target_map_from_l +// OGCG: call i32 @__kmpc_target_init( +// OGCG: user_code.entry: +// OGCG: store i32 42, ptr %{{.*}}, align 4 +// OGCG: call void @__kmpc_target_deinit() +// OGCG: ret void + +// OGCG-LABEL: define weak_odr protected amdgpu_kernel void @__omp_offloading_{{.*}}_target_map_tofrom_l +// OGCG: call i32 @__kmpc_target_init( +// OGCG: user_code.entry: +// OGCG: %[[LD:.*]] = load i32, ptr %{{.*}}, align 4 +// OGCG: %[[ADD:.*]] = add nsw i32 %[[LD]], 1 +// OGCG: store i32 %[[ADD]], ptr %{{.*}}, align 4 +// OGCG: call void @__kmpc_target_deinit() +// OGCG: ret void + +// OGCG-LABEL: define weak_odr protected amdgpu_kernel void @__omp_offloading_{{.*}}_target_map_multiple_l +// OGCG: call i32 @__kmpc_target_init( +// OGCG: user_code.entry: +// OGCG: %[[A:.*]] = load i32, ptr %{{.*}}, align 4 +// OGCG: store i32 %[[A]], ptr %{{.*}}, align 4 +// OGCG: call void @__kmpc_target_deinit() +// OGCG: ret void diff --git a/clang/test/CIR/CodeGenOpenMP/target-map-llvm-host.c b/clang/test/CIR/CodeGenOpenMP/target-map-llvm-host.c new file mode 100644 index 0000000000000..a42e955396980 --- /dev/null +++ b/clang/test/CIR/CodeGenOpenMP/target-map-llvm-host.c @@ -0,0 +1,163 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fopenmp \ +// RUN: -fopenmp-targets=amdgcn-amd-amdhsa -fclangir -emit-llvm %s -o - \ +// RUN: | FileCheck %s --check-prefix=LLVM +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fopenmp \ +// RUN: -fopenmp-targets=amdgcn-amd-amdhsa -emit-llvm %s -o - \ +// RUN: | FileCheck %s --check-prefix=OGCG + +void use(int); + +void target_map_to(int x) { +#pragma omp target map(to : x) + { + use(x); + } +} + +void target_map_from(int x) { +#pragma omp target map(from : x) + { + x = 42; + } +} + +void target_map_tofrom(int x) { +#pragma omp target map(tofrom : x) + { + x = x + 1; + } +} + +void target_map_multiple(int a, int b) { +#pragma omp target map(to : a) map(from : b) + { + b = a; + } +} + +// Host wrappers +// +// LLVM-LABEL: define {{.*}} void @target_map_to( +// LLVM-SAME: i32 noundef %[[ARG:[^,)]+]] +// LLVM: %[[X_ADDR:.*]] = alloca i32, i64 1, align 4 +// LLVM: store i32 %[[ARG]], ptr %[[X_ADDR]], align 4 +// LLVM: %[[BP:.*]] = getelementptr inbounds [2 x ptr], ptr %.offload_baseptrs, i32 0, i32 0 +// LLVM: store ptr %[[X_ADDR]], ptr %[[BP]], align 8 +// LLVM: %[[P:.*]] = getelementptr inbounds [2 x ptr], ptr %.offload_ptrs, i32 0, i32 0 +// LLVM: store ptr %[[X_ADDR]], ptr %[[P]], align 8 +// LLVM: call i32 @__tgt_target_kernel( +// LLVM: omp_offload.failed: +// LLVM: call void @__omp_offloading_{{.*}}_target_map_to_l{{.*}}(ptr %[[X_ADDR]], ptr null) + +// LLVM-LABEL: define {{.*}} void @target_map_from( +// LLVM-SAME: i32 noundef %[[ARG:[^,)]+]] +// LLVM: %[[X_ADDR:.*]] = alloca i32, i64 1, align 4 +// LLVM: store i32 %[[ARG]], ptr %[[X_ADDR]], align 4 +// LLVM: %[[BP:.*]] = getelementptr inbounds [2 x ptr], ptr %.offload_baseptrs, i32 0, i32 0 +// LLVM: store ptr %[[X_ADDR]], ptr %[[BP]], align 8 +// LLVM: %[[P:.*]] = getelementptr inbounds [2 x ptr], ptr %.offload_ptrs, i32 0, i32 0 +// LLVM: store ptr %[[X_ADDR]], ptr %[[P]], align 8 +// LLVM: call i32 @__tgt_target_kernel( +// LLVM: omp_offload.failed: +// LLVM: call void @__omp_offloading_{{.*}}_target_map_from_l{{.*}}(ptr %[[X_ADDR]], ptr null) + +// LLVM-LABEL: define {{.*}} void @target_map_tofrom( +// LLVM-SAME: i32 noundef %[[ARG:[^,)]+]] +// LLVM: %[[X_ADDR:.*]] = alloca i32, i64 1, align 4 +// LLVM: store i32 %[[ARG]], ptr %[[X_ADDR]], align 4 +// LLVM: %[[BP:.*]] = getelementptr inbounds [2 x ptr], ptr %.offload_baseptrs, i32 0, i32 0 +// LLVM: store ptr %[[X_ADDR]], ptr %[[BP]], align 8 +// LLVM: %[[P:.*]] = getelementptr inbounds [2 x ptr], ptr %.offload_ptrs, i32 0, i32 0 +// LLVM: store ptr %[[X_ADDR]], ptr %[[P]], align 8 +// LLVM: call i32 @__tgt_target_kernel( +// LLVM: omp_offload.failed: +// LLVM: call void @__omp_offloading_{{.*}}_target_map_tofrom_l{{.*}}(ptr %[[X_ADDR]], ptr null) + +// LLVM-LABEL: define {{.*}} void @target_map_multiple( +// LLVM-SAME: i32 noundef %[[ARG_A:[^,)]+]], i32 noundef %[[ARG_B:[^,)]+]] +// LLVM: %[[A_ADDR:.*]] = alloca i32, i64 1, align 4 +// LLVM: %[[B_ADDR:.*]] = alloca i32, i64 1, align 4 +// LLVM: store i32 %[[ARG_A]], ptr %[[A_ADDR]], align 4 +// LLVM: store i32 %[[ARG_B]], ptr %[[B_ADDR]], align 4 +// LLVM: %[[BP_A:.*]] = getelementptr inbounds [3 x ptr], ptr %.offload_baseptrs, i32 0, i32 0 +// LLVM: store ptr %[[A_ADDR]], ptr %[[BP_A]], align 8 +// LLVM: %[[P_A:.*]] = getelementptr inbounds [3 x ptr], ptr %.offload_ptrs, i32 0, i32 0 +// LLVM: store ptr %[[A_ADDR]], ptr %[[P_A]], align 8 +// LLVM: %[[BP_B:.*]] = getelementptr inbounds [3 x ptr], ptr %.offload_baseptrs, i32 0, i32 1 +// LLVM: store ptr %[[B_ADDR]], ptr %[[BP_B]], align 8 +// LLVM: %[[P_B:.*]] = getelementptr inbounds [3 x ptr], ptr %.offload_ptrs, i32 0, i32 1 +// LLVM: store ptr %[[B_ADDR]], ptr %[[P_B]], align 8 +// LLVM: call i32 @__tgt_target_kernel( +// LLVM: omp_offload.failed: +// LLVM: call void @__omp_offloading_{{.*}}_target_map_multiple_l{{.*}}(ptr %[[A_ADDR]], ptr %[[B_ADDR]], ptr null) + +// Outlined target functions +// +// The mapped pointer arrives as the first function argument; load/store the +// user value directly through it. + +// LLVM-LABEL: define internal void @__omp_offloading_{{.*}}_target_map_to_l +// LLVM-SAME: (ptr %[[ARG:[^,]+]], ptr +// LLVM: %[[V:.*]] = load i32, ptr %[[ARG]], align 4 +// LLVM: call void @use(i32 {{.*}} %[[V]]) +// LLVM: ret void + +// LLVM-LABEL: define internal void @__omp_offloading_{{.*}}_target_map_from_l +// LLVM-SAME: (ptr %[[ARG:[^,]+]], ptr +// LLVM: store i32 42, ptr %[[ARG]], align 4 +// LLVM: ret void + +// LLVM-LABEL: define internal void @__omp_offloading_{{.*}}_target_map_tofrom_l +// LLVM-SAME: (ptr %[[ARG:[^,]+]], ptr +// LLVM: %[[LD:.*]] = load i32, ptr %[[ARG]], align 4 +// LLVM: %[[ADD:.*]] = add nsw i32 %[[LD]], 1 +// LLVM: store i32 %[[ADD]], ptr %[[ARG]], align 4 +// LLVM: ret void + +// LLVM-LABEL: define internal void @__omp_offloading_{{.*}}_target_map_multiple_l +// LLVM-SAME: (ptr %[[ARG_A:[^,]+]], ptr %[[ARG_B:[^,]+]], ptr +// LLVM: %[[A:.*]] = load i32, ptr %[[ARG_A]], align 4 +// LLVM: store i32 %[[A]], ptr %[[ARG_B]], align 4 +// LLVM: ret void + +// OGCG interleaves host wrapper and outlined function per target region. + +// OGCG-LABEL: define {{.*}} void @target_map_to(i32 +// OGCG: call i32 @__tgt_target_kernel( +// OGCG: omp_offload.failed: +// OGCG: call void @__omp_offloading_{{.*}}_target_map_to_l + +// OGCG-LABEL: define internal void @__omp_offloading_{{.*}}_target_map_to_l +// OGCG: %[[V:.*]] = load i32, ptr %{{.*}}, align 4 +// OGCG: call void @use(i32 {{.*}} %[[V]]) +// OGCG: ret void + +// OGCG-LABEL: define {{.*}} void @target_map_from(i32 +// OGCG: call i32 @__tgt_target_kernel( +// OGCG: omp_offload.failed: +// OGCG: call void @__omp_offloading_{{.*}}_target_map_from_l + +// OGCG-LABEL: define internal void @__omp_offloading_{{.*}}_target_map_from_l +// OGCG: store i32 42, ptr %{{.*}}, align 4 +// OGCG: ret void + +// OGCG-LABEL: define {{.*}} void @target_map_tofrom(i32 +// OGCG: call i32 @__tgt_target_kernel( +// OGCG: omp_offload.failed: +// OGCG: call void @__omp_offloading_{{.*}}_target_map_tofrom_l + +// OGCG-LABEL: define internal void @__omp_offloading_{{.*}}_target_map_tofrom_l +// OGCG: %[[LD:.*]] = load i32, ptr %{{.*}}, align 4 +// OGCG: %[[ADD:.*]] = add nsw i32 %[[LD]], 1 +// OGCG: store i32 %[[ADD]], ptr %{{.*}}, align 4 +// OGCG: ret void + +// OGCG-LABEL: define {{.*}} void @target_map_multiple(i32 +// OGCG: call i32 @__tgt_target_kernel( +// OGCG: omp_offload.failed: +// OGCG: call void @__omp_offloading_{{.*}}_target_map_multiple_l + +// OGCG-LABEL: define internal void @__omp_offloading_{{.*}}_target_map_multiple_l +// OGCG: %[[A:.*]] = load i32, ptr %{{.*}}, align 4 +// OGCG: store i32 %[[A]], ptr %{{.*}}, align 4 +// OGCG: ret void diff --git a/clang/test/CIR/CodeGenOpenMP/target-map.c b/clang/test/CIR/CodeGenOpenMP/target-map.c new file mode 100644 index 0000000000000..394b7abb9e0b2 --- /dev/null +++ b/clang/test/CIR/CodeGenOpenMP/target-map.c @@ -0,0 +1,105 @@ +// Host compilation (x86 host, AMDGPU offload target): no address space on allocas. +// RUN: %clang_cc1 -fopenmp -fopenmp-targets=amdgcn-amd-amdhsa -emit-cir -fclangir %s -o - \ +// RUN: | FileCheck %s --check-prefix=CIR-HOST + +// Device compilation (AMDGPU): allocas in private address space, addrspacecast for map info. +// RUN: %clang_cc1 -triple amdgcn-amd-amdhsa -fopenmp -fopenmp-is-target-device \ +// RUN: -emit-cir -fclangir %s -o - \ +// RUN: | FileCheck %s --check-prefix=CIR-DEVICE + +void use(int); + +void target_map_to(int x) { + // CIR-HOST: cir.func{{.*}}@target_map_to + // CIR-HOST: %[[X_ALLOCA:.*]] = cir.alloca "x" align(4) init : !cir.ptr + // CIR-HOST: %[[MAP:.*]] = omp.map.info var_ptr(%[[X_ALLOCA]] : !cir.ptr, !s32i) map_clauses(to) capture(ByRef) -> !cir.ptr {name = "x"} + // CIR-HOST-NEXT: omp.target kernel_type(generic) map_entries(%[[MAP]] -> %[[ARG:.*]] : !cir.ptr) { + // CIR-HOST-NEXT: %[[LOAD:.*]] = cir.load align(4) %[[ARG]] + // CIR-HOST-NEXT: cir.call @use(%[[LOAD]]) + // CIR-HOST-NEXT: omp.terminator + // CIR-HOST-NEXT: } + + // CIR-DEVICE: cir.func{{.*}}@target_map_to + // CIR-DEVICE: %[[X_ALLOCA:.*]] = cir.alloca "x" align(4) init : !cir.ptr + // CIR-DEVICE: %[[CAST:.*]] = cir.cast address_space %[[X_ALLOCA]] : !cir.ptr -> !cir.ptr + // CIR-DEVICE: %[[MAP:.*]] = omp.map.info var_ptr(%[[CAST]] : !cir.ptr, !s32i) map_clauses(to) capture(ByRef) -> !cir.ptr {name = "x"} + // CIR-DEVICE-NEXT: omp.target kernel_type(generic) map_entries(%[[MAP]] -> %[[ARG:.*]] : !cir.ptr) { + // CIR-DEVICE: omp.terminator + // CIR-DEVICE-NEXT: } +#pragma omp target map(to : x) + { + use(x); + } +} + +void target_map_from(int x) { + // CIR-HOST: cir.func{{.*}}@target_map_from + // CIR-HOST: %[[X_ALLOCA:.*]] = cir.alloca "x" align(4) init : !cir.ptr + // CIR-HOST: %[[MAP:.*]] = omp.map.info var_ptr(%[[X_ALLOCA]] : !cir.ptr, !s32i) map_clauses(from) capture(ByRef) -> !cir.ptr {name = "x"} + // CIR-HOST-NEXT: omp.target kernel_type(generic) map_entries(%[[MAP]] -> %[[ARG:.*]] : !cir.ptr) { + // CIR-HOST-NEXT: %[[C42:.*]] = cir.const #cir.int<42> : !s32i + // CIR-HOST-NEXT: cir.store align(4) %[[C42]], %[[ARG]] + // CIR-HOST-NEXT: omp.terminator + // CIR-HOST-NEXT: } + + // CIR-DEVICE: cir.func{{.*}}@target_map_from + // CIR-DEVICE: %[[X_ALLOCA:.*]] = cir.alloca "x" align(4) init : !cir.ptr + // CIR-DEVICE: %[[CAST:.*]] = cir.cast address_space %[[X_ALLOCA]] : !cir.ptr -> !cir.ptr + // CIR-DEVICE: %[[MAP:.*]] = omp.map.info var_ptr(%[[CAST]] : !cir.ptr, !s32i) map_clauses(from) capture(ByRef) -> !cir.ptr {name = "x"} + // CIR-DEVICE-NEXT: omp.target kernel_type(generic) map_entries(%[[MAP]] -> %[[ARG:.*]] : !cir.ptr) { + // CIR-DEVICE: omp.terminator + // CIR-DEVICE-NEXT: } +#pragma omp target map(from : x) + { + x = 42; + } +} + +void target_map_tofrom(int x) { + // CIR-HOST: cir.func{{.*}}@target_map_tofrom + // CIR-HOST: %[[X_ALLOCA:.*]] = cir.alloca "x" align(4) init : !cir.ptr + // CIR-HOST: %[[MAP:.*]] = omp.map.info var_ptr(%[[X_ALLOCA]] : !cir.ptr, !s32i) map_clauses(tofrom) capture(ByRef) -> !cir.ptr {name = "x"} + // CIR-HOST-NEXT: omp.target kernel_type(generic) map_entries(%[[MAP]] -> %[[ARG:.*]] : !cir.ptr) { + // CIR-HOST: omp.terminator + // CIR-HOST-NEXT: } + + // CIR-DEVICE: cir.func{{.*}}@target_map_tofrom + // CIR-DEVICE: %[[X_ALLOCA:.*]] = cir.alloca "x" align(4) init : !cir.ptr + // CIR-DEVICE: %[[CAST:.*]] = cir.cast address_space %[[X_ALLOCA]] : !cir.ptr -> !cir.ptr + // CIR-DEVICE: %[[MAP:.*]] = omp.map.info var_ptr(%[[CAST]] : !cir.ptr, !s32i) map_clauses(tofrom) capture(ByRef) -> !cir.ptr {name = "x"} + // CIR-DEVICE-NEXT: omp.target kernel_type(generic) map_entries(%[[MAP]] -> %[[ARG:.*]] : !cir.ptr) { + // CIR-DEVICE: omp.terminator + // CIR-DEVICE-NEXT: } +#pragma omp target map(tofrom : x) + { + x = x + 1; + } +} + +void target_map_multiple(int a, int b) { + // CIR-HOST: cir.func{{.*}}@target_map_multiple + // CIR-HOST-DAG: %[[A_ALLOCA:.*]] = cir.alloca "a" align(4) init : !cir.ptr + // CIR-HOST-DAG: %[[B_ALLOCA:.*]] = cir.alloca "b" align(4) init : !cir.ptr + // CIR-HOST: %[[MAP_A:.*]] = omp.map.info var_ptr(%[[A_ALLOCA]] : !cir.ptr, !s32i) map_clauses(to) capture(ByRef) -> !cir.ptr {name = "a"} + // CIR-HOST-NEXT: %[[MAP_B:.*]] = omp.map.info var_ptr(%[[B_ALLOCA]] : !cir.ptr, !s32i) map_clauses(from) capture(ByRef) -> !cir.ptr {name = "b"} + // CIR-HOST-NEXT: omp.target kernel_type(generic) map_entries(%[[MAP_A]] -> %[[ARG_A:.*]], %[[MAP_B]] -> %[[ARG_B:.*]] : !cir.ptr, !cir.ptr) { + // CIR-HOST: omp.terminator + // CIR-HOST-NEXT: } + + // CIR-DEVICE: cir.func{{.*}}@target_map_multiple + // CIR-DEVICE-DAG: %[[A_ALLOCA:.*]] = cir.alloca "a" align(4) init : !cir.ptr + // CIR-DEVICE-DAG: %[[B_ALLOCA:.*]] = cir.alloca "b" align(4) init : !cir.ptr + // CIR-DEVICE: %[[CAST_A:.*]] = cir.cast address_space %[[A_ALLOCA]] : !cir.ptr -> !cir.ptr + // CIR-DEVICE: %[[MAP_A:.*]] = omp.map.info var_ptr(%[[CAST_A]] : !cir.ptr, !s32i) map_clauses(to) capture(ByRef) -> !cir.ptr {name = "a"} + // CIR-DEVICE: %[[CAST_B:.*]] = cir.cast address_space %[[B_ALLOCA]] : !cir.ptr -> !cir.ptr + // CIR-DEVICE: %[[MAP_B:.*]] = omp.map.info var_ptr(%[[CAST_B]] : !cir.ptr, !s32i) map_clauses(from) capture(ByRef) -> !cir.ptr {name = "b"} + // CIR-DEVICE: omp.target kernel_type(generic) map_entries(%[[MAP_A]] -> %[[ARG_A:.*]], %[[MAP_B]] -> %[[ARG_B:.*]] : !cir.ptr, !cir.ptr) { + // CIR-DEVICE: omp.terminator + // CIR-DEVICE-NEXT: } +#pragma omp target map(to : a) map(from : b) + { + b = a; + } +} + +// TODO: Test implicit mapping. Currently NYI diff --git a/clang/test/CXX/expr/expr.const/p6-2a.cpp b/clang/test/CXX/expr/expr.const/p6-2a.cpp index a937474d53b22..e97f35c891717 100644 --- a/clang/test/CXX/expr/expr.const/p6-2a.cpp +++ b/clang/test/CXX/expr/expr.const/p6-2a.cpp @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -std=c++2a -verify %s +// RUN: %clang_cc1 -std=c++2a -verify %s -fexperimental-new-constant-interpreter constexpr int non_class = 42; constexpr int arr_non_class[5] = {1, 2, 3}; diff --git a/clang/test/CodeGen/amdgpu-feature-builtins-invalid-use.cpp b/clang/test/CodeGen/amdgpu-feature-builtins-invalid-use.cpp deleted file mode 100644 index 78f18d3a37b46..0000000000000 --- a/clang/test/CodeGen/amdgpu-feature-builtins-invalid-use.cpp +++ /dev/null @@ -1,48 +0,0 @@ -// RUN: not %clang_cc1 -triple amdgcn-amd-amdhsa -target-cpu gfx900 -emit-llvm %s -o - 2>&1 | FileCheck %s -// RUN: not %clang_cc1 -triple spirv64-amd-amdhsa -emit-llvm %s -o - 2>&1 | FileCheck %s - -bool predicate(bool x); -void pass_by_value(__amdgpu_feature_predicate_t x); - -void invalid_uses(int *p, int x, const __amdgpu_feature_predicate_t &lv, - __amdgpu_feature_predicate_t &&rv) { - // CHECK: error: 'a' has type __amdgpu_feature_predicate_t, which is not constructible - __amdgpu_feature_predicate_t a; - // CHECK: error: 'b' has type __amdgpu_feature_predicate_t, which is not constructible - __amdgpu_feature_predicate_t b = __builtin_amdgcn_processor_is("gfx906"); - // CHECK: error: 'c' has type __amdgpu_feature_predicate_t, which is not constructible - __amdgpu_feature_predicate_t c = lv; - // CHECK: error: 'd' has type __amdgpu_feature_predicate_t, which is not constructible - __amdgpu_feature_predicate_t d = rv; - // CHECK: error: '__builtin_amdgcn_processor_is("gfx906")' must be explicitly cast to 'bool'; however, please note that this is almost always an error and that it prevents the effective guarding of target dependent code, and thus should be avoided - bool invalid_use_in_init_0 = __builtin_amdgcn_processor_is("gfx906"); - // CHECK: error: 'x' has type __amdgpu_feature_predicate_t, which is not constructible - pass_by_value(__builtin_amdgcn_processor_is("gfx906")); - // CHECK: error: '__builtin_amdgcn_is_invocable(__builtin_amdgcn_s_sleep_var)' must be explicitly cast to 'bool'; however, please note that this is almost always an error and that it prevents the effective guarding of target dependent code, and thus should be avoided - bool invalid_use_in_init_1 = __builtin_amdgcn_is_invocable(__builtin_amdgcn_s_sleep_var); - // CHECK: error: '__builtin_amdgcn_processor_is("gfx906")' must be explicitly cast to 'bool'; however, please note that this is almost always an error and that it prevents the effective guarding of target dependent code, and thus should be avoided - if (bool invalid_use_in_init_2 = __builtin_amdgcn_processor_is("gfx906")) return; - // CHECK: error: '__builtin_amdgcn_processor_is("gfx1200")' must be explicitly cast to 'bool'; however, please note that this is almost always an error and that it prevents the effective guarding of target dependent code, and thus should be avoided - if (predicate(__builtin_amdgcn_processor_is("gfx1200"))) __builtin_amdgcn_s_sleep_var(x); -} - -void invalid_invocations(int x, const char* str) { - // CHECK: error: the argument to __builtin_amdgcn_processor_is must be a valid AMDGCN processor identifier; 'not_an_amdgcn_gfx_id' is not valid - // CHECK-DAG: note: valid AMDGCN processor identifiers are: {{.*}}gfx{{.*}} - if (__builtin_amdgcn_processor_is("not_an_amdgcn_gfx_id")) return; - // CHECK: error: the argument to __builtin_amdgcn_processor_is must be a string literal - if (__builtin_amdgcn_processor_is(str)) return; - // CHECK: error: the argument to __builtin_amdgcn_is_invocable must be either a target agnostic builtin or an AMDGCN target specific builtin; {{.*}}__builtin_amdgcn_s_sleep_var{{.*}} is not valid - if (__builtin_amdgcn_is_invocable("__builtin_amdgcn_s_sleep_var")) return; - // CHECK: error: the argument to __builtin_amdgcn_is_invocable must be either a target agnostic builtin or an AMDGCN target specific builtin; {{.*}}str{{.*}} is not valid - else if (__builtin_amdgcn_is_invocable(str)) return; - // CHECK: error: the argument to __builtin_amdgcn_is_invocable must be either a target agnostic builtin or an AMDGCN target specific builtin; {{.*}}x{{.*}} is not valid - else if (__builtin_amdgcn_is_invocable(x)) return; - // CHECK: error: use of undeclared identifier '__builtin_ia32_pause' - else if (__builtin_amdgcn_is_invocable(__builtin_ia32_pause)) return; -} - -bool return_needs_cast() { - // CHECK: error: '__builtin_amdgcn_processor_is("gfx900")' must be explicitly cast to 'bool'; however, please note that this is almost always an error and that it prevents the effective guarding of target dependent code, and thus should be avoided - return __builtin_amdgcn_processor_is("gfx900"); -} diff --git a/clang/test/CodeGenCXX/const-init-cxx2a.cpp b/clang/test/CodeGenCXX/const-init-cxx2a.cpp index 3c83a9c94adec..765f5b8d46e6f 100644 --- a/clang/test/CodeGenCXX/const-init-cxx2a.cpp +++ b/clang/test/CodeGenCXX/const-init-cxx2a.cpp @@ -1,4 +1,5 @@ -// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -o - %s -std=c++2a | FileCheck %s --implicit-check-not=cxx_global_var_init --implicit-check-not=cxa_atexit +// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -o - %s -std=c++2a | FileCheck %s --implicit-check-not=cxx_global_var_init --implicit-check-not=cxa_atexit +// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -o - %s -std=c++2a -fexperimental-new-constant-interpreter | FileCheck %s --implicit-check-not=cxx_global_var_init --implicit-check-not=cxa_atexit // RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-pch -o %t.pch %s -std=c++2a // RUN: %clang_cc1 -triple x86_64-linux-gnu -include-pch %t.pch -x c++ /dev/null -emit-llvm -o - -std=c++2a | FileCheck %s --implicit-check-not=cxx_global_var_init --implicit-check-not=cxa_atexit diff --git a/clang/test/CodeGenCXX/non-const-init-cxx2a.cpp b/clang/test/CodeGenCXX/non-const-init-cxx2a.cpp index 1ebb595897b31..48594632d4d06 100644 --- a/clang/test/CodeGenCXX/non-const-init-cxx2a.cpp +++ b/clang/test/CodeGenCXX/non-const-init-cxx2a.cpp @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s -std=c++2a | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s -std=c++2a -fexperimental-new-constant-interpreter | FileCheck %s // RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-pch -o %t.pch %s -std=c++2a // RUN: %clang_cc1 -triple x86_64-apple-darwin -include-pch %t.pch -x c++ /dev/null -emit-llvm -o - -std=c++2a | FileCheck %s diff --git a/clang/test/CodeGenOpenCL/address-spaces-conversions.cl b/clang/test/CodeGenOpenCL/address-spaces-conversions.cl index f3a22fe89eaeb..af0c40e1417b2 100644 --- a/clang/test/CodeGenOpenCL/address-spaces-conversions.cl +++ b/clang/test/CodeGenOpenCL/address-spaces-conversions.cl @@ -1,7 +1,7 @@ -// RUN: %clang_cc1 %s -triple x86_64-unknown-linux-gnu -O0 -ffake-address-space-map -cl-std=CL2.0 -emit-llvm -o - | FileCheck %s -// RUN: %clang_cc1 %s -triple x86_64-unknown-linux-gnu -O0 -ffake-address-space-map -cl-std=CL3.0 -cl-ext=+__opencl_c_generic_address_space -emit-llvm -o - | FileCheck %s -// RUN: %clang_cc1 %s -triple x86_64-unknown-linux-gnu -O0 -cl-std=CL2.0 -emit-llvm -o - | FileCheck --check-prefix=CHECK-NOFAKE %s -// RUN: %clang_cc1 %s -triple x86_64-unknown-linux-gnu -O0 -cl-std=CL3.0 -cl-ext=+__opencl_c_generic_address_space -emit-llvm -o - | FileCheck --check-prefix=CHECK-NOFAKE %s +// RUN: %clang_cc1 %s -triple x86_64-unknown-linux-gnu -O0 -ffake-address-space-map -cl-std=CL2.0 -emit-llvm -o - -Wno-deprecated-attributes | FileCheck %s +// RUN: %clang_cc1 %s -triple x86_64-unknown-linux-gnu -O0 -ffake-address-space-map -cl-std=CL3.0 -cl-ext=+__opencl_c_generic_address_space -emit-llvm -o - -Wno-deprecated-attributes | FileCheck %s +// RUN: %clang_cc1 %s -triple x86_64-unknown-linux-gnu -O0 -cl-std=CL2.0 -emit-llvm -o - -Wno-deprecated-attributes | FileCheck --check-prefix=CHECK-NOFAKE %s +// RUN: %clang_cc1 %s -triple x86_64-unknown-linux-gnu -O0 -cl-std=CL3.0 -cl-ext=+__opencl_c_generic_address_space -emit-llvm -o - -Wno-deprecated-attributes | FileCheck --check-prefix=CHECK-NOFAKE %s // When -ffake-address-space-map is not used, all addr space mapped to 0 for x86_64. // test that we generate address space casts everywhere we need conversions of diff --git a/clang/test/CodeGenOpenCL/address-spaces.cl b/clang/test/CodeGenOpenCL/address-spaces.cl index b9f01069fa26c..072ce8f922937 100644 --- a/clang/test/CodeGenOpenCL/address-spaces.cl +++ b/clang/test/CodeGenOpenCL/address-spaces.cl @@ -1,15 +1,15 @@ -// RUN: %clang_cc1 %s -O0 -ffake-address-space-map -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK,SPIR -// RUN: %clang_cc1 %s -O0 -cl-std=CL3.0 -cl-ext=-all -ffake-address-space-map -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK,SPIR -// RUN: %clang_cc1 %s -O0 -cl-std=clc++2021 -cl-ext=-all -ffake-address-space-map -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK,SPIR -// RUN: %clang_cc1 %s -O0 -DCL20 -cl-std=CL2.0 -ffake-address-space-map -emit-llvm -o - | FileCheck %s --check-prefixes=CL20,CL20SPIR -// RUN: %clang_cc1 %s -O0 -triple amdgcn-amd-mesa3d -emit-llvm -o - | FileCheck --check-prefixes=CHECK,AMDGCN %s -// RUN: %clang_cc1 %s -O0 -triple amdgcn-amd-mesa3d -cl-std=CL3.0 -emit-llvm -o - | FileCheck --check-prefixes=CHECK,AMDGCN %s -// RUN: %clang_cc1 %s -O0 -triple amdgcn-amd-amdhsa -DCL20 -cl-std=CL2.0 -emit-llvm -o - | FileCheck %s --check-prefixes=CL20,CL20AMDGCN -// RUN: %clang_cc1 %s -O0 -triple amdgcn-amd-amdhsa -DCL20 -cl-std=CL3.0 -emit-llvm -o - | FileCheck %s --check-prefixes=CL20,CL20AMDGCN -// RUN: %clang_cc1 %s -O0 -triple amdgcn-mesa-mesa3d -emit-llvm -o - | FileCheck --check-prefixes=CHECK,AMDGCN %s -// RUN: %clang_cc1 %s -O0 -triple amdgcn-mesa-mesa3d -cl-std=CL3.0 -emit-llvm -o - | FileCheck --check-prefixes=CHECK,AMDGCN %s -// RUN: %clang_cc1 %s -O0 -triple r600-- -emit-llvm -o - | FileCheck --check-prefixes=CHECK,AMDGCN %s -// RUN: %clang_cc1 %s -O0 -triple r600-- -emit-llvm -cl-std=CL3.0 -o - | FileCheck --check-prefixes=CHECK,AMDGCN %s +// RUN: %clang_cc1 %s -O0 -ffake-address-space-map -emit-llvm -o - -Wno-deprecated-attributes | FileCheck %s --check-prefixes=CHECK,SPIR +// RUN: %clang_cc1 %s -O0 -cl-std=CL3.0 -cl-ext=-all -ffake-address-space-map -emit-llvm -o - -Wno-deprecated-attributes | FileCheck %s --check-prefixes=CHECK,SPIR +// RUN: %clang_cc1 %s -O0 -cl-std=clc++2021 -cl-ext=-all -ffake-address-space-map -emit-llvm -o - -Wno-deprecated-attributes | FileCheck %s --check-prefixes=CHECK,SPIR +// RUN: %clang_cc1 %s -O0 -DCL20 -cl-std=CL2.0 -ffake-address-space-map -emit-llvm -o - -Wno-deprecated-attributes | FileCheck %s --check-prefixes=CL20,CL20SPIR +// RUN: %clang_cc1 %s -O0 -triple amdgcn-amd-mesa3d -emit-llvm -o - -Wno-deprecated-attributes | FileCheck --check-prefixes=CHECK,AMDGCN %s +// RUN: %clang_cc1 %s -O0 -triple amdgcn-amd-mesa3d -cl-std=CL3.0 -emit-llvm -o - -Wno-deprecated-attributes | FileCheck --check-prefixes=CHECK,AMDGCN %s +// RUN: %clang_cc1 %s -O0 -triple amdgcn-amd-amdhsa -DCL20 -cl-std=CL2.0 -emit-llvm -o - -Wno-deprecated-attributes | FileCheck %s --check-prefixes=CL20,CL20AMDGCN +// RUN: %clang_cc1 %s -O0 -triple amdgcn-amd-amdhsa -DCL20 -cl-std=CL3.0 -emit-llvm -o - -Wno-deprecated-attributes | FileCheck %s --check-prefixes=CL20,CL20AMDGCN +// RUN: %clang_cc1 %s -O0 -triple amdgcn-mesa-mesa3d -emit-llvm -o - -Wno-deprecated-attributes | FileCheck --check-prefixes=CHECK,AMDGCN %s +// RUN: %clang_cc1 %s -O0 -triple amdgcn-mesa-mesa3d -cl-std=CL3.0 -emit-llvm -o - -Wno-deprecated-attributes | FileCheck --check-prefixes=CHECK,AMDGCN %s +// RUN: %clang_cc1 %s -O0 -triple r600-- -emit-llvm -o - -Wno-deprecated-attributes | FileCheck --check-prefixes=CHECK,AMDGCN %s +// RUN: %clang_cc1 %s -O0 -triple r600-- -emit-llvm -cl-std=CL3.0 -o - -Wno-deprecated-attributes | FileCheck --check-prefixes=CHECK,AMDGCN %s // SPIR: %struct.S = type { i32, i32, ptr } // CL20SPIR: %struct.S = type { i32, i32, ptr addrspace(4) } diff --git a/clang/test/CodeGenOpenCL/amdgpu-sizeof-alignof.cl b/clang/test/CodeGenOpenCL/amdgpu-sizeof-alignof.cl index 3bd395da6d452..1761ae3ac984b 100644 --- a/clang/test/CodeGenOpenCL/amdgpu-sizeof-alignof.cl +++ b/clang/test/CodeGenOpenCL/amdgpu-sizeof-alignof.cl @@ -1,21 +1,17 @@ // RUN: %clang_cc1 -triple r600 -cl-std=CL1.2 %s -emit-llvm -o - | FileCheck %s // RUN: %clang_cc1 -triple amdgcn-mesa-mesa3d -cl-std=CL1.2 %s -emit-llvm -o - | FileCheck %s -// RUN: %clang_cc1 -triple amdgcn---opencl -cl-std=CL1.2 %s -emit-llvm -o - | FileCheck %s -// RUN: %clang_cc1 -triple amdgcn---opencl -cl-std=CL2.0 %s -emit-llvm -o - | FileCheck %s -// RUN: %clang_cc1 -triple amdgcn---amdgizcl -cl-std=CL1.2 %s -emit-llvm -o - | FileCheck %s -// RUN: %clang_cc1 -triple amdgcn---amdgizcl -cl-std=CL2.0 %s -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 -triple amdgcn-amd-amdhsa -cl-std=CL1.2 %s -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 -triple amdgcn-amd-amdhsa -cl-std=CL2.0 %s -emit-llvm -o - | FileCheck %s // RUN: %clang_cc1 -triple r600 -cl-std=CL3.0 %s -emit-llvm -o - | FileCheck %s // RUN: %clang_cc1 -triple amdgcn-mesa-mesa3d -cl-std=CL3.0 %s -emit-llvm -o - | FileCheck %s -// RUN: %clang_cc1 -triple amdgcn---opencl -cl-std=CL3.0 %s -emit-llvm -o - | FileCheck %s -// RUN: %clang_cc1 -triple amdgcn---amdgizcl -cl-std=CL3.0 %s -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 -triple amdgcn-amd-amdhsa -cl-std=CL3.0 %s -emit-llvm -o - | FileCheck %s // RUN: %clang_cc1 -triple amdgcn-mesa-mesa3d -cl-ext=+__opencl_c_generic_address_space -cl-std=CL3.0 %s -emit-llvm -o - | FileCheck %s -// RUN: %clang_cc1 -triple amdgcn---opencl -cl-ext=+__opencl_c_generic_address_space -cl-std=CL3.0 %s -emit-llvm -o - | FileCheck %s -// RUN: %clang_cc1 -triple amdgcn---amdgizcl -cl-ext=+__opencl_c_generic_address_space -cl-std=CL3.0 %s -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 -triple amdgcn-amd-amdhsa -cl-ext=+__opencl_c_generic_address_space -cl-std=CL3.0 %s -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 -triple amdgcn-amd-amdpal -cl-ext=+__opencl_c_generic_address_space -cl-std=CL3.0 %s -emit-llvm -o - | FileCheck %s // RUN: %clang_cc1 -triple r600 -cl-ext=+cl_khr_fp64,+__opencl_c_fp64 -cl-std=CL3.0 %s -emit-llvm -o - | FileCheck %s // RUN: %clang_cc1 -triple amdgcn-mesa-mesa3d -cl-ext=+cl_khr_fp64,+__opencl_c_fp64 -cl-std=CL3.0 %s -emit-llvm -o - | FileCheck %s -// RUN: %clang_cc1 -triple amdgcn---opencl -cl-ext=+cl_khr_fp64,+__opencl_c_fp64 -cl-std=CL3.0 %s -emit-llvm -o - | FileCheck %s -// RUN: %clang_cc1 -triple amdgcn---amdgizcl -cl-ext=+cl_khr_fp64,+__opencl_c_fp64 -cl-std=CL3.0 %s -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 -triple amdgcn-amd-amdhsa -cl-ext=+cl_khr_fp64,+__opencl_c_fp64 -cl-std=CL3.0 %s -emit-llvm -o - | FileCheck %s #ifdef __AMDGCN__ #define PTSIZE 8 diff --git a/clang/test/CodeGenOpenCL/func-call-dbg-loc.cl b/clang/test/CodeGenOpenCL/func-call-dbg-loc.cl index 6b56cbb35f3fd..60bf3916e9937 100644 --- a/clang/test/CodeGenOpenCL/func-call-dbg-loc.cl +++ b/clang/test/CodeGenOpenCL/func-call-dbg-loc.cl @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -triple amdgcn---amdgizcl -debug-info-kind=limited -gno-column-info -O0 -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple amdgcn-amd-amdhsa -debug-info-kind=limited -gno-column-info -O0 -emit-llvm -o - %s | FileCheck %s typedef struct { diff --git a/clang/test/CodeGenSYCL/address-space-conversions.cpp b/clang/test/CodeGenSYCL/address-space-conversions.cpp index 506a24fb4a3ba..138a920880161 100644 --- a/clang/test/CodeGenSYCL/address-space-conversions.cpp +++ b/clang/test/CodeGenSYCL/address-space-conversions.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -triple spir64 -fsycl-is-device -disable-llvm-passes -emit-llvm %s -o - | FileCheck %s +// RUN: %clang_cc1 -triple spir64 -fsycl-is-device -disable-llvm-passes -emit-llvm %s -o - -Wno-deprecated-attributes | FileCheck %s void bar(int &Data) {} // CHECK-DAG: define{{.*}} void @[[RAW_REF:[a-zA-Z0-9_]+]](ptr addrspace(4) noundef align 4 dereferenceable(4) % void bar2(int &Data) {} diff --git a/clang/test/CodeGenSYCL/amd-address-space-conversions.cpp b/clang/test/CodeGenSYCL/amd-address-space-conversions.cpp index 17a98195318ad..beb675e75e5a2 100644 --- a/clang/test/CodeGenSYCL/amd-address-space-conversions.cpp +++ b/clang/test/CodeGenSYCL/amd-address-space-conversions.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -triple amdgcn-amd-amdhsa -fsycl-is-device -disable-llvm-passes -emit-llvm %s -o - | FileCheck %s +// RUN: %clang_cc1 -triple amdgcn-amd-amdhsa -fsycl-is-device -disable-llvm-passes -emit-llvm %s -o - -Wno-deprecated-attributes | FileCheck %s void bar(int &Data) {} // CHECK-DAG: define {{.*}} void @[[RAW_REF:[a-zA-Z0-9_]+]](ptr noundef nonnull align 4 dereferenceable(4) % void bar2(int &Data) {} diff --git a/clang/test/CodeGenSYCL/cuda-address-space-conversions.cpp b/clang/test/CodeGenSYCL/cuda-address-space-conversions.cpp index ffb601e62c118..ca3b7eca7cb4f 100644 --- a/clang/test/CodeGenSYCL/cuda-address-space-conversions.cpp +++ b/clang/test/CodeGenSYCL/cuda-address-space-conversions.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -triple nvptx64-nvidia-cuda -fsycl-is-device -disable-llvm-passes -emit-llvm %s -o - | FileCheck %s +// RUN: %clang_cc1 -triple nvptx64-nvidia-cuda -fsycl-is-device -disable-llvm-passes -emit-llvm %s -o - -Wno-deprecated-attributes | FileCheck %s void bar(int &Data) {} // CHECK-DAG: define {{.*}} void @[[RAW_REF:[a-zA-Z0-9_]+]](ptr noundef nonnull align 4 dereferenceable(4) % void bar2(int &Data) {} diff --git a/clang/test/Sema/LifetimeSafety/safety.cpp b/clang/test/Sema/LifetimeSafety/safety.cpp index b59fac191dcfb..2c2d62b25b6c8 100644 --- a/clang/test/Sema/LifetimeSafety/safety.cpp +++ b/clang/test/Sema/LifetimeSafety/safety.cpp @@ -3955,3 +3955,9 @@ struct [[gsl::Pointer()]] PtrWithInt { int x; }; PtrWithInt f() { return PtrWithInt{10}; } + +// This would normally trigger a suggestion warning if -Wlifetime-safety-suggestions was on. +// Since it is off, we expect NO warnings or notes here. +View suggestion_disabled_test(View a) { + return a; +} diff --git a/clang/test/SemaCXX/amdgpu-feature-builtins-invalid-use.cpp b/clang/test/SemaCXX/amdgpu-feature-builtins-invalid-use.cpp new file mode 100644 index 0000000000000..e4036ed839cab --- /dev/null +++ b/clang/test/SemaCXX/amdgpu-feature-builtins-invalid-use.cpp @@ -0,0 +1,50 @@ +// RUN: %clang_cc1 -triple amdgcn-amd-amdhsa -target-cpu gfx900 -fsyntax-only -verify %s +// RUN: %clang_cc1 -triple spirv64-amd-amdhsa -fsyntax-only -verify=expected,spirv %s + +bool predicate(bool x); +void pass_by_value(__amdgpu_feature_predicate_t x); + +void invalid_uses(int *p, int x, const __amdgpu_feature_predicate_t &lv, + __amdgpu_feature_predicate_t &&rv) { + __amdgpu_feature_predicate_t a; + // expected-error@-1 {{'a' has type __amdgpu_feature_predicate_t, which is not constructible}} + __amdgpu_feature_predicate_t b = __builtin_amdgcn_processor_is("gfx906"); + // expected-error@-1 {{'b' has type __amdgpu_feature_predicate_t, which is not constructible}} + __amdgpu_feature_predicate_t c = lv; + // expected-error@-1 {{'c' has type __amdgpu_feature_predicate_t, which is not constructible}} + __amdgpu_feature_predicate_t d = rv; + // expected-error@-1 {{'d' has type __amdgpu_feature_predicate_t, which is not constructible}} + bool invalid_use_in_init_0 = __builtin_amdgcn_processor_is("gfx906"); + // expected-error@-1 {{'__builtin_amdgcn_processor_is("gfx906")' must be explicitly cast to 'bool'; however, please note that this is almost always an error and that it prevents the effective guarding of target dependent code, and thus should be avoided}} + pass_by_value(__builtin_amdgcn_processor_is("gfx906")); + // expected-error@-1 {{'x' has type __amdgpu_feature_predicate_t, which is not constructible}} + bool invalid_use_in_init_1 = __builtin_amdgcn_is_invocable(__builtin_amdgcn_s_sleep_var); + // expected-error@-1 {{'__builtin_amdgcn_is_invocable(__builtin_amdgcn_s_sleep_var)' must be explicitly cast to 'bool'; however, please note that this is almost always an error and that it prevents the effective guarding of target dependent code, and thus should be avoided}} + if (bool invalid_use_in_init_2 = __builtin_amdgcn_processor_is("gfx906")) return; + // expected-error@-1 {{'__builtin_amdgcn_processor_is("gfx906")' must be explicitly cast to 'bool'; however, please note that this is almost always an error and that it prevents the effective guarding of target dependent code, and thus should be avoided}} + if (predicate(__builtin_amdgcn_processor_is("gfx1200"))) __builtin_amdgcn_s_sleep_var(x); + // expected-error@-1 {{no matching function for call to 'predicate'}} + // expected-error@-2 {{'__builtin_amdgcn_processor_is("gfx1200")' must be explicitly cast to 'bool'; however, please note that this is almost always an error and that it prevents the effective guarding of target dependent code, and thus should be avoided}} + // spirv-error@-3 {{'__builtin_amdgcn_s_sleep_var' cannot be invoked in the current context, as it requires the 'gfx12-insts' feature(s)}} +} + +void invalid_invocations(int x, const char* str) { + if (__builtin_amdgcn_processor_is("not_an_amdgcn_gfx_id")) return; + // expected-error@-1 {{the argument to __builtin_amdgcn_processor_is must be a valid AMDGCN processor identifier; 'not_an_amdgcn_gfx_id' is not valid}} + // expected-note-re@-2 {{valid AMDGCN processor identifiers are: {{.*gfx.*}}}} + if (__builtin_amdgcn_processor_is(str)) return; + // expected-error@-1 {{the argument to __builtin_amdgcn_processor_is must be a string literal}} + if (__builtin_amdgcn_is_invocable("__builtin_amdgcn_s_sleep_var")) return; + // expected-error-re@-1 {{the argument to __builtin_amdgcn_is_invocable must be either a target agnostic builtin or an AMDGCN target specific builtin; {{.*__builtin_amdgcn_s_sleep_var.*}} is not valid}} + else if (__builtin_amdgcn_is_invocable(str)) return; + // expected-error-re@-1 {{the argument to __builtin_amdgcn_is_invocable must be either a target agnostic builtin or an AMDGCN target specific builtin; {{.*str.*}} is not valid}} + else if (__builtin_amdgcn_is_invocable(x)) return; + // expected-error-re@-1 {{the argument to __builtin_amdgcn_is_invocable must be either a target agnostic builtin or an AMDGCN target specific builtin; {{.*x.*}} is not valid}} + else if (__builtin_amdgcn_is_invocable(__builtin_ia32_pause)) return; + // expected-error@-1 {{use of undeclared identifier '__builtin_ia32_pause'}} +} + +bool return_needs_cast() { + return __builtin_amdgcn_processor_is("gfx900"); + // expected-error@-1 {{'__builtin_amdgcn_processor_is("gfx900")' must be explicitly cast to 'bool'; however, please note that this is almost always an error and that it prevents the effective guarding of target dependent code, and thus should be avoided}} +} diff --git a/clang/test/SemaCXX/constant-expression-p2280r4.cpp b/clang/test/SemaCXX/constant-expression-p2280r4.cpp index bb5499e57ac78..77a9891e6620c 100644 --- a/clang/test/SemaCXX/constant-expression-p2280r4.cpp +++ b/clang/test/SemaCXX/constant-expression-p2280r4.cpp @@ -205,8 +205,8 @@ int f() { namespace uninit_reference_used { int y; constexpr int &r = r; // expected-error {{must be initialized by a constant expression}} \ - // expected-note {{initializer of 'r' is not a constant expression}} \ - // expected-note {{declared here}} + // expected-note {{initializer of 'r' is not a constant expression}} \ + // expected-note {{declared here}} constexpr int &rr = (rr, y); constexpr int &g() { int &x = x; // expected-warning {{reference 'x' is not yet bound to a value when used within its own initialization}} \ @@ -224,12 +224,12 @@ namespace uninit_reference_used { // expected-note {{in call to 'g2()'}} constexpr int &g3() { int &x = (x,y); // expected-warning{{left operand of comma operator has no effect}} \ - // expected-warning {{reference 'x' is not yet bound to a value when used within its own initialization}} \ - // nointerpreter-note {{use of reference outside its lifetime is not allowed in a constant expression}} + // expected-warning {{reference 'x' is not yet bound to a value when used within its own initialization}} \ + // expected-note {{use of reference outside its lifetime is not allowed in a constant expression}} return x; } - constexpr int &gg3 = g3(); // nointerpreter-error {{must be initialized by a constant expression}} \ - // nointerpreter-note {{in call to 'g3()'}} + constexpr int &gg3 = g3(); // expected-error {{must be initialized by a constant expression}} \ + // expected-note {{in call to 'g3()'}} typedef decltype(sizeof(1)) uintptr_t; constexpr uintptr_t g4() { uintptr_t * &x = x; // expected-warning {{reference 'x' is not yet bound to a value when used within its own initialization}} \ diff --git a/clang/test/SemaOpenCL/usm-address-spaces-conversions.cl b/clang/test/SemaOpenCL/usm-address-spaces-conversions.cl index 668b0db70d49e..8817e1ab42ee2 100644 --- a/clang/test/SemaOpenCL/usm-address-spaces-conversions.cl +++ b/clang/test/SemaOpenCL/usm-address-spaces-conversions.cl @@ -24,14 +24,14 @@ #endif // CONSTANT void test(AS_COMP int *arg_comp, - __attribute__((opencl_global_device)) int *arg_device, - __attribute__((opencl_global_host)) int *arg_host) { + __attribute__((opencl_global_device)) int *arg_device, // expected-warning {{''opencl_global_device'' attribute is deprecated}} + __attribute__((opencl_global_host)) int *arg_host) { // expected-warning {{''opencl_global_host'' attribute is deprecated}} AS_COMP int *var_glob1 = arg_device; AS_COMP int *var_glob2 = arg_host; AS_COMP int *var_glob3 = (AS_COMP int *)arg_device; AS_COMP int *var_glob4 = (AS_COMP int *)arg_host; - arg_device = (__attribute__((opencl_global_device)) int *)arg_comp; - arg_host = (__attribute__((opencl_global_host)) int *)arg_comp; + arg_device = (__attribute__((opencl_global_device)) int *)arg_comp; // expected-warning {{''opencl_global_device'' attribute is deprecated}} + arg_host = (__attribute__((opencl_global_host)) int *)arg_comp; // expected-warning {{''opencl_global_host'' attribute is deprecated}} #ifdef GENERIC // expected-error@+6{{assigning '__generic int *__private' to '__global_device int *__private' changes address space of pointer}} // expected-error@+6{{assigning '__generic int *__private' to '__global_host int *__private' changes address space of pointer}} @@ -61,7 +61,7 @@ void test(AS_COMP int *arg_comp, AS_INCOMP int *var_incomp1 = arg_device; AS_INCOMP int *var_incomp2 = arg_host; AS_INCOMP int *var_incomp3 = - (__attribute__((opencl_global_device)) int *)arg_device; + (__attribute__((opencl_global_device)) int *)arg_device; // expected-warning {{''opencl_global_device'' attribute is deprecated}} AS_INCOMP int *var_incomp4 = - (__attribute__((opencl_global_host)) int *)arg_host; + (__attribute__((opencl_global_host)) int *)arg_host; // expected-warning {{''opencl_global_host'' attribute is deprecated}} } diff --git a/clang/test/SemaSYCL/address-space-conversions.cpp b/clang/test/SemaSYCL/address-space-conversions.cpp index d8758248499de..e1a078338d523 100644 --- a/clang/test/SemaSYCL/address-space-conversions.cpp +++ b/clang/test/SemaSYCL/address-space-conversions.cpp @@ -65,16 +65,16 @@ void usages() { (void)i; (void)v; - __attribute__((opencl_global_host)) int *GLOB_HOST; + __attribute__((opencl_global_host)) int *GLOB_HOST; // expected-warning {{''opencl_global_host'' attribute is deprecated}} bar(*GLOB_HOST); bar2(*GLOB_HOST); GLOB = GLOB_HOST; GLOB_HOST = GLOB; // expected-error {{assigning '__global int *' to '__global_host int *' changes address space of pointer}} - GLOB_HOST = static_cast<__attribute__((opencl_global_host)) int *>(GLOB); // expected-error {{static_cast from '__global int *' to '__global_host int *' is not allowed}} - __attribute__((opencl_global_device)) int *GLOB_DEVICE; + GLOB_HOST = static_cast<__attribute__((opencl_global_host)) int *>(GLOB); // expected-warning {{''opencl_global_host'' attribute is deprecated}} expected-error {{static_cast from '__global int *' to '__global_host int *' is not allowed}} + __attribute__((opencl_global_device)) int *GLOB_DEVICE; // expected-warning {{''opencl_global_device'' attribute is deprecated}} bar(*GLOB_DEVICE); bar2(*GLOB_DEVICE); GLOB = GLOB_DEVICE; GLOB_DEVICE = GLOB; // expected-error {{assigning '__global int *' to '__global_device int *' changes address space of pointer}} - GLOB_DEVICE = static_cast<__attribute__((opencl_global_device)) int *>(GLOB); // expected-error {{static_cast from '__global int *' to '__global_device int *' is not allowed}} + GLOB_DEVICE = static_cast<__attribute__((opencl_global_device)) int *>(GLOB); // expected-warning {{''opencl_global_device'' attribute is deprecated}} expected-error {{static_cast from '__global int *' to '__global_device int *' is not allowed}} } diff --git a/clang/unittests/AST/CommentLexer.cpp b/clang/unittests/AST/CommentLexer.cpp index 99f469173964e..1d016cee2877b 100644 --- a/clang/unittests/AST/CommentLexer.cpp +++ b/clang/unittests/AST/CommentLexer.cpp @@ -447,22 +447,22 @@ TEST_F(CommentLexerTest, DoxygenCommand9) { ASSERT_EQ(tok::text, Toks[0].getKind()); ASSERT_EQ(StringRef(" "), Toks[0].getText()); - ASSERT_EQ(tok::unknown_command, Toks[1].getKind()); + ASSERT_EQ(tok::unknown_backslash_command, Toks[1].getKind()); ASSERT_EQ(StringRef("aaa"), Toks[1].getUnknownCommandName()); - ASSERT_EQ(tok::unknown_command, Toks[2].getKind()); + ASSERT_EQ(tok::unknown_backslash_command, Toks[2].getKind()); ASSERT_EQ(StringRef("bbb"), Toks[2].getUnknownCommandName()); ASSERT_EQ(tok::text, Toks[3].getKind()); ASSERT_EQ(StringRef(" "), Toks[3].getText()); - ASSERT_EQ(tok::unknown_command, Toks[4].getKind()); + ASSERT_EQ(tok::unknown_backslash_command, Toks[4].getKind()); ASSERT_EQ(StringRef("ccc"), Toks[4].getUnknownCommandName()); ASSERT_EQ(tok::text, Toks[5].getKind()); ASSERT_EQ(StringRef("\t"), Toks[5].getText()); - ASSERT_EQ(tok::unknown_command, Toks[6].getKind()); + ASSERT_EQ(tok::unknown_backslash_command, Toks[6].getKind()); ASSERT_EQ(StringRef("ddd"), Toks[6].getUnknownCommandName()); ASSERT_EQ(tok::newline, Toks[7].getKind()); @@ -485,6 +485,38 @@ TEST_F(CommentLexerTest, DoxygenCommand10) { ASSERT_EQ(tok::newline, Toks[2].getKind()); } +TEST_F(CommentLexerTest, DoxygenCommand11) { + const char *Source = "/// @aaa@bbb @ccc\t@ddd\n"; + std::vector Toks; + + lexString(Source, Toks); + + ASSERT_EQ(8U, Toks.size()); + + ASSERT_EQ(tok::text, Toks[0].getKind()); + ASSERT_EQ(StringRef(" "), Toks[0].getText()); + + ASSERT_EQ(tok::unknown_at_command, Toks[1].getKind()); + ASSERT_EQ(StringRef("aaa"), Toks[1].getUnknownCommandName()); + + ASSERT_EQ(tok::unknown_at_command, Toks[2].getKind()); + ASSERT_EQ(StringRef("bbb"), Toks[2].getUnknownCommandName()); + + ASSERT_EQ(tok::text, Toks[3].getKind()); + ASSERT_EQ(StringRef(" "), Toks[3].getText()); + + ASSERT_EQ(tok::unknown_at_command, Toks[4].getKind()); + ASSERT_EQ(StringRef("ccc"), Toks[4].getUnknownCommandName()); + + ASSERT_EQ(tok::text, Toks[5].getKind()); + ASSERT_EQ(StringRef("\t"), Toks[5].getText()); + + ASSERT_EQ(tok::unknown_at_command, Toks[6].getKind()); + ASSERT_EQ(StringRef("ddd"), Toks[6].getUnknownCommandName()); + + ASSERT_EQ(tok::newline, Toks[7].getKind()); +} + TEST_F(CommentLexerTest, RegisterCustomBlockCommand) { const char *Source = "/// \\NewBlockCommand Aaa.\n" diff --git a/compiler-rt/lib/tysan/tysan.cpp b/compiler-rt/lib/tysan/tysan.cpp index 0be4fe91a7938..8b3b60dc4cf83 100644 --- a/compiler-rt/lib/tysan/tysan.cpp +++ b/compiler-rt/lib/tysan/tysan.cpp @@ -331,8 +331,6 @@ __tysan_instrument_mem_inst(char *dest, char *src, uint64_t size, if (needsMemMove) { internal_memmove((char *)destShadowDataPtr, srcShadow, size << PtrShift()); - } else { - internal_memcpy((char *)destShadowDataPtr, srcShadow, size << PtrShift()); } } diff --git a/compiler-rt/lib/tysan/tysan_interceptors.cpp b/compiler-rt/lib/tysan/tysan_interceptors.cpp index 095ce0e74bb8b..1ba613d603ee8 100644 --- a/compiler-rt/lib/tysan/tysan_interceptors.cpp +++ b/compiler-rt/lib/tysan/tysan_interceptors.cpp @@ -53,18 +53,6 @@ INTERCEPTOR(void *, memmove, void *dst, const void *src, uptr size) { return res; } -INTERCEPTOR(void *, memcpy, void *dst, const void *src, uptr size) { - if (!tysan_inited && REAL(memcpy) == nullptr) { - // memmove is used here because on some platforms this will also - // intercept the memmove implementation. - return internal_memmove(dst, src, size); - } - - void *res = REAL(memcpy)(dst, src, size); - tysan_copy_types(dst, src, size); - return res; -} - INTERCEPTOR(void *, mmap, void *addr, SIZE_T length, int prot, int flags, int fd, OFF_T offset) { void *res = REAL(mmap)(addr, length, prot, flags, fd, offset); @@ -238,7 +226,6 @@ void InitializeInterceptors() { INTERCEPT_FUNCTION(memset); INTERCEPT_FUNCTION(memmove); - INTERCEPT_FUNCTION(memcpy); inited = 1; } diff --git a/compiler-rt/test/tysan/global.c b/compiler-rt/test/tysan/global.c index 247ee768a8162..9fac976776410 100644 --- a/compiler-rt/test/tysan/global.c +++ b/compiler-rt/test/tysan/global.c @@ -12,20 +12,12 @@ int main() { // CHECK: WRITE of size 4 at {{.*}} with type int accesses an existing object of type float // CHECK: {{#0 0x.* in main .*global.c:}}[[@LINE-3]] - void *mem = malloc(sizeof(long)); - *(int *)mem = 6; - memcpy(mem, &L, sizeof(L)); - *(int *)mem = 8; + P = *(((float *)&L) + 1); // CHECK: ERROR: TypeSanitizer: type-aliasing-violation - // CHECK: WRITE of size 4 at {{.*}} with type int accesses an existing object of type long + // CHECK: READ of size 4 at {{.*}} with type float accesses part of an existing object of type long that starts at offset -4 // CHECK: {{#0 0x.* in main .*global.c:}}[[@LINE-3]] - int r = *(((int *)mem) + 1); - // CHECK: ERROR: TypeSanitizer: type-aliasing-violation - // CHECK: READ of size 4 at {{.*}} with type int accesses part of an existing object of type long that starts at offset -4 - // CHECK: {{#0 0x.* in main .*global.c:}}[[@LINE-3]] - free(mem); - return r; + return 0; } // CHECK-NOT: ERROR: TypeSanitizer: type-aliasing-violation diff --git a/compiler-rt/test/tysan/memcpy_doesnt_change_shadow.c b/compiler-rt/test/tysan/memcpy_doesnt_change_shadow.c new file mode 100644 index 0000000000000..2545acfa1fbb3 --- /dev/null +++ b/compiler-rt/test/tysan/memcpy_doesnt_change_shadow.c @@ -0,0 +1,25 @@ +// RUN: %clang_tysan -O0 %s -o %t && %run %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out + +#include +#include + +int main() { + + int i = 0; + float f = 5.0f; + + *(float *)&i = 3.0f; + *(int *)&f = 2; + // CHECK: WRITE of size 4 at 0x{{.*}} with type float accesses an existing object of type int + // CHECK: WRITE of size 4 at 0x{{.*}} with type int accesses an existing object of type float + + memcpy(&i, &f, sizeof(int)); + + *(float *)&i = 3.0f; + *(int *)&f = 2; + // CHECK: WRITE of size 4 at 0x{{.*}} with type float accesses an existing object of type int + // CHECK: WRITE of size 4 at 0x{{.*}} with type int accesses an existing object of type float + + return 0; +} diff --git a/flang-rt/lib/runtime/CMakeLists.txt b/flang-rt/lib/runtime/CMakeLists.txt index 1cb65c5c6f696..96dd0b1abe305 100644 --- a/flang-rt/lib/runtime/CMakeLists.txt +++ b/flang-rt/lib/runtime/CMakeLists.txt @@ -12,16 +12,10 @@ find_package(Backtrace) set(HAVE_BACKTRACE ${Backtrace_FOUND}) set(BACKTRACE_HEADER ${Backtrace_HEADER}) -# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror") - -# Module sources that are required by other modules -set(intrinsics_sources - __fortran_builtins.f90 - __cuda_builtins.f90 -) - # Fortran sources for builtin .mod files set(module_sources + __fortran_builtins.f90 + __cuda_builtins.f90 __fortran_ieee_exceptions.f90 __fortran_type_info.f90 f90deviceio.f90 @@ -218,10 +212,8 @@ file(GLOB_RECURSE private_headers ) if (LLVM_TARGET_TRIPLE MATCHES "^ppc|^powerpc") - list(APPEND intrinsics_sources - __ppc_types.f90 - ) list(APPEND module_sources + __ppc_types.f90 __ppc_intrinsics.f90 mma.f90 ) @@ -267,21 +259,6 @@ if (TARGET FortranFloat128MathILib) endif () -# When a target depends on an object library, CMake seems to try to only build -# the object files that the target actual needs. If we are only interested -# in the module files, nothing gets built at all. To ensure that the module -# files are built, insert a custom target that is opaque to CMake so it cannot -# apply this optimization. Dependees on module files must depend on this -# barrier instead. An actual COMMAND (that does nothing) seems to be necessary -# on Windows to work. -function (add_module_barrier barriername objlib) - add_custom_target(${barriername} - COMMAND ${CMAKE_COMMAND} -E true - ) - add_dependencies(${barriername} ${objlib}) -endfunction () - - # Build module files if requested. # The object files written by Flang for these are unused. In the future parts # of flang-rt may itself be implemented in Fortran in which case these Fortran @@ -289,50 +266,10 @@ endfunction () # libflang_rt.runtime{.a/.so}. If they also provide an importable .mod, add them # to flang_module_target(... PUBLIC). if (FLANG_RT_FORTRAN_MODULES) - # CMake ignores intrinsic USE dependencies - # CMake has an option Fortran_BUILDING_INSTRINSIC_MODULES/Fortran_BUILDING_INTRINSIC_MODULES - # to disable this behavior, unfortunately it does not work with Ninja - # (https://gitlab.kitware.com/cmake/cmake/-/issues/26803) - # As a workaround, we build those intrinsic modules first such that the main - # runtime can depend on it. To ensure that modules files are also transitively - # updated if a USE'd .mod file changes (a .mod stores the checksums of all - # .mod files it depends on and therefore needs to be updated as well), inject - # an file-level dependency via OBJECT_DEPENDS. - - add_flangrt_library(flang_rt.mod.fortran.builtins OBJECT - __fortran_builtins.f90 - ) - set_property(SOURCE __fortran_builtins.f90 PROPERTY OBJECT_OUTPUTS "${CMAKE_BINARY_DIR}/modules/${CMAKE_CFG_INTDIR}/__fortran_builtins${CMAKE_Fortran_OUTPUT_EXTENSION}") - flang_module_target(flang_rt.mod.fortran.builtins PUBLIC) - add_module_barrier(flang_rt.mod.fortran.builtins.barrier flang_rt.mod.fortran.builtins) - - add_flangrt_library(flang_rt.mod.cuda.builtins OBJECT - __cuda_builtins.f90 - ) - set_property(SOURCE __cuda_builtins.f90 PROPERTY OBJECT_OUTPUTS "${CMAKE_BINARY_DIR}/modules/${CMAKE_CFG_INTDIR}/__cuda_builtins${CMAKE_Fortran_OUTPUT_EXTENSION}") - add_dependencies(flang_rt.mod.cuda.builtins flang_rt.mod.fortran.builtins.barrier) - set_property(SOURCE __cuda_builtins.f90 - APPEND PROPERTY OBJECT_DEPENDS - "${CMAKE_BINARY_DIR}/modules/${CMAKE_CFG_INTDIR}/__fortran_builtins${CMAKE_Fortran_OUTPUT_EXTENSION}" - ) - flang_module_target(flang_rt.mod.cuda.builtins PUBLIC) - add_module_barrier(flang_rt.mod.cuda.builtins.barrier flang_rt.mod.cuda.builtins) - - # The modules themselves - add_flangrt_library(flang_rt.mod OBJECT + add_flangrt_library(flang-rt-mod OBJECT ${module_sources} ) - add_dependencies(flang_rt.mod flang_rt.mod.fortran.builtins.barrier flang_rt.mod.cuda.builtins.barrier) - foreach(_srcfile IN LISTS module_sources) - set_property(SOURCE ${_srcfile} - APPEND PROPERTY OBJECT_DEPENDS - "${CMAKE_BINARY_DIR}/modules/${CMAKE_CFG_INTDIR}/__fortran_builtins${CMAKE_Fortran_OUTPUT_EXTENSION}" - "${CMAKE_BINARY_DIR}/modules/${CMAKE_CFG_INTDIR}/__cuda_builtins${CMAKE_Fortran_OUTPUT_EXTENSION}" - ) - endforeach() - - flang_module_target(flang_rt.mod PUBLIC) - add_module_barrier(flang-rt-mod flang_rt.mod) + flang_module_target(flang-rt-mod PUBLIC) if (RUNTIMES_FORTRAN_MODULES) set(_mod_install_dest "${RUNTIMES_INSTALL_RESOURCE_MOD_PATH}/..") diff --git a/flang-rt/lib/runtime/__fortran_type_info.f90 b/flang-rt/lib/runtime/__fortran_type_info.f90 index 0f1c3d018d009..d8cf385b8665e 100644 --- a/flang-rt/lib/runtime/__fortran_type_info.f90 +++ b/flang-rt/lib/runtime/__fortran_type_info.f90 @@ -13,7 +13,7 @@ module __fortran_type_info - use, intrinsic :: __fortran_builtins, & + use __fortran_builtins, & only: __builtin_c_ptr, __builtin_c_devptr, __builtin_c_funptr implicit none diff --git a/flang-rt/lib/runtime/cooperative_groups.f90 b/flang-rt/lib/runtime/cooperative_groups.f90 index 5ca0c3aa1f3a5..5c141d4d254db 100644 --- a/flang-rt/lib/runtime/cooperative_groups.f90 +++ b/flang-rt/lib/runtime/cooperative_groups.f90 @@ -10,8 +10,8 @@ module cooperative_groups -use, intrinsic :: __fortran_builtins, only: c_devptr => __builtin_c_devptr -use :: cudadevice ! implicit dependency, made explicit for CMake +use __fortran_builtins, only: c_devptr => __builtin_c_devptr +use cudadevice ! implicit dependency, made explicit for CMake implicit none diff --git a/flang-rt/lib/runtime/cudadevice.f90 b/flang-rt/lib/runtime/cudadevice.f90 index be041ba9d0a71..ea4787dd62e40 100644 --- a/flang-rt/lib/runtime/cudadevice.f90 +++ b/flang-rt/lib/runtime/cudadevice.f90 @@ -10,9 +10,9 @@ module cudadevice use __cuda_device - use, intrinsic :: __fortran_builtins, only: dim3 => __builtin_dim3 - use, intrinsic :: __fortran_builtins, only: c_devptr => __builtin_c_devptr - use, intrinsic :: __fortran_builtins, only: c_devloc => __builtin_c_devloc + use __fortran_builtins, only: dim3 => __builtin_dim3 + use __fortran_builtins, only: c_devptr => __builtin_c_devptr + use __fortran_builtins, only: c_devloc => __builtin_c_devloc implicit none ! Synchronization Functions diff --git a/flang/lib/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.cpp b/flang/lib/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.cpp index da9114200a5f2..e0ab6b148f11b 100644 --- a/flang/lib/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.cpp +++ b/flang/lib/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.cpp @@ -345,7 +345,9 @@ generateSeqTyAccBounds(fir::SequenceType seqType, mlir::Value var, firBuilder, loc, exv, info); } - assert(false && "array with unknown dimension expected to have descriptor"); + // An assumed-size array (or other non-descriptor array with an unknown + // trailing extent) has no recoverable bounds here and is passed without a + // descriptor; map it without bounds rather than asserting. return {}; } diff --git a/flang/lib/Semantics/openmp-utils.cpp b/flang/lib/Semantics/openmp-utils.cpp index cfdf2f8eb56c9..ffda807c2dc32 100644 --- a/flang/lib/Semantics/openmp-utils.cpp +++ b/flang/lib/Semantics/openmp-utils.cpp @@ -27,6 +27,7 @@ #include "flang/Parser/openmp-utils.h" #include "flang/Parser/parse-tree.h" #include "flang/Semantics/expression.h" +#include "flang/Semantics/openmp-directive-sets.h" #include "flang/Semantics/scope.h" #include "flang/Semantics/semantics.h" #include "flang/Semantics/symbol.h" @@ -2318,6 +2319,31 @@ UnsupportedSelectorFeature FindUnsupportedSelectorFeature( return UnsupportedSelectorFeature::None; } +// Add the construct trait properties implied by an OpenMP directive (e.g. +// `target` adds `construct_target_target`, `target teams` adds both +// `construct_target_target` and `construct_teams_teams`) to \p vmi. This +// decomposes combined/composite construct selectors into their leaf traits. +static void AppendConstructTraitsForDirective( + llvm::omp::Directive dir, llvm::omp::VariantMatchInfo &vmi) { + auto add = [&](llvm::omp::TraitProperty prop) { + vmi.addTrait(prop, llvm::omp::getOpenMPContextTraitPropertyName(prop, "")); + }; + if (llvm::omp::allTargetSet.test(dir)) + add(llvm::omp::TraitProperty::construct_target_target); + if (llvm::omp::allTeamsSet.test(dir)) + add(llvm::omp::TraitProperty::construct_teams_teams); + if (llvm::omp::allParallelSet.test(dir)) + add(llvm::omp::TraitProperty::construct_parallel_parallel); + if (llvm::omp::allDoSet.test(dir)) + add(llvm::omp::TraitProperty::construct_for_for); + if (llvm::omp::allSimdSet.test(dir)) + add(llvm::omp::TraitProperty::construct_simd_simd); + // dispatch is a standalone construct trait (not part of any combined + // directive set), so it is matched explicitly. + if (dir == llvm::omp::Directive::OMPD_dispatch) + add(llvm::omp::TraitProperty::construct_dispatch_dispatch); +} + static void AddTraitPropertiesFromSelector(llvm::omp::TraitSet set, const parser::OmpTraitSelector &selector, llvm::omp::VariantMatchInfo &vmi, SemanticsContext &semaCtx, @@ -2368,10 +2394,8 @@ static void AddTraitPropertiesFromSelector(llvm::omp::TraitSet set, // Construct trait selector with no properties (e.g. `construct={simd}`): // the selector itself implies the property. - llvm::omp::TraitProperty propKind{ - llvm::omp::getOpenMPContextTraitPropertyForSelector(selectorKind)}; - if (propKind != llvm::omp::TraitProperty::invalid) { - vmi.addTrait(set, propKind, traitName.ToString(), scorePtr); + if (const auto *dir{std::get_if(&traitName.u)}) { + AppendConstructTraitsForDirective(*dir, vmi); } } diff --git a/flang/test/Fir/OpenACC/openacc-mappable.fir b/flang/test/Fir/OpenACC/openacc-mappable.fir index 91a83915a0900..900ba2886c67e 100644 --- a/flang/test/Fir/OpenACC/openacc-mappable.fir +++ b/flang/test/Fir/OpenACC/openacc-mappable.fir @@ -141,4 +141,19 @@ module attributes {dlti.dl_spec = #dlti.dl_spec : vector<2xi64>, // CHECK: fir.result %[[ZERO]], %[[MINUSONE]], %[[ZERO]], %[[ZERO]], %[[ZERO]] : index, index, index, index, index // CHECK: } // CHECK: Upper bound: %[[IF]]:5 = fir.if %[[PRESENT]] -> (index, index, index, index, index) { + + // An assumed-size array (unknown trailing extent) passed without a + // descriptor, whose acc clause operand is not produced by an [hl]fir.declare + // (so no shape is recoverable). It must produce no bounds. + func.func @_QPassumed_size_no_descriptor(%arg0: !fir.ref> {fir.bindc_name = "a"}) { + %0 = fir.convert %arg0 : (!fir.ref>) -> !fir.ref> + %1 = acc.copyin varPtr(%0 : !fir.ref>) -> !fir.ref> {name = "a", structured = false} + acc.enter_data dataOperands(%1 : !fir.ref>) + return + } + // CHECK: Visiting: %{{.*}} = acc.copyin varPtr(%{{.*}} : !fir.ref>) -> !fir.ref> {name = "a", structured = false} + // CHECK: Pointer-like and Mappable: !fir.ref> + // CHECK: Type category: array + // CHECK: Has unknown dimensions: true + // CHECK-NOT: Bound[ } diff --git a/flang/test/Lower/OpenMP/metadirective-construct.f90 b/flang/test/Lower/OpenMP/metadirective-construct.f90 index 5c2fdf93b6057..d21585699cd5a 100644 --- a/flang/test/Lower/OpenMP/metadirective-construct.f90 +++ b/flang/test/Lower/OpenMP/metadirective-construct.f90 @@ -95,3 +95,22 @@ subroutine test_begin_construct_selected_parent() !$omp end metadirective !$omp end target end subroutine + +! CHECK-LABEL: func.func @_QPtest_construct_combined_directive( +! CHECK: omp.target +! CHECK: omp.parallel +! CHECK-NOT: omp.taskyield +! CHECK: omp.barrier +! CHECK: omp.terminator +! CHECK: omp.terminator +! CHECK: return +subroutine test_construct_combined_directive() + !$omp target + !$omp parallel + !$omp metadirective & + !$omp & when(construct={parallel}: taskyield) & + !$omp & when(construct={target parallel}: barrier) & + !$omp & default(nothing) + !$omp end parallel + !$omp end target +end subroutine diff --git a/libc/config/baremetal/aarch64/entrypoints.txt b/libc/config/baremetal/aarch64/entrypoints.txt index f64eb55b40acd..73f4c1f937388 100644 --- a/libc/config/baremetal/aarch64/entrypoints.txt +++ b/libc/config/baremetal/aarch64/entrypoints.txt @@ -865,6 +865,7 @@ list(APPEND TARGET_LIBM_ENTRYPOINTS libc.src.math.setpayloadbf16 libc.src.math.setpayloadsigbf16 libc.src.math.sqrtbf16 + libc.src.math.tanbf16 libc.src.math.truncbf16 libc.src.math.totalorderbf16 libc.src.math.totalordermagbf16 diff --git a/libc/config/baremetal/arm/entrypoints.txt b/libc/config/baremetal/arm/entrypoints.txt index 55a175923faa1..a5c1b20a7a434 100644 --- a/libc/config/baremetal/arm/entrypoints.txt +++ b/libc/config/baremetal/arm/entrypoints.txt @@ -876,6 +876,7 @@ list(APPEND TARGET_LIBM_ENTRYPOINTS libc.src.math.setpayloadbf16 libc.src.math.setpayloadsigbf16 libc.src.math.sqrtbf16 + libc.src.math.tanbf16 libc.src.math.truncbf16 libc.src.math.totalorderbf16 libc.src.math.totalordermagbf16 diff --git a/libc/config/baremetal/riscv/entrypoints.txt b/libc/config/baremetal/riscv/entrypoints.txt index 201d2e9cbf97b..60bc924993fc8 100644 --- a/libc/config/baremetal/riscv/entrypoints.txt +++ b/libc/config/baremetal/riscv/entrypoints.txt @@ -873,6 +873,7 @@ list(APPEND TARGET_LIBM_ENTRYPOINTS libc.src.math.setpayloadbf16 libc.src.math.setpayloadsigbf16 libc.src.math.sqrtbf16 + libc.src.math.tanbf16 libc.src.math.truncbf16 libc.src.math.totalorderbf16 libc.src.math.totalordermagbf16 diff --git a/libc/config/darwin/aarch64/entrypoints.txt b/libc/config/darwin/aarch64/entrypoints.txt index 413534a14f34e..6f4916b203de5 100644 --- a/libc/config/darwin/aarch64/entrypoints.txt +++ b/libc/config/darwin/aarch64/entrypoints.txt @@ -686,6 +686,7 @@ list(APPEND TARGET_LIBM_ENTRYPOINTS libc.src.math.setpayloadbf16 libc.src.math.setpayloadsigbf16 libc.src.math.sqrtbf16 + libc.src.math.tanbf16 libc.src.math.truncbf16 libc.src.math.totalorderbf16 libc.src.math.totalordermagbf16 diff --git a/libc/config/darwin/x86_64/entrypoints.txt b/libc/config/darwin/x86_64/entrypoints.txt index d35700d341d1a..c09ccadbb8c4c 100644 --- a/libc/config/darwin/x86_64/entrypoints.txt +++ b/libc/config/darwin/x86_64/entrypoints.txt @@ -304,6 +304,7 @@ list(APPEND TARGET_LIBM_ENTRYPOINTS libc.src.math.setpayloadbf16 libc.src.math.setpayloadsigbf16 libc.src.math.sqrtbf16 + libc.src.math.tanbf16 libc.src.math.truncbf16 libc.src.math.totalorderbf16 libc.src.math.totalordermagbf16 diff --git a/libc/config/freebsd/x86_64/entrypoints.txt b/libc/config/freebsd/x86_64/entrypoints.txt index 394b83130f067..7b8b8384e6dd8 100644 --- a/libc/config/freebsd/x86_64/entrypoints.txt +++ b/libc/config/freebsd/x86_64/entrypoints.txt @@ -627,6 +627,7 @@ list(APPEND TARGET_LIBM_ENTRYPOINTS libc.src.math.setpayloadbf16 libc.src.math.setpayloadsigbf16 libc.src.math.sqrtbf16 + libc.src.math.tanbf16 libc.src.math.truncbf16 libc.src.math.totalorderbf16 libc.src.math.totalordermagbf16 diff --git a/libc/config/gpu/amdgpu/entrypoints.txt b/libc/config/gpu/amdgpu/entrypoints.txt index 7fcab53bd99f3..60a98cf5c773f 100644 --- a/libc/config/gpu/amdgpu/entrypoints.txt +++ b/libc/config/gpu/amdgpu/entrypoints.txt @@ -711,6 +711,7 @@ list(APPEND TARGET_LIBM_ENTRYPOINTS libc.src.math.setpayloadbf16 libc.src.math.setpayloadsigbf16 libc.src.math.sqrtbf16 + libc.src.math.tanbf16 libc.src.math.truncbf16 libc.src.math.totalorderbf16 libc.src.math.totalordermagbf16 diff --git a/libc/config/gpu/nvptx/entrypoints.txt b/libc/config/gpu/nvptx/entrypoints.txt index be1467e9cbceb..70bdbde97e868 100644 --- a/libc/config/gpu/nvptx/entrypoints.txt +++ b/libc/config/gpu/nvptx/entrypoints.txt @@ -713,6 +713,7 @@ list(APPEND TARGET_LIBM_ENTRYPOINTS libc.src.math.setpayloadbf16 libc.src.math.setpayloadsigbf16 libc.src.math.sqrtbf16 + libc.src.math.tanbf16 libc.src.math.truncbf16 libc.src.math.totalorderbf16 libc.src.math.totalordermagbf16 diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt index 599ae32a35073..570f7666ba67b 100644 --- a/libc/config/linux/aarch64/entrypoints.txt +++ b/libc/config/linux/aarch64/entrypoints.txt @@ -986,6 +986,7 @@ list(APPEND TARGET_LIBM_ENTRYPOINTS libc.src.math.setpayloadbf16 libc.src.math.setpayloadsigbf16 libc.src.math.sqrtbf16 + libc.src.math.tanbf16 libc.src.math.truncbf16 libc.src.math.totalorderbf16 libc.src.math.totalordermagbf16 @@ -1177,6 +1178,7 @@ if(LLVM_LIBC_FULL_BUILD) libc.src.stdlib.exit libc.src.stdlib.getenv libc.src.stdlib.setenv + libc.src.stdlib.unsetenv libc.src.stdlib.quick_exit # signal.h entrypoints diff --git a/libc/config/linux/aarch64/headers.txt b/libc/config/linux/aarch64/headers.txt index a7ce42c9c4a91..0f6687dcd8a2d 100644 --- a/libc/config/linux/aarch64/headers.txt +++ b/libc/config/linux/aarch64/headers.txt @@ -15,6 +15,7 @@ set(TARGET_PUBLIC_HEADERS libc.include.fenv libc.include.float libc.include.inttypes + libc.include.libgen libc.include.limits libc.include.link libc.include.locale diff --git a/libc/config/linux/arm/entrypoints.txt b/libc/config/linux/arm/entrypoints.txt index d610e663229ba..e6aa6091ed550 100644 --- a/libc/config/linux/arm/entrypoints.txt +++ b/libc/config/linux/arm/entrypoints.txt @@ -557,6 +557,7 @@ list(APPEND TARGET_LIBM_ENTRYPOINTS libc.src.math.setpayloadbf16 libc.src.math.setpayloadsigbf16 libc.src.math.sqrtbf16 + libc.src.math.tanbf16 libc.src.math.truncbf16 libc.src.math.totalorderbf16 libc.src.math.totalordermagbf16 diff --git a/libc/config/linux/arm/headers.txt b/libc/config/linux/arm/headers.txt index c8ca848b79f09..50627958eb38c 100644 --- a/libc/config/linux/arm/headers.txt +++ b/libc/config/linux/arm/headers.txt @@ -6,6 +6,7 @@ set(TARGET_PUBLIC_HEADERS libc.include.fenv libc.include.float libc.include.inttypes + libc.include.libgen libc.include.malloc libc.include.math libc.include.search diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt index ef2d13e6d6f9e..2508de5cfe5a4 100644 --- a/libc/config/linux/riscv/entrypoints.txt +++ b/libc/config/linux/riscv/entrypoints.txt @@ -1007,6 +1007,7 @@ list(APPEND TARGET_LIBM_ENTRYPOINTS libc.src.math.setpayloadbf16 libc.src.math.setpayloadsigbf16 libc.src.math.sqrtbf16 + libc.src.math.tanbf16 libc.src.math.truncbf16 libc.src.math.totalorderbf16 libc.src.math.totalordermagbf16 @@ -1306,6 +1307,7 @@ if(LLVM_LIBC_FULL_BUILD) libc.src.stdlib.exit libc.src.stdlib.getenv libc.src.stdlib.setenv + libc.src.stdlib.unsetenv libc.src.stdlib.quick_exit # signal.h entrypoints diff --git a/libc/config/linux/riscv/headers.txt b/libc/config/linux/riscv/headers.txt index ce9cda307caf3..03bc2abd9ddea 100644 --- a/libc/config/linux/riscv/headers.txt +++ b/libc/config/linux/riscv/headers.txt @@ -15,6 +15,7 @@ set(TARGET_PUBLIC_HEADERS libc.include.fenv libc.include.float libc.include.inttypes + libc.include.libgen libc.include.limits libc.include.link libc.include.locale diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt index 8046679785e68..5ace968a739c8 100644 --- a/libc/config/linux/x86_64/entrypoints.txt +++ b/libc/config/linux/x86_64/entrypoints.txt @@ -1078,6 +1078,7 @@ list(APPEND TARGET_LIBM_ENTRYPOINTS libc.src.math.setpayloadbf16 libc.src.math.setpayloadsigbf16 libc.src.math.sqrtbf16 + libc.src.math.tanbf16 libc.src.math.truncbf16 libc.src.math.totalorderbf16 libc.src.math.totalordermagbf16 @@ -1372,6 +1373,7 @@ if(LLVM_LIBC_FULL_BUILD) libc.src.stdlib.exit libc.src.stdlib.getenv libc.src.stdlib.setenv + libc.src.stdlib.unsetenv libc.src.stdlib.mbstowcs libc.src.stdlib.mbtowc libc.src.stdlib.mblen diff --git a/libc/config/linux/x86_64/headers.txt b/libc/config/linux/x86_64/headers.txt index 8b88ded158ebe..6cd16ecdae3e3 100644 --- a/libc/config/linux/x86_64/headers.txt +++ b/libc/config/linux/x86_64/headers.txt @@ -15,6 +15,7 @@ set(TARGET_PUBLIC_HEADERS libc.include.fenv libc.include.float libc.include.inttypes + libc.include.libgen libc.include.limits libc.include.link libc.include.locale diff --git a/libc/config/windows/entrypoints.txt b/libc/config/windows/entrypoints.txt index d7f66dc58e4db..3c68290675b11 100644 --- a/libc/config/windows/entrypoints.txt +++ b/libc/config/windows/entrypoints.txt @@ -393,6 +393,7 @@ list(APPEND TARGET_LIBM_ENTRYPOINTS libc.src.math.setpayloadbf16 libc.src.math.setpayloadsigbf16 libc.src.math.sqrtbf16 + libc.src.math.tanbf16 libc.src.math.truncbf16 libc.src.math.totalorderbf16 libc.src.math.totalordermagbf16 diff --git a/libc/docs/dev/builtin_compatibility.rst b/libc/docs/dev/builtin_compatibility.rst new file mode 100644 index 0000000000000..4ea9cc9ba1115 --- /dev/null +++ b/libc/docs/dev/builtin_compatibility.rst @@ -0,0 +1,351 @@ +.. _builtin_compatibility: + +============================== +GCC Compatibility of Builtins +============================== + +LLVM-libc is written with Clang as the reference compiler but is expected to +build under GCC as well. Many headers reach for compiler intrinsics +(``__builtin_*``) for fast paths and for IEEE-754 semantics. Not every +``__builtin_*`` exists in every compiler. a large family is Clang-only, +and several others were added in specific GCC releases. This page records +which builtins the libc code base references today and the minimum GCC +basepoint that ships each one. + ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| Builtin | gcc-5 | gcc-6 | gcc-7 | gcc-8 | gcc-9 | gcc-10 | gcc-11 | gcc-12 | gcc-13 | gcc-14 | gcc-15 | gcc-16 | gcc-17 | ++========================================+=========+=========+=========+=========+=========+=========+=========+=========+=========+=========+=========+=========+=========+ +| ``__builtin_aarch64_get_fpcr`` | | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_aarch64_get_fpsr`` | | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_aarch64_set_fpcr`` | | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_aarch64_set_fpsr`` | | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_aarch64_wsr64`` | | | | | | | | | | | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_abs`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_addc`` | | | | | | | | | | | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_addcb`` | | | | | | | | | | | | | | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_addcl`` | | | | | | | | | | | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_addcll`` | | | | | | | | | | | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_addcs`` | | | | | | | | | | | | | | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_add_overflow`` | | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_addressof`` | | | | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_align_down`` | | | | | | | | | | | | | | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_align_up`` | | | | | | | | | | | | | | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_alloca`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_amdgcn_ldexp`` | | | | | | | | | | | | | | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_amdgcn_ldexpf`` | | | | | | | | | | | | | | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_amdgcn_s_sendmsg`` | | | | | | | | | | | | | | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_amdgcn_s_sleep`` | | | | | | | | | | | | | | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_amdgcn_workitem_id_x`` | | | | | | | | | | | | | | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_arm_get_fpscr`` | | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_arm_isb`` | | | | | | | | | | | | | | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_arm_set_fpscr`` | | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_arm_wsr64`` | | | | | | | | | | | | | | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_assume`` | | | | | | | | | | | | | | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_assume_aligned`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_bcmp`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_bit_cast`` | | | | | | | | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_bswap16`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_bswap32`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_bswap64`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_ceil`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_ceilf`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_clear_padding`` | | | | | | | | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_clz`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_clzg`` | | | | | | | | | | | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_clzl`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_clzll`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_clzs`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_complex`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_convertvector`` | | | | | | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_copysign`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_copysignf`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_copysignf16`` | | | | | | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_ctz`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_ctzg`` | | | | | | | | | | | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_ctzl`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_ctzll`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_ctzs`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_elementwise_abs`` | | | | | | | | | | | | | | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_elementwise_canonicalize`` | | | | | | | | | | | | | | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_elementwise_ceil`` | | | | | | | | | | | | | | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_elementwise_copysign`` | | | | | | | | | | | | | | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_elementwise_floor`` | | | | | | | | | | | | | | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_elementwise_fma`` | | | | | | | | | | | | | | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_elementwise_fmod`` | | | | | | | | | | | | | | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_elementwise_max`` | | | | | | | | | | | | | | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_elementwise_min`` | | | | | | | | | | | | | | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_elementwise_nearbyint`` | | | | | | | | | | | | | | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_elementwise_rint`` | | | | | | | | | | | | | | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_elementwise_round`` | | | | | | | | | | | | | | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_elementwise_roundeven`` | | | | | | | | | | | | | | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_elementwise_sqrt`` | | | | | | | | | | | | | | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_elementwise_trunc`` | | | | | | | | | | | | | | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_expect`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_fabs`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_fabsf`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_fabsf16`` | | | | | | | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_floor`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_floorf`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_flt_rounds`` | | | | | | | | | | | | | | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_fma`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_fmaf`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_fmax`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_fmaxf`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_fmaxf16`` | | | | | | | | | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_fmin`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_fminf`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_fminf16`` | | | | | | | | | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_fmod`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_fmodf`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_fpclassify`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_frame_address`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_frexp`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_frexpf`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_func`` | | | | | | | | | | | | | | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_huge_val`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_huge_valf`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_ia32_ldmxcsr`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_ia32_pause`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_ia32_stmxcsr`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_inff`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_is_aligned`` | | | | | | | | | | | | | | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_is_constant_evaluated`` | | | | | | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_isfinite`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_isinf`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_isnan`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_isnormal`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_launder`` | | | | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_ldexp`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_ldexpf`` | | | | | | | | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_masked_compress_store`` | | | | | | | | | | | | | | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_masked_expand_load`` | | | | | | | | | | | | | | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_masked_gather`` | | | | | | | | | | | | | | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_masked_load`` | | | | | | | | | | | | | | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_masked_scatter`` | | | | | | | | | | | | | | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_masked_store`` | | | | | | | | | | | | | | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_memcmp`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_memcmp_inline`` | | | | | | | | | | | | | | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_memcpy`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_memcpy_inline`` | | | | | | | | | | | | | | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_memmove`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_memset`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_memset_inline`` | | | | | | | | | | | | | | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_mul_overflow`` | | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_nanf`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_nans`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_nansf`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_nansl`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_nearbyint`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_nearbyintf`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_nondeterministic_value`` | | | | | | | | | | | | | | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_nontemporal_store`` | | | | | | | | | | | | | | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_offsetof`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_popcount`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_popcountg`` | | | | | | | | | | | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_popcountl`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_popcountll`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_prefetch`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_readcyclecounter`` | | | | | | | | | | | | | | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_readsteadycounter`` | | | | | | | | | | | | | | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_reduce_add`` | | | | | | | | | | | | | | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_reduce_and`` | | | | | | | | | | | | | | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_reduce_max`` | | | | | | | | | | | | | | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_reduce_min`` | | | | | | | | | | | | | | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_reduce_mul`` | | | | | | | | | | | | | | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_reduce_or`` | | | | | | | | | | | | | | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_reduce_xor`` | | | | | | | | | | | | | | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_remainder`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_remainderf`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_return_address`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_rint`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_rintf`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_round`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_roundeven`` | | | | | | | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_roundevenf`` | | | | | | | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_roundf`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_sadd_overflow`` | | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_shufflevector`` | | | | | | | | | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_signbit`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_snprintf`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_sqrt`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_sqrtf`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_strlen`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_subc`` | | | | | | | | | | | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_subcb`` | | | | | | | | | | | | | | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_subcl`` | | | | | | | | | | | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_subcll`` | | | | | | | | | | | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_subcs`` | | | | | | | | | | | | | | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_sub_overflow`` | | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_trap`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_trunc`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_truncf`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_unreachable`` | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__builtin_vectorelements`` | | | | | | | | | | | | | | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ +| ``__has_builtin`` | | | | | | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | ++----------------------------------------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+---------+ diff --git a/libc/docs/dev/index.rst b/libc/docs/dev/index.rst index e6463712e3859..83d0956b7f1a9 100644 --- a/libc/docs/dev/index.rst +++ b/libc/docs/dev/index.rst @@ -20,5 +20,6 @@ Navigate to the links below for information on the respective topics: implementation_standard undefined_behavior printf_behavior + builtin_compatibility syscall_wrapper_refactor modular_format diff --git a/libc/docs/headers/math/index.rst b/libc/docs/headers/math/index.rst index c2ebc5031cef5..8f8f381054002 100644 --- a/libc/docs/headers/math/index.rst +++ b/libc/docs/headers/math/index.rst @@ -353,7 +353,7 @@ Higher Math Functions +-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+------------------------+----------------------------+ | sqrt | |check| | |check| | |check| | |check| | |check| | |check| | 7.12.7.10 | F.10.4.10 | +-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+------------------------+----------------------------+ -| tan | |check| | |check| | | |check| | | | 7.12.4.7 | F.10.1.7 | +| tan | |check| | |check| | | |check| | | |check| | 7.12.4.7 | F.10.1.7 | +-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+------------------------+----------------------------+ | tanh | |check| | | | |check| | | | 7.12.5.6 | F.10.2.6 | +-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+------------------------+----------------------------+ diff --git a/libc/include/stdlib.yaml b/libc/include/stdlib.yaml index bf77d5d850ea0..93f61d541b073 100644 --- a/libc/include/stdlib.yaml +++ b/libc/include/stdlib.yaml @@ -376,6 +376,12 @@ functions: return_type: int arguments: - type: const char * + - name: unsetenv + standards: + - posix + return_type: int + arguments: + - type: const char * - name: wctomb standards: - stdc diff --git a/libc/shared/math.h b/libc/shared/math.h index f4b28e3aa139d..2e8a574e4d042 100644 --- a/libc/shared/math.h +++ b/libc/shared/math.h @@ -474,6 +474,7 @@ #include "math/sqrtf16.h" #include "math/sqrtl.h" #include "math/tan.h" +#include "math/tanbf16.h" #include "math/tanf.h" #include "math/tanf16.h" #include "math/tanhf.h" diff --git a/libc/shared/math/tanbf16.h b/libc/shared/math/tanbf16.h new file mode 100644 index 0000000000000..24006da13b4dd --- /dev/null +++ b/libc/shared/math/tanbf16.h @@ -0,0 +1,23 @@ +//===-- Shared tanbf16 function ---------------------------------*- 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_LIBC_SHARED_MATH_TANBF16_H +#define LLVM_LIBC_SHARED_MATH_TANBF16_H + +#include "shared/libc_common.h" +#include "src/__support/math/tanbf16.h" + +namespace LIBC_NAMESPACE_DECL { +namespace shared { + +using math::tanbf16; + +} // namespace shared +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SHARED_MATH_TANBF16_H diff --git a/libc/src/CMakeLists.txt b/libc/src/CMakeLists.txt index 56085c9632f59..62aa164b35ee7 100644 --- a/libc/src/CMakeLists.txt +++ b/libc/src/CMakeLists.txt @@ -14,11 +14,13 @@ add_subdirectory(netinet) add_subdirectory(stdbit) add_subdirectory(stdfix) add_subdirectory(stdio) +# unistd must be added before stdlib because stdlib's environ_internal +# target conditionally depends on unistd's environ target. +add_subdirectory(unistd) add_subdirectory(stdlib) add_subdirectory(string) add_subdirectory(strings) add_subdirectory(time) -add_subdirectory(unistd) add_subdirectory(wchar) add_subdirectory(wctype) diff --git a/libc/src/__support/math/CMakeLists.txt b/libc/src/__support/math/CMakeLists.txt index b57e82a036665..a57086a31dc03 100644 --- a/libc/src/__support/math/CMakeLists.txt +++ b/libc/src/__support/math/CMakeLists.txt @@ -5374,6 +5374,7 @@ add_header_library( libc.src.__support.uint128 libc.include.llvm-libc-types.float128 ) + add_header_library( sqrtl HDRS @@ -5399,6 +5400,22 @@ add_header_library( libc.src.__support.macros.optimization ) +add_header_library( + tanbf16 + HDRS + tanbf16.h + DEPENDS + .sincosf_utils + libc.hdr.errno_macros + libc.hdr.fenv_macros + libc.src.__support.FPUtil.cast + libc.src.__support.FPUtil.fenv_impl + libc.src.__support.FPUtil.fp_bits + libc.src.__support.FPUtil.multiply_add + libc.src.__support.macros.optimization + libc.src.__support.FPUtil.bfloat16 +) + add_header_library( tanf HDRS diff --git a/libc/src/__support/math/tanbf16.h b/libc/src/__support/math/tanbf16.h new file mode 100644 index 0000000000000..3dae149a4a643 --- /dev/null +++ b/libc/src/__support/math/tanbf16.h @@ -0,0 +1,83 @@ +//===-- Implementation of tanbf16 function --------------------------------===// +// +// 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_LIBC_SRC___SUPPORT_MATH_TANBF16_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_TANBF16_H + +#include "hdr/errno_macros.h" +#include "hdr/fenv_macros.h" +#include "sincosf_utils.h" +#include "src/__support/FPUtil/FEnvImpl.h" +#include "src/__support/FPUtil/FPBits.h" +#include "src/__support/FPUtil/bfloat16.h" +#include "src/__support/FPUtil/cast.h" +#include "src/__support/FPUtil/multiply_add.h" +#include "src/__support/macros/optimization.h" + +namespace LIBC_NAMESPACE_DECL { + +namespace math { + +LIBC_INLINE bfloat16 tanbf16(bfloat16 x) { + + using FPBits = fputil::FPBits; + FPBits xbits(x); + + uint16_t x_u = xbits.uintval(); + uint16_t x_abs = x_u & 0x7fff; + float xf = x; + + // NaN or -/+ INF + if (x_abs >= 0x7F80) { + // NaN + if (xbits.is_nan()) { + if (xbits.is_signaling_nan()) { + fputil::raise_except_if_required(FE_INVALID); + return FPBits::quiet_nan().get_val(); + } + return x; + } + //|x| is +/- INF + fputil::set_errno_if_required(EDOM); + fputil::raise_except_if_required(FE_INVALID); + return x + FPBits::quiet_nan().get_val(); + } + + // Through Exhaustive testing - + // The last value where tan(x) ~ x is 0x3db8 + if (LIBC_UNLIKELY(x_abs <= 0x3db8)) { + // |x| = {0} + if (LIBC_UNLIKELY(x_abs == 0)) { + return x; + } + return fputil::cast(fputil::multiply_add(xf, 0x1.0p-11f, xf)); + } + + double xd = static_cast(xf); + uint32_t x_abs_f = fputil::FPBits(xf).uintval() & 0x7fffffff; + double sin_k, cos_k, sin_y, cosm1_y; + + // TODO: Use bfloat16 version for inv_trigf_utils_internals after they are + // available + // Tracking issue : + // https://github.com/llvm/llvm-project/issues/202079 + sincosf_utils_internal::sincosf_eval(xd, x_abs_f, sin_k, cos_k, sin_y, + cosm1_y); + + return fputil::cast( + fputil::multiply_add(sin_y, cos_k, + fputil::multiply_add(cosm1_y, sin_k, sin_k)) / + fputil::multiply_add(sin_y, -sin_k, + fputil::multiply_add(cosm1_y, cos_k, cos_k))); +} + +} // namespace math + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_TANBF16_H diff --git a/libc/src/math/CMakeLists.txt b/libc/src/math/CMakeLists.txt index dcfc8183d716a..4823ceefd7475 100644 --- a/libc/src/math/CMakeLists.txt +++ b/libc/src/math/CMakeLists.txt @@ -587,6 +587,7 @@ add_math_entrypoint_object(sqrtf128) add_math_entrypoint_object(sqrtbf16) add_math_entrypoint_object(tan) +add_math_entrypoint_object(tanbf16) add_math_entrypoint_object(tanf) add_math_entrypoint_object(tanf16) diff --git a/libc/src/math/generic/CMakeLists.txt b/libc/src/math/generic/CMakeLists.txt index 770da1404a95b..5a5bd84213a55 100644 --- a/libc/src/math/generic/CMakeLists.txt +++ b/libc/src/math/generic/CMakeLists.txt @@ -415,6 +415,16 @@ add_entrypoint_object( libc.src.errno.errno ) +add_entrypoint_object( + tanbf16 + SRCS + tanbf16.cpp + HDRS + ../tanbf16.h + DEPENDS + libc.src.__support.math.tanbf16 +) + add_entrypoint_object( tanf SRCS diff --git a/libc/src/math/generic/tanbf16.cpp b/libc/src/math/generic/tanbf16.cpp new file mode 100644 index 0000000000000..990272fdcd677 --- /dev/null +++ b/libc/src/math/generic/tanbf16.cpp @@ -0,0 +1,16 @@ +//===-- Implementation for tanbf16(x) function ----------------------------===// +// +// 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 "src/math/tanbf16.h" +#include "src/__support/math/tanbf16.h" + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(bfloat16, tanbf16, (bfloat16 x)) { return math::tanbf16(x); } + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/math/tanbf16.h b/libc/src/math/tanbf16.h new file mode 100644 index 0000000000000..034167d3bb9c2 --- /dev/null +++ b/libc/src/math/tanbf16.h @@ -0,0 +1,21 @@ +//===-- Implementation header for tanbf16 -----------------------*- 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_LIBC_SRC_MATH_TANBF16_H +#define LLVM_LIBC_SRC_MATH_TANBF16_H + +#include "src/__support/macros/config.h" +#include "src/__support/macros/properties/types.h" + +namespace LIBC_NAMESPACE_DECL { + +bfloat16 tanbf16(bfloat16 x); + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_MATH_TANBF16_H diff --git a/libc/src/stdlib/CMakeLists.txt b/libc/src/stdlib/CMakeLists.txt index 4593288881c7d..1e26588ad7305 100644 --- a/libc/src/stdlib/CMakeLists.txt +++ b/libc/src/stdlib/CMakeLists.txt @@ -77,6 +77,24 @@ if((${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU") AND "-fdisable-tree-waccess3") endif() +set(environ_internal_deps + libc.config.app_h + libc.hdr.types.size_t + libc.src.__support.alloc_checker + libc.src.__support.CPP.new + libc.src.__support.CPP.optional + libc.src.__support.CPP.string_view + libc.src.__support.macros.attributes + libc.src.__support.macros.config + libc.src.string.memory_utils.inline_memcpy +) +set(environ_internal_compile_options ${environ_internal_gcc12_workaround}) + +if("libc.src.unistd.environ" IN_LIST TARGET_LLVMLIBC_ENTRYPOINTS) + list(APPEND environ_internal_deps libc.src.unistd.environ) + list(APPEND environ_internal_compile_options "-DLIBC_COPT_SUPPORT_ENVIRON") +endif() + add_object_library( environ_internal SRCS @@ -84,16 +102,9 @@ add_object_library( HDRS environ_internal.h COMPILE_OPTIONS - ${environ_internal_gcc12_workaround} + ${environ_internal_compile_options} DEPENDS - libc.config.app_h - libc.hdr.types.size_t - libc.src.__support.CPP.new - libc.src.__support.CPP.optional - libc.src.__support.CPP.string_view - libc.src.__support.macros.attributes - libc.src.__support.macros.config - libc.src.string.memory_utils.inline_memcpy + ${environ_internal_deps} ) add_entrypoint_object( @@ -677,6 +688,13 @@ add_entrypoint_object( .${LIBC_TARGET_OS}.setenv ) +add_entrypoint_object( + unsetenv + ALIAS + DEPENDS + .${LIBC_TARGET_OS}.unsetenv +) + if(LIBC_TARGET_OS_IS_BAREMETAL OR LIBC_TARGET_OS_IS_GPU) add_entrypoint_object( malloc diff --git a/libc/src/stdlib/environ_internal.cpp b/libc/src/stdlib/environ_internal.cpp index e9da17d028575..d7ef081e7e2b1 100644 --- a/libc/src/stdlib/environ_internal.cpp +++ b/libc/src/stdlib/environ_internal.cpp @@ -18,6 +18,9 @@ #include "src/__support/alloc-checker.h" #include "src/__support/macros/config.h" #include "src/string/memory_utils/inline_memcpy.h" +#ifdef LIBC_COPT_SUPPORT_ENVIRON +#include "src/unistd/environ.h" +#endif namespace LIBC_NAMESPACE_DECL { namespace internal { @@ -142,6 +145,9 @@ bool EnvironmentManager::ensure_capacity(size_t needed) { // Update the global environ pointer. app.env_ptr = reinterpret_cast(storage); +#ifdef LIBC_COPT_SUPPORT_ENVIRON + environ = storage; +#endif return true; } @@ -168,6 +174,9 @@ bool EnvironmentManager::ensure_capacity(size_t needed) { // Update the global environ pointer. app.env_ptr = reinterpret_cast(storage); +#ifdef LIBC_COPT_SUPPORT_ENVIRON + environ = storage; +#endif return true; } @@ -221,5 +230,40 @@ int EnvironmentManager::set(cpp::string_view name, cpp::string_view value, return 0; } +int EnvironmentManager::unset(cpp::string_view name) { + cpp::optional idx = find_var(name); + if (!idx) + return 0; // Variable not found; POSIX defines this as success. + + // Transition to managed storage so we can modify the array and track + // ownership correctly. + if (!ensure_capacity(count)) + return -1; + + char **env_array = get_array(); + + // Loop to remove all instances of the variable (e.g. duplicates from execve). + while (idx) { + size_t i = *idx; + if (ownership[i].can_free()) + delete[] env_array[i]; + + // Compact: shift remaining entries left to fill the gap. + // Shifting elements preserves the order of environment variables, which is + // desirable to maintain consistency with getenv resolution order and + // typical environ iteration behavior. + for (size_t j = i; j < count - 1; j++) { + env_array[j] = env_array[j + 1]; + ownership[j] = ownership[j + 1]; + } + count--; + env_array[count] = nullptr; + + idx = find_var(name); + } + + return 0; +} + } // namespace internal } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdlib/environ_internal.h b/libc/src/stdlib/environ_internal.h index d902354f421cf..f16d841779734 100644 --- a/libc/src/stdlib/environ_internal.h +++ b/libc/src/stdlib/environ_internal.h @@ -129,6 +129,11 @@ class EnvironmentManager { // Returns 0 on success, -1 on allocation failure (caller should set // errno to ENOMEM). int set(cpp::string_view name, cpp::string_view value, bool overwrite); + + // Remove a variable by name. Frees the string if we own it, then + // compacts the array. Returns 0 on success (including if the variable + // was not found), -1 on allocation failure during array transition. + int unset(cpp::string_view name); }; } // namespace internal diff --git a/libc/src/stdlib/linux/CMakeLists.txt b/libc/src/stdlib/linux/CMakeLists.txt index aedcd3f11bf38..06af6f046afa1 100644 --- a/libc/src/stdlib/linux/CMakeLists.txt +++ b/libc/src/stdlib/linux/CMakeLists.txt @@ -23,3 +23,18 @@ add_entrypoint_object( libc.src.__support.macros.null_check libc.src.stdlib.environ_internal ) + +add_entrypoint_object( + unsetenv + SRCS + unsetenv.cpp + HDRS + ../unsetenv.h + DEPENDS + libc.src.__support.CPP.string_view + libc.src.__support.common + libc.src.__support.libc_errno + libc.src.__support.macros.config + libc.src.__support.macros.null_check + libc.src.stdlib.environ_internal +) diff --git a/libc/src/stdlib/linux/unsetenv.cpp b/libc/src/stdlib/linux/unsetenv.cpp new file mode 100644 index 0000000000000..538242ed29fca --- /dev/null +++ b/libc/src/stdlib/linux/unsetenv.cpp @@ -0,0 +1,43 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Implementation of the POSIX unsetenv function. +/// +//===----------------------------------------------------------------------===// + +#include "src/stdlib/unsetenv.h" +#include "src/__support/CPP/string_view.h" +#include "src/__support/common.h" +#include "src/__support/libc_errno.h" +#include "src/__support/macros/config.h" +#include "src/__support/macros/null_check.h" +#include "src/stdlib/environ_internal.h" + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(int, unsetenv, (const char *name)) { + LIBC_CRASH_ON_NULLPTR(name); + + cpp::string_view name_view(name); + + // POSIX: name must not be empty or contain '='. + if (name_view.empty() || + name_view.find_first_of('=') != cpp::string_view::npos) { + libc_errno = EINVAL; + return -1; + } + + int result = internal::EnvironmentManager::get_instance().unset(name_view); + if (result != 0) + libc_errno = ENOMEM; + + return result; +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdlib/unsetenv.h b/libc/src/stdlib/unsetenv.h new file mode 100644 index 0000000000000..b705d1b481aef --- /dev/null +++ b/libc/src/stdlib/unsetenv.h @@ -0,0 +1,25 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Declaration of the POSIX unsetenv function. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_STDLIB_UNSETENV_H +#define LLVM_LIBC_SRC_STDLIB_UNSETENV_H + +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +int unsetenv(const char *name); + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_STDLIB_UNSETENV_H diff --git a/libc/src/wchar/wcslcat.cpp b/libc/src/wchar/wcslcat.cpp index eb318e066f7a0..456aac4543e41 100644 --- a/libc/src/wchar/wcslcat.cpp +++ b/libc/src/wchar/wcslcat.cpp @@ -21,8 +21,10 @@ LLVM_LIBC_FUNCTION(size_t, wcslcat, size_t dstsize)) { const size_t dstlen = internal::string_length(dst); const size_t srclen = internal::string_length(src); + if (dstlen >= dstsize) + return dstsize + srclen; int limit = static_cast(dstsize - dstlen - 1); - size_t returnval = (dstsize < dstlen ? dstsize : dstlen) + srclen; + size_t returnval = dstlen + srclen; if (limit < 0) return returnval; int i = 0; diff --git a/libc/src/wchar/wcsncat.cpp b/libc/src/wchar/wcsncat.cpp index 62595b4b5418c..985fb5f1cbace 100644 --- a/libc/src/wchar/wcsncat.cpp +++ b/libc/src/wchar/wcsncat.cpp @@ -21,7 +21,7 @@ LLVM_LIBC_FUNCTION(wchar_t *, wcsncat, size_t n)) { size_t size = internal::string_length(s1); size_t i = 0; - for (; s2[i] && i < n; ++i) + for (; i < n && s2[i]; ++i) s1[size + i] = s2[i]; // Appending null character to the end of the result. s1[size + i] = L'\0'; diff --git a/libc/test/integration/src/stdlib/CMakeLists.txt b/libc/test/integration/src/stdlib/CMakeLists.txt index 2e0389f9a60d3..789f9aded9570 100644 --- a/libc/test/integration/src/stdlib/CMakeLists.txt +++ b/libc/test/integration/src/stdlib/CMakeLists.txt @@ -30,6 +30,22 @@ if(${LIBC_TARGET_OS} STREQUAL "linux") libc.src.string.strcmp ) + add_integration_test( + unsetenv_test + SUITE + stdlib-integration-tests + SRCS + unsetenv_test.cpp + DEPENDS + libc.src.__support.alloc_checker + libc.src.stdlib.getenv + libc.src.stdlib.setenv + libc.src.stdlib.unsetenv + libc.src.string.memory_utils.inline_memcpy + libc.src.string.strcmp + libc.src.unistd.environ + ) + add_integration_test( abort_test SUITE diff --git a/libc/test/integration/src/stdlib/unsetenv_test.cpp b/libc/test/integration/src/stdlib/unsetenv_test.cpp new file mode 100644 index 0000000000000..53341940702ed --- /dev/null +++ b/libc/test/integration/src/stdlib/unsetenv_test.cpp @@ -0,0 +1,176 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// Integration tests for unsetenv. +/// +//===----------------------------------------------------------------------===// + +#include "src/__support/alloc-checker.h" +#include "src/stdlib/environ_internal.h" +#include "src/stdlib/getenv.h" +#include "src/stdlib/setenv.h" +#include "src/stdlib/unsetenv.h" +#include "src/string/memory_utils/inline_memcpy.h" +#include "src/string/strcmp.h" +#include "src/unistd/environ.h" + +#include "test/IntegrationTest/test.h" + +#include + +namespace LIBC_NAMESPACE { + +TEST_MAIN([[maybe_unused]] int argc, [[maybe_unused]] char **argv, + [[maybe_unused]] char **envp) { + // Test: Remove a variable set by setenv + { + ASSERT_EQ(setenv("UNSET_VAR", "value", 1), 0); + ASSERT_TRUE(getenv("UNSET_VAR") != nullptr); + + ASSERT_EQ(unsetenv("UNSET_VAR"), 0); + ASSERT_TRUE(getenv("UNSET_VAR") == nullptr); + } + + // Test: Unset non-existent variable succeeds + { + ASSERT_EQ(unsetenv("DOES_NOT_EXIST"), 0); + } + + // Test: Empty name sets errno to EINVAL + { + errno = 0; + ASSERT_EQ(unsetenv(""), -1); + ASSERT_ERRNO_EQ(EINVAL); + } + + // Test: Name with '=' sets errno to EINVAL + { + errno = 0; + ASSERT_EQ(unsetenv("BAD=NAME"), -1); + ASSERT_ERRNO_EQ(EINVAL); + } + + // Test: Unset then re-set + { + ASSERT_EQ(setenv("REUSE_VAR", "first", 1), 0); + ASSERT_EQ(strcmp(getenv("REUSE_VAR"), "first"), 0); + + ASSERT_EQ(unsetenv("REUSE_VAR"), 0); + ASSERT_TRUE(getenv("REUSE_VAR") == nullptr); + + ASSERT_EQ(setenv("REUSE_VAR", "second", 1), 0); + ASSERT_EQ(strcmp(getenv("REUSE_VAR"), "second"), 0); + } + + // Test: Unset multiple variables + { + ASSERT_EQ(setenv("MULTI_A", "a", 1), 0); + ASSERT_EQ(setenv("MULTI_B", "b", 1), 0); + ASSERT_EQ(setenv("MULTI_C", "c", 1), 0); + + ASSERT_EQ(unsetenv("MULTI_B"), 0); + + ASSERT_TRUE(getenv("MULTI_A") != nullptr); + ASSERT_TRUE(getenv("MULTI_B") == nullptr); + ASSERT_TRUE(getenv("MULTI_C") != nullptr); + + ASSERT_EQ(strcmp(getenv("MULTI_A"), "a"), 0); + ASSERT_EQ(strcmp(getenv("MULTI_C"), "c"), 0); + } + + // Test: Unset same variable twice is harmless + { + ASSERT_EQ(setenv("DOUBLE_UNSET", "val", 1), 0); + ASSERT_EQ(unsetenv("DOUBLE_UNSET"), 0); + ASSERT_EQ(unsetenv("DOUBLE_UNSET"), 0); + ASSERT_TRUE(getenv("DOUBLE_UNSET") == nullptr); + } + + // Test: environ is updated and does NOT contain the variable + { + ASSERT_EQ(setenv("ENV_CHECK", "val", 1), 0); + // Verify it is in environ + bool found = false; + for (char **env = environ; *env != nullptr; ++env) { + if (strcmp(*env, "ENV_CHECK=val") == 0) { + found = true; + break; + } + } + ASSERT_TRUE(found); + + // Now unset it + ASSERT_EQ(unsetenv("ENV_CHECK"), 0); + + // Verify it is NOT in environ + found = false; + for (char **env = environ; *env != nullptr; ++env) { + bool match = true; + const char *prefix = "ENV_CHECK="; + for (size_t i = 0; i < 10; ++i) { + if ((*env)[i] == '\0' || (*env)[i] != prefix[i]) { + match = false; + break; + } + } + if (match) { + found = true; + break; + } + } + ASSERT_FALSE(found); + } + + // Test: Unset removes all duplicate instances of a variable + { + ASSERT_EQ(setenv("DUP_VAL1", "1", 1), 0); + ASSERT_EQ(setenv("DUP_VAL2", "2", 1), 0); + + AllocChecker ac; + char *d1 = new (ac) char[14]; + ASSERT_TRUE(ac); + const char *s1 = "DUP_VAR=first"; + inline_memcpy(d1, s1, 14); + + char *d2 = new (ac) char[15]; + ASSERT_TRUE(ac); + const char *s2 = "DUP_VAR=second"; + inline_memcpy(d2, s2, 15); + + internal::EnvironmentManager &mgr = + internal::EnvironmentManager::get_instance(); + char **env_array = mgr.begin(); + size_t count = mgr.size(); + + size_t idx1 = count; + size_t idx2 = count; + for (size_t i = 0; i < count; ++i) { + cpp::string_view curr(env_array[i]); + if (curr.starts_with("DUP_VAL1=")) + idx1 = i; + if (curr.starts_with("DUP_VAL2=")) + idx2 = i; + } + ASSERT_TRUE(idx1 < count); + ASSERT_TRUE(idx2 < count); + + delete[] env_array[idx1]; + delete[] env_array[idx2]; + + env_array[idx1] = d1; + env_array[idx2] = d2; + + ASSERT_EQ(unsetenv("DUP_VAR"), 0); + ASSERT_TRUE(getenv("DUP_VAR") == nullptr); + } + + return 0; +} + +} // namespace LIBC_NAMESPACE diff --git a/libc/test/shared/CMakeLists.txt b/libc/test/shared/CMakeLists.txt index 17e1570f1b19a..9b990dd5a5c84 100644 --- a/libc/test/shared/CMakeLists.txt +++ b/libc/test/shared/CMakeLists.txt @@ -479,6 +479,7 @@ add_fp_unittest( libc.src.__support.math.sqrtf libc.src.__support.math.sqrtl libc.src.__support.math.tan + libc.src.__support.math.tanbf16 libc.src.__support.math.tanf libc.src.__support.math.tanf16 libc.src.__support.math.tanhf diff --git a/libc/test/shared/shared_math_test.cpp b/libc/test/shared/shared_math_test.cpp index e26532773c69b..5877729ae7931 100644 --- a/libc/test/shared/shared_math_test.cpp +++ b/libc/test/shared/shared_math_test.cpp @@ -893,5 +893,6 @@ TEST(LlvmLibcSharedMathTest, AllBFloat16) { EXPECT_FP_EQ(bfloat16(0.0), LIBC_NAMESPACE::shared::roundbf16(bfloat16(0.0))); EXPECT_FP_EQ(bfloat16(0.0), LIBC_NAMESPACE::shared::roundevenbf16(bfloat16(0.0))); + EXPECT_FP_EQ(bfloat16(0.0), LIBC_NAMESPACE::shared::tanbf16(bfloat16(0.0))); EXPECT_FP_EQ(bfloat16(0.0), LIBC_NAMESPACE::shared::truncbf16(bfloat16(0.0))); } diff --git a/libc/test/src/math/CMakeLists.txt b/libc/test/src/math/CMakeLists.txt index 1e27724fe0a60..31f6468e01110 100644 --- a/libc/test/src/math/CMakeLists.txt +++ b/libc/test/src/math/CMakeLists.txt @@ -201,6 +201,19 @@ add_fp_unittest( libc.src.__support.FPUtil.fp_bits ) +add_fp_unittest( + tanbf16_test + NEED_MPFR + SUITE + libc-math-unittests + SRCS + tanbf16_test.cpp + DEPENDS + libc.src.math.tanbf16 + libc.src.__support.FPUtil.fp_bits + libc.src.__support.FPUtil.bfloat16 +) + add_fp_unittest( tanf_test NEED_MPFR diff --git a/libc/test/src/math/smoke/CMakeLists.txt b/libc/test/src/math/smoke/CMakeLists.txt index b763cdb43b31c..73d2265322c4d 100644 --- a/libc/test/src/math/smoke/CMakeLists.txt +++ b/libc/test/src/math/smoke/CMakeLists.txt @@ -110,6 +110,19 @@ add_fp_unittest( libc.src.__support.FPUtil.fp_bits ) +add_fp_unittest( + tanbf16_test + SUITE + libc-math-smoke-tests + SRCS + tanbf16_test.cpp + DEPENDS + libc.hdr.errno_macros + libc.src.math.tanbf16 + libc.hdr.fenv_macros + libc.src.__support.FPUtil.bfloat16 +) + add_fp_unittest( tanf_test SUITE diff --git a/libc/test/src/math/smoke/tanbf16_test.cpp b/libc/test/src/math/smoke/tanbf16_test.cpp new file mode 100644 index 0000000000000..4e760b4a747e4 --- /dev/null +++ b/libc/test/src/math/smoke/tanbf16_test.cpp @@ -0,0 +1,41 @@ +//===-- Unittests for tanbf16 ---------------------------------------------===// +// +// +// 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 "hdr/errno_macros.h" +#include "src/__support/FPUtil/bfloat16.h" +#include "src/math/tanbf16.h" +#include "test/UnitTest/FEnvSafeTest.h" +#include "test/UnitTest/FPMatcher.h" +#include "test/UnitTest/Test.h" + +class LlvmLibcTanBf16Test : public LIBC_NAMESPACE::testing::FEnvSafeTest { + DECLARE_SPECIAL_CONSTANTS(bfloat16) +public: + void test_special_numbers() { + EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::tanbf16(aNaN)); + EXPECT_MATH_ERRNO(0); + + EXPECT_FP_EQ_WITH_EXCEPTION_ALL_ROUNDING( + aNaN, LIBC_NAMESPACE::tanbf16(sNaN), FE_INVALID); + EXPECT_MATH_ERRNO(0); + + EXPECT_FP_EQ_ALL_ROUNDING(zero, LIBC_NAMESPACE::tanbf16(zero)); + EXPECT_MATH_ERRNO(0); + + EXPECT_FP_EQ_ALL_ROUNDING(neg_zero, LIBC_NAMESPACE::tanbf16(neg_zero)); + EXPECT_MATH_ERRNO(0); + + EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::tanbf16(inf)); + EXPECT_MATH_ERRNO(EDOM); + + EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::tanbf16(neg_inf)); + EXPECT_MATH_ERRNO(EDOM); + } +}; +TEST_F(LlvmLibcTanBf16Test, SpecialNumbers) { test_special_numbers(); } diff --git a/libc/test/src/math/tanbf16_test.cpp b/libc/test/src/math/tanbf16_test.cpp new file mode 100644 index 0000000000000..848e07debe18d --- /dev/null +++ b/libc/test/src/math/tanbf16_test.cpp @@ -0,0 +1,43 @@ +//===-- Exhaustive test for tanbf16 ---------------------------------------===// +// +// 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 "src/__support/FPUtil/bfloat16.h" +#include "src/math/tanbf16.h" +#include "test/UnitTest/FPMatcher.h" +#include "test/UnitTest/Test.h" +#include "utils/MPFRWrapper/MPFRUtils.h" + +using LlvmLibcTanBf16Test = LIBC_NAMESPACE::testing::FPTest; + +namespace mpfr = LIBC_NAMESPACE::testing::mpfr; + +// Range: [0, Inf] +static constexpr uint16_t POS_START = 0x0000U; +static constexpr uint16_t POS_STOP = 0x7f80U; + +// Range: [-Inf, 0] +static constexpr uint16_t NEG_START = 0x8000U; +static constexpr uint16_t NEG_STOP = 0xff80U; + +TEST_F(LlvmLibcTanBf16Test, PositiveRange) { + for (uint16_t v = POS_START; v <= POS_STOP; ++v) { + bfloat16 x = FPBits(v).get_val(); + + EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Tan, x, + LIBC_NAMESPACE::tanbf16(x), 0.5); + } +} + +TEST_F(LlvmLibcTanBf16Test, NegativeRange) { + for (uint16_t v = NEG_START; v <= NEG_STOP; ++v) { + bfloat16 x = FPBits(v).get_val(); + + EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Tan, x, + LIBC_NAMESPACE::tanbf16(x), 0.5); + } +} diff --git a/libc/test/src/wchar/wcslcat_test.cpp b/libc/test/src/wchar/wcslcat_test.cpp index bad37496384e2..564a5c60006e6 100644 --- a/libc/test/src/wchar/wcslcat_test.cpp +++ b/libc/test/src/wchar/wcslcat_test.cpp @@ -55,3 +55,15 @@ TEST(LlvmLibcWCSLCatTest, SmallerNoOverwriteAfter0) { ASSERT_TRUE(dst[7] == L'\0'); ASSERT_EQ(res, size_t(4)); } + +TEST(LlvmLibcWCSLCatTest, DstsizeLessThanDstlen) { + const wchar_t *src = L"d"; + wchar_t dst[4]{L"abc"}; + // Should return src length + dst size + size_t res = LIBC_NAMESPACE::wcslcat(dst, src, 2); + ASSERT_TRUE(dst[0] == L'a'); + ASSERT_TRUE(dst[1] == L'b'); + ASSERT_TRUE(dst[2] == L'c'); + ASSERT_TRUE(dst[3] == L'\0'); + ASSERT_EQ(res, size_t(3)); +} diff --git a/libc/test/src/wchar/wcsncat_test.cpp b/libc/test/src/wchar/wcsncat_test.cpp index 47359f88cec9e..0795685713e00 100644 --- a/libc/test/src/wchar/wcsncat_test.cpp +++ b/libc/test/src/wchar/wcsncat_test.cpp @@ -80,3 +80,15 @@ TEST(LlvmLibcWCSNCatTest, NonEmptyDest) { ASSERT_TRUE(dest[3] == L'\0'); ASSERT_TRUE(dest[4] == L'Z'); } + +TEST(LlvmLibcWCSNCatTest, OOBAccess) { + wchar_t dest[4] = {L'\0'}; + wchar_t src[3] = {L'a', L'b', L'c'}; + + // Checking the bound + LIBC_NAMESPACE::wcsncat(dest, src, 3); + ASSERT_TRUE(dest[0] == L'a'); + ASSERT_TRUE(dest[1] == L'b'); + ASSERT_TRUE(dest[2] == L'c'); + ASSERT_TRUE(dest[3] == L'\0'); +} diff --git a/libcxx/include/__algorithm/simd_utils.h b/libcxx/include/__algorithm/simd_utils.h index f73c9ea4b6ea7..c47f79ac7f1dd 100644 --- a/libcxx/include/__algorithm/simd_utils.h +++ b/libcxx/include/__algorithm/simd_utils.h @@ -124,15 +124,6 @@ template return _VecT{__iter[_LoadIndices]..., ((void)_ZeroIndices, 0)...}; }(make_index_sequence<_Np>{}, make_index_sequence<__simd_vector_size_v<_VecT> - _Np>{}); } - -// Create a vector where every elements is __val -template -[[__nodiscard__]] _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _VecT -__broadcast(__simd_vector_underlying_type_t<_VecT> __val) { - return [&](index_sequence<_Indices...>) { - return _VecT{((void)_Indices, __val)...}; - }(make_index_sequence<__simd_vector_size_v<_VecT>>()); -} _LIBCPP_DIAGNOSTIC_POP template diff --git a/libcxx/include/__locale_dir/num.h b/libcxx/include/__locale_dir/num.h index 8af427ca37dbe..5b3b917384121 100644 --- a/libcxx/include/__locale_dir/num.h +++ b/libcxx/include/__locale_dir/num.h @@ -96,9 +96,8 @@ struct __num_get : protected __num_get_base { _LIBCPP_DIAGNOSTIC_PUSH _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wpsabi") using __vec = __simd_vector; - __vec __chars = std::__broadcast<__vec>(__val); __vec __cmp = std::__partial_load<__vec, __int_chr_cnt>(__atoms); - auto __res = __chars == __cmp; + auto __res = __vec(__val) == __cmp; if (std::__none_of(__res)) return __int_chr_cnt; return std::min(__int_chr_cnt, std::__find_first_set(__res)); diff --git a/libcxx/include/__memory/shared_ptr.h b/libcxx/include/__memory/shared_ptr.h index 8d12e395bb86c..c1d4222f195dc 100644 --- a/libcxx/include/__memory/shared_ptr.h +++ b/libcxx/include/__memory/shared_ptr.h @@ -90,7 +90,7 @@ class weak_ptr; template class _LIBCPP_HIDE_STRUCT_FROM_ABI __shared_ptr_pointer final : public __shared_weak_count { - using __alloc_t = __allocator_traits_rebind_t<_Alloc, __shared_ptr_pointer>; + using __alloc_t _LIBCPP_NODEBUG = __allocator_traits_rebind_t<_Alloc, __shared_ptr_pointer>; _LIBCPP_NO_UNIQUE_ADDRESS __alloc_t __alloc_; _LIBCPP_NO_UNIQUE_ADDRESS _Dp __deleter_; @@ -158,7 +158,7 @@ struct _LIBCPP_HIDE_STRUCT_FROM_ABI __shared_ptr_emplace_for_overwrite : __share using __alloc_t _LIBCPP_NODEBUG = __allocator_traits_rebind_t<_Alloc, __shared_ptr_emplace_for_overwrite>; using __value_type _LIBCPP_NODEBUG = __remove_cv_t<_Tp>; - explicit __shared_ptr_emplace_for_overwrite(_Alloc __a) : __alloc_(std::move(__a)) {} + _LIBCPP_HIDE_FROM_ABI explicit __shared_ptr_emplace_for_overwrite(_Alloc __a) : __alloc_(std::move(__a)) {} _LIBCPP_HIDE_FROM_ABI_VIRTUAL void __on_zero_shared() _NOEXCEPT override { __value_.~__value_type(); } _LIBCPP_HIDE_FROM_ABI_VIRTUAL void __on_zero_shared_weak() _NOEXCEPT override { @@ -168,7 +168,7 @@ struct _LIBCPP_HIDE_STRUCT_FROM_ABI __shared_ptr_emplace_for_overwrite : __share __alloc_traits::deallocate(__tmp, pointer_traits::pointer_to(*this), 1); } - __value_type* __get_elem() _NOEXCEPT { return std::addressof(__value_); } + _LIBCPP_HIDE_FROM_ABI __value_type* __get_elem() _NOEXCEPT { return std::addressof(__value_); } private: _LIBCPP_NO_UNIQUE_ADDRESS __alloc_t __alloc_; @@ -602,12 +602,12 @@ class _LIBCPP_SHARED_PTR_TRIVIAL_ABI shared_ptr { template struct __get_shared_from_this { - using type = __nat; + using type _LIBCPP_NODEBUG = __nat; }; template struct __get_shared_from_this<_Vp, __void_t(nullptr)))> > { - using type = const enable_shared_from_this(nullptr)))::type>*; }; @@ -616,7 +616,7 @@ class _LIBCPP_SHARED_PTR_TRIVIAL_ABI shared_ptr { class _OrigPtr, __enable_if_t >::type>::value, int> = 0> - void __enable_weak_this(_Yp, _OrigPtr) {} + _LIBCPP_HIDE_FROM_ABI void __enable_weak_this(_Yp, _OrigPtr) {} template struct __shared_ptr_default_delete : default_delete<_Yp> {}; diff --git a/libsycl/docs/index.rst b/libsycl/docs/index.rst index 4e92a219163ca..a5d657f3e6404 100644 --- a/libsycl/docs/index.rst +++ b/libsycl/docs/index.rst @@ -126,7 +126,7 @@ TODO for added SYCL classes * handle sub devices once they are implemented (blocked by liboffload support) * ``event``: get_wait_list, get_info, get_profiling_info, wait_and_throw & default ctor are not implemented -* ``range``, ``id`` - to add operators +* ``range``, ``id`` - __SYCL_DISABLE_ID_TO_INT_CONV__ and __SYCL_ASSUME_ID_RANGE optimizations are not implemented * general opens: * define a way to report errors from object dtors diff --git a/libsycl/include/sycl/__impl/index_space_classes.hpp b/libsycl/include/sycl/__impl/index_space_classes.hpp index 823dcea062d15..8f99d03d004ee 100644 --- a/libsycl/include/sycl/__impl/index_space_classes.hpp +++ b/libsycl/include/sycl/__impl/index_space_classes.hpp @@ -27,36 +27,40 @@ namespace detail { class Builder; +template +using IntegralType = std::enable_if_t, T>; + /// Helper class for dimensions data management. -template class RawArray { +template class IndexSpaceBase { static_assert(Dimensions >= 1 && Dimensions <= 3, - "RawArray can only be 1, 2, or 3 Dimensional."); + "IndexSpaceBase can only be 1, 2, or 3 Dimensional."); public: /// Constructs a one-dimensional instance and assigns the corresponding data /// to Dim0 value. Available only if Dimensions = 1. template = true> - RawArray(size_t Dim0 = 0) : MArray{Dim0} {} + IndexSpaceBase(size_t Dim0 = 0) : MArray{Dim0} {} /// Constructs a two-dimensional instance and assigns the corresponding data. /// Available only if Dimensions = 2. template = true> - RawArray(size_t Dim0, size_t Dim1) : MArray{Dim0, Dim1} {} + IndexSpaceBase(size_t Dim0, size_t Dim1) : MArray{Dim0, Dim1} {} /// Constructs a two-dimensional instance with the zero-initialized /// corresponding data. Available only if Dimensions = 2. template = true> - RawArray() : RawArray(0, 0) {} + IndexSpaceBase() : IndexSpaceBase(0, 0) {} /// Constructs a three-dimensional instance and assigns the corresponding /// data. Available only if Dimensions = 3. template = true> - RawArray(size_t Dim0, size_t Dim1, size_t Dim2) : MArray{Dim0, Dim1, Dim2} {} + IndexSpaceBase(size_t Dim0, size_t Dim1, size_t Dim2) + : MArray{Dim0, Dim1, Dim2} {} /// Constructs a three-dimensional instance with the zero-initialized /// corresponding data. Available only if Dimensions = 3. template = true> - RawArray() : RawArray(0, 0, 0) {} + IndexSpaceBase() : IndexSpaceBase(0, 0, 0) {} /// Returns the value for the specified dimension. /// Results in undefined behavior if dimension is not in the range [0, @@ -81,14 +85,16 @@ template class RawArray { return MArray[Dimension]; } - RawArray(const RawArray &rhs) = default; - RawArray(RawArray &&rhs) = default; - RawArray &operator=(const RawArray &rhs) = default; - RawArray &operator=(RawArray &&rhs) = default; - ~RawArray() = default; + IndexSpaceBase(const IndexSpaceBase &rhs) = default; + IndexSpaceBase(IndexSpaceBase &&rhs) = default; + IndexSpaceBase & + operator=(const IndexSpaceBase &rhs) = default; + IndexSpaceBase & + operator=(IndexSpaceBase &&rhs) = default; + ~IndexSpaceBase() = default; - friend bool operator==(const RawArray &lhs, - const RawArray &rhs) { + friend bool operator==(const IndexSpaceBase &lhs, + const IndexSpaceBase &rhs) { for (int i = 0; i < Dimensions; ++i) { if (lhs.MArray[i] != rhs.MArray[i]) { return false; @@ -97,14 +103,127 @@ template class RawArray { return true; } - friend bool operator!=(const RawArray &lhs, - const RawArray &rhs) { + friend bool operator!=(const IndexSpaceBase &lhs, + const IndexSpaceBase &rhs) { return !(lhs == rhs); } +#define _LIBSYCL_GEN_OPT(op) \ + friend Derived operator op(const Derived &lhs, \ + const Derived &rhs) noexcept { \ + Derived result; \ + for (int i = 0; i < Dimensions; ++i) { \ + result.MArray[i] = lhs.MArray[i] op rhs.MArray[i]; \ + } \ + return result; \ + } \ + \ + template \ + friend IntegralType operator op(const Derived &lhs, \ + const T &rhs) noexcept { \ + Derived result; \ + for (int i = 0; i < Dimensions; ++i) { \ + result.MArray[i] = lhs.MArray[i] op rhs; \ + } \ + return result; \ + } \ + \ + template \ + friend IntegralType operator op(const T &lhs, \ + const Derived &rhs) noexcept { \ + Derived result; \ + for (int i = 0; i < Dimensions; ++i) { \ + result.MArray[i] = lhs op rhs.MArray[i]; \ + } \ + return result; \ + } + + _LIBSYCL_GEN_OPT(+) + _LIBSYCL_GEN_OPT(-) + _LIBSYCL_GEN_OPT(*) + _LIBSYCL_GEN_OPT(/) + _LIBSYCL_GEN_OPT(%) + _LIBSYCL_GEN_OPT(<<) + _LIBSYCL_GEN_OPT(>>) + _LIBSYCL_GEN_OPT(&) + _LIBSYCL_GEN_OPT(|) + _LIBSYCL_GEN_OPT(^) + _LIBSYCL_GEN_OPT(&&) + _LIBSYCL_GEN_OPT(||) + _LIBSYCL_GEN_OPT(<) + _LIBSYCL_GEN_OPT(>) + _LIBSYCL_GEN_OPT(<=) + _LIBSYCL_GEN_OPT(>=) + +#undef _LIBSYCL_GEN_OPT + +#define _LIBSYCL_GEN_OPT(op) \ + friend Derived &operator op(Derived &lhs, const Derived &rhs) noexcept { \ + for (int i = 0; i < Dimensions; ++i) { \ + lhs.MArray[i] op rhs[i]; \ + } \ + return lhs; \ + } \ + template \ + friend IntegralType &operator op(Derived &lhs, \ + const T &rhs) noexcept { \ + for (int i = 0; i < Dimensions; ++i) { \ + lhs.MArray[i] op rhs; \ + } \ + return lhs; \ + } + + _LIBSYCL_GEN_OPT(+=) + _LIBSYCL_GEN_OPT(-=) + _LIBSYCL_GEN_OPT(*=) + _LIBSYCL_GEN_OPT(/=) + _LIBSYCL_GEN_OPT(%=) + _LIBSYCL_GEN_OPT(<<=) + _LIBSYCL_GEN_OPT(>>=) + _LIBSYCL_GEN_OPT(&=) + _LIBSYCL_GEN_OPT(|=) + _LIBSYCL_GEN_OPT(^=) + +#undef _LIBSYCL_GEN_OPT + +#define _LIBSYCL_GEN_OPT(op) \ + friend Derived operator op(const Derived &rhs) noexcept { \ + Derived result; \ + for (int i = 0; i < Dimensions; ++i) { \ + result.MArray[i] = (op rhs.MArray[i]); \ + } \ + return result; \ + } + + _LIBSYCL_GEN_OPT(+) + _LIBSYCL_GEN_OPT(-) + +#undef _LIBSYCL_GEN_OPT + +#define _LIBSYCL_GEN_OPT(op) \ + friend Derived &operator op(Derived &rhs) noexcept { \ + for (int i = 0; i < Dimensions; ++i) { \ + op rhs.MArray[i]; \ + } \ + return rhs; \ + } \ + friend Derived operator op(Derived &lhs, int) noexcept { \ + Derived oldLhs(lhs); \ + for (int i = 0; i < Dimensions; ++i) { \ + op lhs.MArray[i]; \ + } \ + return oldLhs; \ + } + + _LIBSYCL_GEN_OPT(++) + _LIBSYCL_GEN_OPT(--) + +#undef _LIBSYCL_GEN_OPT + protected: size_t MArray[Dimensions]; }; + } // namespace detail /// SYCL 2020 4.9.1.1. range class. @@ -112,10 +231,10 @@ template class RawArray { /// domain of either a single work-group in a parallel dispatch, or the overall /// Dimensions of the dispatch. template -class range : public detail::RawArray { +class range : public detail::IndexSpaceBase, Dimensions> { static_assert(Dimensions >= 1 && Dimensions <= 3, "range can only be 1-, 2-, or 3-dimensional."); - using Base = detail::RawArray; + using Base = detail::IndexSpaceBase, Dimensions>; public: static constexpr int dimensions = Dimensions; @@ -142,7 +261,7 @@ class range : public detail::RawArray { : Base(dim0, dim1, dim2) {} /* - Declared and implemented in detail::RawArray: + Declared and implemented in detail::IndexSpaceBase: std::size_t get(int dimension) const noexcept; std::size_t& operator[](int dimension) noexcept; std::size_t operator[](int dimension) const noexcept; @@ -156,8 +275,6 @@ class range : public detail::RawArray { } return size; } - - // TODO: operators to be added }; /// c++ deduction guides. @@ -173,10 +290,11 @@ template class item; /// id is a vector of Dimensions that is used to represent an id /// into a global or local range. It can be used as an index in an accessor of /// the same rank. -template class id : public detail::RawArray { +template +class id : public detail::IndexSpaceBase, Dimensions> { static_assert(Dimensions >= 1 && Dimensions <= 3, "id can only be 1-, 2-, or 3-dimensional."); - using Base = detail::RawArray; + using Base = detail::IndexSpaceBase, Dimensions>; // Helper class for conversion operator. Void type is not suitable. User // cannot even try to get address of the operator PrivateTag(). User @@ -230,39 +348,67 @@ template class id : public detail::RawArray { /// Constructs an id from item.get_id(). /// Only valid when the template parameter Dimensions is equal to 1. - template = true> - id(const item &item) noexcept : Base(item.get_id(0)) {} + template = true> + id(const item &item) noexcept + : Base(item.get_id(0)) {} /// Constructs an id from item.get_id(). /// Only valid when the template parameter Dimensions is equal to 2. - template = true> - id(const item &item) noexcept + template = true> + id(const item &item) noexcept : Base(item.get_id(0), item.get_id(1)) {} /// Constructs an id from item.get_id(). /// Only valid when the template parameter Dimensions is equal to 3. - template = true> - id(const item &item) noexcept + template = true> + id(const item &item) noexcept : Base(item.get_id(0), item.get_id(1), item.get_id(2)) {} /* - Declared and implemented in detail::RawArray: + Declared and implemented in detail::IndexSpaceBase: std::size_t get(int dimension) const noexcept; std::size_t& operator[](int dimension) noexcept; std::size_t operator[](int dimension) const noexcept; */ // Template operator is not allowed because it disables further type - // conversion. For example, the next code will not work in case of template - // conversion: - // int a = id<1>(value); + // conversion. For example, the next code will not work in case of template + // conversion: int a = id<1>(value); /// Returns the same value as get(0). /// Available only when: Dimensions == 1. operator EnableIfT<(Dimensions == 1), std::size_t>() const noexcept { return Base::get(0); } - // TODO: operators to be added +// These operators are not a part of SYCL 2020 spec but are needed to avoid +// ambiguity in case of implicit conversion id<1> vs size_t. Template operators +// take precedence over type conversion. In the case of non-template operators, +// ambiguity appears: "id op size_t" may refer "size_t op size_t" or "id op +// size_t". In the case of template operators it will be "id op size_t". +#define _LIBSYCL_GEN_OPT(op) \ + template = true> \ + detail::IntegralType operator op(const T &rhs) const noexcept { \ + if (this->MArray[0] != rhs) \ + return false op true; \ + return true op true; \ + } \ + template = true> \ + friend detail::IntegralType operator op( \ + const T &lhs, const id &rhs) noexcept { \ + if (lhs != rhs.MArray[0]) \ + return false op true; \ + return true op true; \ + } + + _LIBSYCL_GEN_OPT(==) + _LIBSYCL_GEN_OPT(!=) + +#undef _LIBSYCL_GEN_OPT }; /// c++ deduction guides. diff --git a/libsycl/include/sycl/__impl/queue.hpp b/libsycl/include/sycl/__impl/queue.hpp index 87f1a4d7e6c14..d05592e5fa3fd 100644 --- a/libsycl/include/sycl/__impl/queue.hpp +++ b/libsycl/include/sycl/__impl/queue.hpp @@ -32,6 +32,7 @@ _LIBSYCL_BEGIN_NAMESPACE_SYCL class context; namespace detail { +class MockQueue; class QueueImpl; template struct CheckFunctionCallOperator { @@ -430,6 +431,7 @@ class _LIBSYCL_EXPORT queue { std::shared_ptr impl; friend sycl::detail::ImplUtils; + friend sycl::detail::MockQueue; }; // class queue _LIBSYCL_END_NAMESPACE_SYCL diff --git a/libsycl/test/basic/index_space_classes.cpp b/libsycl/test/basic/index_space_classes.cpp new file mode 100644 index 0000000000000..1afb70e634303 --- /dev/null +++ b/libsycl/test/basic/index_space_classes.cpp @@ -0,0 +1,284 @@ +// REQUIRES: any-device +// RUN: %clangxx -fsycl %s -o %t.out +// RUN: %t.out +// +// Unified test for sycl::range and sycl::id covering all operators defined in +// theirs base class, plus class-specific behaviour for each type. + +#include +#include +#include + +using sycl::detail::Builder; + +// Helper to create values for any dimension from three components. +// Only uses the required number of values based on dimension. +template