From 48eb697441e20f2e1a66d953436b9d66e0fc466d Mon Sep 17 00:00:00 2001 From: Florian Hahn Date: Mon, 24 Nov 2025 19:23:04 +0000 Subject: [PATCH 01/50] [LV] Count cost of middle block if TC <= VF. (#168949) If the expected trip count is less than the VF, the vector loop will only execute a single iteration. When that's the case, the cost of the middle block has the same impact as the cost of the vector loop. Include it in isOutsideLoopWorkProfitable to avoid vectorizing when the extra work in the middle block makes it unprofitable. Note that isOutsideLoopWorkProfitable already scales the cost of blocks outside the vector region, but the patch restricts accounting for the middle block to cases where VF <= ExpectedTC, to initially catch some worst cases and avoid regressions. This initial version should specifically avoid unprofitable tail-folding for loops with low trip counts after re-applying https://github.com/llvm/llvm-project/pull/149042. PR: https://github.com/llvm/llvm-project/pull/168949 --- .../Transforms/Vectorize/LoopVectorize.cpp | 17 +++++-- .../X86/replicating-load-store-costs.ll | 51 +++++++------------ 2 files changed, 31 insertions(+), 37 deletions(-) diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp index 7ac132a99fbec..a63956c0cba6b 100644 --- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp +++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp @@ -9257,6 +9257,7 @@ static InstructionCost calculateEarlyExitCost(VPCostContext &CostCtx, /// 2. In the case of loops with uncountable early exits, we may have to do /// extra work when exiting the loop early, such as calculating the final /// exit values of variables used outside the loop. +/// 3. The middle block, if expected TC <= VF.Width. static bool isOutsideLoopWorkProfitable(GeneratedRTChecks &Checks, VectorizationFactor &VF, Loop *L, PredicatedScalarEvolution &PSE, @@ -9271,6 +9272,14 @@ static bool isOutsideLoopWorkProfitable(GeneratedRTChecks &Checks, // one exists. TotalCost += calculateEarlyExitCost(CostCtx, Plan, VF.Width); + // If the expected trip count is less than the VF, the vector loop will only + // execute a single iteration. Then the middle block is executed the same + // number of times as the vector region. + // TODO: Extend logic to always account for the cost of the middle block. + auto ExpectedTC = getSmallBestKnownTC(PSE, L); + if (ExpectedTC && ElementCount::isKnownLE(*ExpectedTC, VF.Width)) + TotalCost += Plan.getMiddleBlock()->cost(VF.Width, CostCtx); + // When interleaving only scalar and vector cost will be equal, which in turn // would lead to a divide by 0. Fall back to hard threshold. if (VF.Width.isScalar()) { @@ -9301,9 +9310,11 @@ static bool isOutsideLoopWorkProfitable(GeneratedRTChecks &Checks, // The total cost of the vector loop is // RtC + VecC * (TC / VF) + EpiC // where - // * RtC is the cost of the generated runtime checks plus the cost of - // performing any additional work in the vector.early.exit block for loops - // with uncountable early exits. + // * RtC is the sum of the costs cost of + // - the generated runtime checks + // - performing any additional work in the vector.early.exit block for + // loops with uncountable early exits. + // - the middle block, if ExpectedTC <= VF.Width. // * VecC is the cost of a single vector iteration. // * TC is the actual trip count of the loop // * VF is the vectorization factor diff --git a/llvm/test/Transforms/LoopVectorize/X86/replicating-load-store-costs.ll b/llvm/test/Transforms/LoopVectorize/X86/replicating-load-store-costs.ll index 803c472a35a51..f44d3008cbaa5 100644 --- a/llvm/test/Transforms/LoopVectorize/X86/replicating-load-store-costs.ll +++ b/llvm/test/Transforms/LoopVectorize/X86/replicating-load-store-costs.ll @@ -569,53 +569,36 @@ define double @test_load_used_by_other_load_scev_low_trip_count(ptr %ptr.a, ptr ; I64-NEXT: [[ENTRY:.*]]: ; I64-NEXT: br label %[[OUTER_LOOP:.*]] ; I64: [[OUTER_LOOP_LOOPEXIT:.*]]: +; I64-NEXT: [[RESULT_LCSSA:%.*]] = phi double [ [[RESULT:%.*]], %[[INNER_LOOP:.*]] ] ; I64-NEXT: br label %[[OUTER_LOOP]] ; I64: [[OUTER_LOOP]]: -; I64-NEXT: [[ACCUM:%.*]] = phi double [ 0.000000e+00, %[[ENTRY]] ], [ [[TMP29:%.*]], %[[OUTER_LOOP_LOOPEXIT]] ] +; I64-NEXT: [[ACCUM:%.*]] = phi double [ 0.000000e+00, %[[ENTRY]] ], [ [[RESULT_LCSSA]], %[[OUTER_LOOP_LOOPEXIT]] ] ; I64-NEXT: [[COND:%.*]] = call i1 @cond() ; I64-NEXT: br i1 [[COND]], label %[[INNER_LOOP_PREHEADER:.*]], label %[[EXIT:.*]] ; I64: [[INNER_LOOP_PREHEADER]]: -; I64-NEXT: br label %[[VECTOR_PH:.*]] -; I64: [[VECTOR_PH]]: -; I64-NEXT: br label %[[VECTOR_BODY:.*]] -; I64: [[VECTOR_BODY]]: -; I64-NEXT: [[TMP0:%.*]] = add i64 0, 1 -; I64-NEXT: [[TMP1:%.*]] = add i64 1, 1 -; I64-NEXT: [[TMP2:%.*]] = getelementptr i8, ptr [[PTR_C]], i64 [[TMP0]] +; I64-NEXT: br label %[[INNER_LOOP]] +; I64: [[INNER_LOOP]]: +; I64-NEXT: [[IV:%.*]] = phi i64 [ [[IV_NEXT:%.*]], %[[INNER_LOOP]] ], [ 0, %[[INNER_LOOP_PREHEADER]] ] +; I64-NEXT: [[ACCUM_INNER:%.*]] = phi double [ [[MUL1:%.*]], %[[INNER_LOOP]] ], [ [[ACCUM]], %[[INNER_LOOP_PREHEADER]] ] +; I64-NEXT: [[TMP1:%.*]] = add i64 [[IV]], 1 ; I64-NEXT: [[TMP3:%.*]] = getelementptr i8, ptr [[PTR_C]], i64 [[TMP1]] -; I64-NEXT: [[TMP4:%.*]] = getelementptr i64, ptr [[PTR_A]], i64 [[TMP0]] ; I64-NEXT: [[TMP5:%.*]] = getelementptr i64, ptr [[PTR_A]], i64 [[TMP1]] -; I64-NEXT: [[TMP6:%.*]] = load i64, ptr [[TMP4]], align 8 ; I64-NEXT: [[TMP7:%.*]] = load i64, ptr [[TMP5]], align 8 -; I64-NEXT: [[TMP8:%.*]] = getelementptr double, ptr [[PTR_B]], i64 [[TMP6]] ; I64-NEXT: [[TMP9:%.*]] = getelementptr double, ptr [[PTR_B]], i64 [[TMP7]] ; I64-NEXT: [[TMP10:%.*]] = load double, ptr [[PTR_A]], align 8 -; I64-NEXT: [[BROADCAST_SPLATINSERT:%.*]] = insertelement <2 x double> poison, double [[TMP10]], i64 0 -; I64-NEXT: [[BROADCAST_SPLAT:%.*]] = shufflevector <2 x double> [[BROADCAST_SPLATINSERT]], <2 x double> poison, <2 x i32> zeroinitializer -; I64-NEXT: [[TMP11:%.*]] = fadd <2 x double> [[BROADCAST_SPLAT]], zeroinitializer -; I64-NEXT: [[TMP12:%.*]] = getelementptr i8, ptr [[TMP2]], i64 8 +; I64-NEXT: [[ADD1:%.*]] = fadd double [[TMP10]], 0.000000e+00 ; I64-NEXT: [[TMP13:%.*]] = getelementptr i8, ptr [[TMP3]], i64 8 -; I64-NEXT: [[TMP14:%.*]] = load double, ptr [[TMP12]], align 8 ; I64-NEXT: [[TMP15:%.*]] = load double, ptr [[TMP13]], align 8 -; I64-NEXT: [[TMP16:%.*]] = insertelement <2 x double> poison, double [[TMP14]], i32 0 -; I64-NEXT: [[TMP17:%.*]] = insertelement <2 x double> [[TMP16]], double [[TMP15]], i32 1 -; I64-NEXT: [[TMP18:%.*]] = fmul <2 x double> [[TMP11]], zeroinitializer -; I64-NEXT: [[BROADCAST_SPLATINSERT1:%.*]] = insertelement <2 x double> poison, double [[ACCUM]], i64 0 -; I64-NEXT: [[BROADCAST_SPLAT2:%.*]] = shufflevector <2 x double> [[BROADCAST_SPLATINSERT1]], <2 x double> poison, <2 x i32> zeroinitializer -; I64-NEXT: [[TMP19:%.*]] = shufflevector <2 x double> [[BROADCAST_SPLAT2]], <2 x double> [[TMP18]], <2 x i32> -; I64-NEXT: [[TMP20:%.*]] = fmul <2 x double> [[TMP17]], zeroinitializer -; I64-NEXT: [[TMP21:%.*]] = fadd <2 x double> [[TMP20]], zeroinitializer -; I64-NEXT: [[TMP22:%.*]] = fadd <2 x double> [[TMP21]], splat (double 1.000000e+00) -; I64-NEXT: [[TMP23:%.*]] = load double, ptr [[TMP8]], align 8 +; I64-NEXT: [[MUL1]] = fmul double [[ADD1]], 0.000000e+00 +; I64-NEXT: [[MUL2:%.*]] = fmul double [[TMP15]], 0.000000e+00 +; I64-NEXT: [[ADD2:%.*]] = fadd double [[MUL2]], 0.000000e+00 +; I64-NEXT: [[ADD3:%.*]] = fadd double [[ADD2]], 1.000000e+00 ; I64-NEXT: [[TMP24:%.*]] = load double, ptr [[TMP9]], align 8 -; I64-NEXT: [[TMP25:%.*]] = insertelement <2 x double> poison, double [[TMP23]], i32 0 -; I64-NEXT: [[TMP26:%.*]] = insertelement <2 x double> [[TMP25]], double [[TMP24]], i32 1 -; I64-NEXT: [[TMP27:%.*]] = fdiv <2 x double> [[TMP26]], [[TMP22]] -; I64-NEXT: [[TMP28:%.*]] = fsub <2 x double> [[TMP19]], [[TMP27]] -; I64-NEXT: br label %[[MIDDLE_BLOCK:.*]] -; I64: [[MIDDLE_BLOCK]]: -; I64-NEXT: [[TMP29]] = extractelement <2 x double> [[TMP28]], i32 1 -; I64-NEXT: br label %[[OUTER_LOOP_LOOPEXIT]] +; I64-NEXT: [[DIV:%.*]] = fdiv double [[TMP24]], [[ADD3]] +; I64-NEXT: [[RESULT]] = fsub double [[ACCUM_INNER]], [[DIV]] +; I64-NEXT: [[IV_NEXT]] = add i64 [[IV]], 1 +; I64-NEXT: [[EXITCOND:%.*]] = icmp eq i64 [[IV]], 1 +; I64-NEXT: br i1 [[EXITCOND]], label %[[OUTER_LOOP_LOOPEXIT]], label %[[INNER_LOOP]] ; I64: [[EXIT]]: ; I64-NEXT: ret double [[ACCUM]] ; From 7b186e4bf0f1485657697bc79c66b5792dcd562e Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Mon, 24 Nov 2025 20:26:07 +0100 Subject: [PATCH 02/50] [clang-format] Fix designated initializer detection (#169228) Currently, in the following snippet, the second designated initializer is incorrectly detected as an OBJC method expr. Fix that and a test to make sure we don't regress. ``` Foo foo[] = {[0] = 1, [1] = 2}; ``` --- clang/lib/Format/TokenAnnotator.cpp | 5 +++++ clang/unittests/Format/TokenAnnotatorTest.cpp | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp index 200ee13901f4b..79cfa73001e54 100644 --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -708,6 +708,11 @@ class AnnotatingParser { IsCpp && !IsCpp11AttributeSpecifier && !IsCSharpAttributeSpecifier && Contexts.back().CanBeExpression && Left->isNot(TT_LambdaLSquare) && CurrentToken->isNoneOf(tok::l_brace, tok::r_square) && + // Do not consider '[' after a comma inside a braced initializer the + // start of an ObjC method expression. In braced initializer lists, + // commas are list separators and should not trigger ObjC parsing. + (!Parent || !Parent->is(tok::comma) || + Contexts.back().ContextKind != tok::l_brace) && (!Parent || Parent->isOneOf(tok::colon, tok::l_square, tok::l_paren, tok::kw_return, tok::kw_throw) || diff --git a/clang/unittests/Format/TokenAnnotatorTest.cpp b/clang/unittests/Format/TokenAnnotatorTest.cpp index 6d769396589ee..008adff1cee2d 100644 --- a/clang/unittests/Format/TokenAnnotatorTest.cpp +++ b/clang/unittests/Format/TokenAnnotatorTest.cpp @@ -3370,6 +3370,11 @@ TEST_F(TokenAnnotatorTest, UnderstandDesignatedInitializers) { ASSERT_EQ(Tokens.size(), 14u) << Tokens; EXPECT_TOKEN(Tokens[6], tok::l_square, TT_DesignatedInitializerLSquare); EXPECT_BRACE_KIND(Tokens[9], BK_BracedInit); + + Tokens = annotate("Foo foo[] = {[0] = 1, [1] = 2};"); + ASSERT_EQ(Tokens.size(), 20u) << Tokens; + EXPECT_TOKEN(Tokens[6], tok::l_square, TT_DesignatedInitializerLSquare); + EXPECT_TOKEN(Tokens[12], tok::l_square, TT_DesignatedInitializerLSquare); } TEST_F(TokenAnnotatorTest, UnderstandsJavaScript) { From 40334b8632f6d065e6672ada1c4342d07ecce629 Mon Sep 17 00:00:00 2001 From: Shilei Tian Date: Mon, 24 Nov 2025 14:31:38 -0500 Subject: [PATCH 03/50] Revert " [clang] Refactor to remove clangDriver dependency from clangFrontend and flangFrontend (#165277)" This reverts commit 3773bbe9e7916ec89fb3e3cd02e29c54cabac82b. --- clang-tools-extra/clangd/CompileCommands.cpp | 3 +- clang-tools-extra/clangd/Compiler.cpp | 1 - clang/docs/ReleaseNotes.rst | 2 - clang/include/clang/Driver/CommonArgs.h | 10 + .../clang/Driver/CreateASTUnitFromArgs.h | 80 ---- .../clang/Driver/CreateInvocationFromArgs.h | 76 ---- clang/include/clang/Driver/Driver.h | 5 + clang/include/clang/Frontend/ASTUnit.h | 146 ++++---- .../Frontend/ChainedDiagnosticConsumer.h | 2 +- .../clang/Frontend/CompilerInvocation.h | 10 + .../clang/Frontend/StandaloneDiagnostic.h | 82 ----- clang/include/clang/Frontend/Utils.h | 45 +++ clang/include/clang/Options/OptionUtils.h | 24 -- clang/lib/CrossTU/CMakeLists.txt | 1 - clang/lib/CrossTU/CrossTranslationUnit.cpp | 3 +- clang/lib/Driver/CMakeLists.txt | 4 - clang/lib/Driver/CreateASTUnitFromArgs.cpp | 166 --------- clang/lib/Driver/Driver.cpp | 35 +- clang/lib/Driver/ToolChains/Clang.cpp | 1 - clang/lib/Driver/ToolChains/CommonArgs.cpp | 163 +++++++++ clang/lib/Driver/ToolChains/Flang.cpp | 1 - clang/lib/Frontend/ASTUnit.cpp | 346 +++++++++++++++--- clang/lib/Frontend/CMakeLists.txt | 3 +- clang/lib/Frontend/CompilerInvocation.cpp | 7 + .../CreateInvocationFromCommandLine.cpp} | 15 +- clang/lib/Frontend/StandaloneDiagnostic.cpp | 117 ------ clang/lib/Interpreter/CMakeLists.txt | 1 - clang/lib/Interpreter/Interpreter.cpp | 3 +- clang/lib/Options/OptionUtils.cpp | 215 +---------- clang/lib/Tooling/Tooling.cpp | 4 +- clang/tools/c-index-test/CMakeLists.txt | 1 - clang/tools/c-index-test/core_main.cpp | 1 - clang/tools/diagtool/CMakeLists.txt | 1 - clang/tools/diagtool/ShowEnabledWarnings.cpp | 1 - clang/tools/driver/cc1_main.cpp | 3 +- clang/tools/libclang/CIndex.cpp | 3 +- clang/tools/libclang/CIndexer.cpp | 3 +- clang/tools/libclang/CMakeLists.txt | 1 - clang/tools/libclang/Indexing.cpp | 1 - clang/unittests/Driver/DXCModeTest.cpp | 1 - clang/unittests/Driver/ToolChainTest.cpp | 1 - clang/unittests/Frontend/ASTUnitTest.cpp | 6 +- .../Frontend/CompilerInstanceTest.cpp | 1 - clang/unittests/Frontend/UtilsTest.cpp | 1 - clang/unittests/Sema/CMakeLists.txt | 1 - clang/unittests/Sema/SemaNoloadLookupTest.cpp | 1 - .../Serialization/ForceCheckFileInputTest.cpp | 1 - .../Serialization/LoadSpecLazilyTest.cpp | 1 - .../Serialization/ModuleCacheTest.cpp | 1 - .../Serialization/NoCommentsTest.cpp | 1 - .../PreambleInNamedModulesTest.cpp | 1 - .../Serialization/VarDeclConstantInitTest.cpp | 1 - clang/unittests/Tooling/Syntax/TokensTest.cpp | 1 - .../unittests/Tooling/Syntax/TreeTestBase.cpp | 1 - flang/lib/Frontend/CMakeLists.txt | 1 + flang/lib/Frontend/CompilerInvocation.cpp | 5 +- lldb/source/Commands/CommandObjectTarget.cpp | 1 - .../ExpressionParser/Clang/CMakeLists.txt | 2 +- .../ExpressionParser/Clang/ClangHost.cpp | 4 +- .../Clang/ClangModulesDeclVendor.cpp | 1 - lldb/unittests/Expression/ClangParserTest.cpp | 4 +- 61 files changed, 687 insertions(+), 937 deletions(-) delete mode 100644 clang/include/clang/Driver/CreateASTUnitFromArgs.h delete mode 100644 clang/include/clang/Driver/CreateInvocationFromArgs.h delete mode 100644 clang/include/clang/Frontend/StandaloneDiagnostic.h delete mode 100644 clang/lib/Driver/CreateASTUnitFromArgs.cpp rename clang/lib/{Driver/CreateInvocationFromArgs.cpp => Frontend/CreateInvocationFromCommandLine.cpp} (93%) delete mode 100644 clang/lib/Frontend/StandaloneDiagnostic.cpp diff --git a/clang-tools-extra/clangd/CompileCommands.cpp b/clang-tools-extra/clangd/CompileCommands.cpp index 4eda330716f21..7990f2719e9a0 100644 --- a/clang-tools-extra/clangd/CompileCommands.cpp +++ b/clang-tools-extra/clangd/CompileCommands.cpp @@ -132,7 +132,8 @@ std::optional detectSysroot() { std::string detectStandardResourceDir() { static int StaticForMainAddr; // Just an address in this process. - return GetResourcesPath("clangd", (void *)&StaticForMainAddr); + return CompilerInvocation::GetResourcesPath("clangd", + (void *)&StaticForMainAddr); } // The path passed to argv[0] is important: diff --git a/clang-tools-extra/clangd/Compiler.cpp b/clang-tools-extra/clangd/Compiler.cpp index 9ea7df139382a..6ebc2eac25745 100644 --- a/clang-tools-extra/clangd/Compiler.cpp +++ b/clang-tools-extra/clangd/Compiler.cpp @@ -9,7 +9,6 @@ #include "Compiler.h" #include "support/Logger.h" #include "clang/Basic/TargetInfo.h" -#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/CompilerInvocation.h" #include "clang/Lex/PreprocessorOptions.h" #include "clang/Serialization/PCHContainerOperations.h" diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index b12e4539dc3a6..51f07256c5d9f 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -84,8 +84,6 @@ Potentially Breaking Changes - Downstream projects that previously linked only against ``clangDriver`` may now (also) need to link against the new ``clangOptions`` library, since options-related code has been moved out of the Driver into a separate library. -- The ``clangFrontend`` library no longer depends on ``clangDriver``, which may - break downstream projects that relied on this transitive dependency. C/C++ Language Potentially Breaking Changes ------------------------------------------- diff --git a/clang/include/clang/Driver/CommonArgs.h b/clang/include/clang/Driver/CommonArgs.h index 264bd4965f9ad..ac17d6211d882 100644 --- a/clang/include/clang/Driver/CommonArgs.h +++ b/clang/include/clang/Driver/CommonArgs.h @@ -291,6 +291,16 @@ void handleVectorizeLoopsArgs(const llvm::opt::ArgList &Args, void handleVectorizeSLPArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs); +// Parse -mprefer-vector-width=. Return the Value string if well-formed. +// Otherwise, return an empty string and issue a diagnosic message if needed. +StringRef parseMPreferVectorWidthOption(clang::DiagnosticsEngine &Diags, + const llvm::opt::ArgList &Args); + +// Parse -mrecip. Return the Value string if well-formed. +// Otherwise, return an empty string and issue a diagnosic message if needed. +StringRef parseMRecipOption(clang::DiagnosticsEngine &Diags, + const llvm::opt::ArgList &Args); + // Convert ComplexRangeKind to a string that can be passed as a frontend option. std::string complexRangeKindToStr(LangOptions::ComplexRangeKind Range); diff --git a/clang/include/clang/Driver/CreateASTUnitFromArgs.h b/clang/include/clang/Driver/CreateASTUnitFromArgs.h deleted file mode 100644 index 30575cc04ca7c..0000000000000 --- a/clang/include/clang/Driver/CreateASTUnitFromArgs.h +++ /dev/null @@ -1,80 +0,0 @@ -//===-- CreateInvocationFromArgs.h - Create an ASTUnit from Args-*- 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 -// -//===----------------------------------------------------------------------===// -// -// Utility for creating an ASTUnit from a vector of command line arguments. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_DRIVER_CREATEASTUNITFROMARGS_H -#define LLVM_CLANG_DRIVER_CREATEASTUNITFROMARGS_H - -#include "clang/Frontend/ASTUnit.h" - -namespace clang { - -/// Create an ASTUnit from a vector of command line arguments, which must -/// specify exactly one source file. -/// -/// \param ArgBegin - The beginning of the argument vector. -/// -/// \param ArgEnd - The end of the argument vector. -/// -/// \param PCHContainerOps - The PCHContainerOperations to use for loading and -/// creating modules. -/// -/// \param Diags - The diagnostics engine to use for reporting errors; its -/// lifetime is expected to extend past that of the returned ASTUnit. -/// -/// \param ResourceFilesPath - The path to the compiler resource files. -/// -/// \param StorePreamblesInMemory - Whether to store PCH in memory. If false, -/// PCH are stored in temporary files. -/// -/// \param PreambleStoragePath - The path to a directory, in which to create -/// temporary PCH files. If empty, the default system temporary directory is -/// used. This parameter is ignored if \p StorePreamblesInMemory is true. -/// -/// \param ModuleFormat - If provided, uses the specific module format. -/// -/// \param ErrAST - If non-null and parsing failed without any AST to return -/// (e.g. because the PCH could not be loaded), this accepts the ASTUnit -/// mainly to allow the caller to see the diagnostics. -/// -/// \param VFS - A llvm::vfs::FileSystem to be used for all file accesses. -/// Note that preamble is saved to a temporary directory on a RealFileSystem, -/// so in order for it to be loaded correctly, VFS should have access to -/// it(i.e., be an overlay over RealFileSystem). RealFileSystem will be used -/// if \p VFS is nullptr. -/// -// FIXME: Move OnlyLocalDecls, UseBumpAllocator to setters on the ASTUnit, we -// shouldn't need to specify them at construction time. -std::unique_ptr CreateASTUnitFromCommandLine( - const char **ArgBegin, const char **ArgEnd, - std::shared_ptr PCHContainerOps, - std::shared_ptr DiagOpts, - IntrusiveRefCntPtr Diags, StringRef ResourceFilesPath, - bool StorePreamblesInMemory = false, - StringRef PreambleStoragePath = StringRef(), bool OnlyLocalDecls = false, - CaptureDiagsKind CaptureDiagnostics = CaptureDiagsKind::None, - ArrayRef RemappedFiles = {}, - bool RemappedFilesKeepOriginalName = true, - unsigned PrecompilePreambleAfterNParses = 0, - TranslationUnitKind TUKind = TU_Complete, - bool CacheCodeCompletionResults = false, - bool IncludeBriefCommentsInCodeCompletion = false, - bool AllowPCHWithCompilerErrors = false, - SkipFunctionBodiesScope SkipFunctionBodies = SkipFunctionBodiesScope::None, - bool SingleFileParse = false, bool UserFilesAreVolatile = false, - bool ForSerialization = false, bool RetainExcludedConditionalBlocks = false, - std::optional ModuleFormat = std::nullopt, - std::unique_ptr *ErrAST = nullptr, - IntrusiveRefCntPtr VFS = nullptr); - -} // namespace clang - -#endif // LLVM_CLANG_DRIVER_CREATEASTUNITFROMARGS_H diff --git a/clang/include/clang/Driver/CreateInvocationFromArgs.h b/clang/include/clang/Driver/CreateInvocationFromArgs.h deleted file mode 100644 index 0e0f67373ce87..0000000000000 --- a/clang/include/clang/Driver/CreateInvocationFromArgs.h +++ /dev/null @@ -1,76 +0,0 @@ -//===--- CreateInvocationFromArgs.h - CompilerInvocation from Args --------===// -// -// 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 -// -//===----------------------------------------------------------------------===// -// -// Utility for creating a CompilerInvocation from command-line arguments, for -// tools to use in preparation to parse a file. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_DRIVER_CREATEINVOCATIONFROMARGS_H -#define LLVM_CLANG_DRIVER_CREATEINVOCATIONFROMARGS_H - -#include "clang/Basic/Diagnostic.h" -#include "clang/Basic/LLVM.h" -#include "llvm/Support/VirtualFileSystem.h" -#include -#include -#include - -namespace clang { - -class CompilerInvocation; -class DiagnosticsEngine; - -/// Optional inputs to createInvocation. -struct CreateInvocationOptions { - /// Receives diagnostics encountered while parsing command-line flags. - /// If not provided, these are printed to stderr. - IntrusiveRefCntPtr Diags = nullptr; - /// Used e.g. to probe for system headers locations. - /// If not provided, the real filesystem is used. - /// FIXME: the driver does perform some non-virtualized IO. - IntrusiveRefCntPtr VFS = nullptr; - /// Whether to attempt to produce a non-null (possibly incorrect) invocation - /// if any errors were encountered. - /// By default, always return null on errors. - bool RecoverOnError = false; - /// Allow the driver to probe the filesystem for PCH files. - /// This is used to replace -include with -include-pch in the cc1 args. - /// FIXME: ProbePrecompiled=true is a poor, historical default. - /// It misbehaves if the PCH file is from GCC, has the wrong version, etc. - bool ProbePrecompiled = false; - /// If set, the target is populated with the cc1 args produced by the driver. - /// This may be populated even if createInvocation returns nullptr. - std::vector *CC1Args = nullptr; -}; - -/// Interpret clang arguments in preparation to parse a file. -/// -/// This simulates a number of steps Clang takes when its driver is invoked: -/// - choosing actions (e.g compile + link) to run -/// - probing the system for settings like standard library locations -/// - spawning a cc1 subprocess to compile code, with more explicit arguments -/// - in the cc1 process, assembling those arguments into a CompilerInvocation -/// which is used to configure the parser -/// -/// This simulation is lossy, e.g. in some situations one driver run would -/// result in multiple parses. (Multi-arch, CUDA, ...). -/// This function tries to select a reasonable invocation that tools should use. -/// -/// Args[0] should be the driver name, such as "clang" or "/usr/bin/g++". -/// Absolute path is preferred - this affects searching for system headers. -/// -/// May return nullptr if an invocation could not be determined. -/// See CreateInvocationOptions::RecoverOnError to try harder! -std::unique_ptr -createInvocation(ArrayRef Args, - CreateInvocationOptions Opts = {}); - -} // namespace clang - -#endif // LLVM_CLANG_DRIVER_CREATEINVOCATIONFROMARGS_H diff --git a/clang/include/clang/Driver/Driver.h b/clang/include/clang/Driver/Driver.h index 76a6c5a128efb..aa86bffb802a4 100644 --- a/clang/include/clang/Driver/Driver.h +++ b/clang/include/clang/Driver/Driver.h @@ -406,6 +406,11 @@ class Driver { SmallString<128> &CrashDiagDir); public: + + /// Takes the path to a binary that's either in bin/ or lib/ and returns + /// the path to clang's resource directory. + static std::string GetResourcesPath(StringRef BinaryPath); + Driver(StringRef ClangExecutable, StringRef TargetTriple, DiagnosticsEngine &Diags, std::string Title = "clang LLVM compiler", IntrusiveRefCntPtr VFS = nullptr); diff --git a/clang/include/clang/Frontend/ASTUnit.h b/clang/include/clang/Frontend/ASTUnit.h index 341460e1962cb..3cea159afa33c 100644 --- a/clang/include/clang/Frontend/ASTUnit.h +++ b/clang/include/clang/Frontend/ASTUnit.h @@ -22,14 +22,12 @@ #include "clang/Basic/SourceLocation.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetOptions.h" -#include "clang/Frontend/PrecompiledPreamble.h" -#include "clang/Frontend/StandaloneDiagnostic.h" #include "clang/Lex/HeaderSearchOptions.h" #include "clang/Lex/ModuleLoader.h" #include "clang/Lex/PreprocessingRecord.h" #include "clang/Sema/CodeCompleteConsumer.h" #include "clang/Serialization/ASTBitCodes.h" -#include "clang/Serialization/ASTWriter.h" +#include "clang/Frontend/PrecompiledPreamble.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/IntrusiveRefCntPtr.h" @@ -38,7 +36,6 @@ #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/iterator_range.h" -#include "llvm/Bitstream/BitstreamWriter.h" #include #include #include @@ -91,6 +88,25 @@ enum class CaptureDiagsKind { None, All, AllWithoutNonErrorsFromIncludes }; /// Utility class for loading a ASTContext from an AST file. class ASTUnit { +public: + struct StandaloneFixIt { + std::pair RemoveRange; + std::pair InsertFromRange; + std::string CodeToInsert; + bool BeforePreviousInsertions; + }; + + struct StandaloneDiagnostic { + unsigned ID; + DiagnosticsEngine::Level Level; + std::string Message; + std::string Filename; + unsigned LocOffset; + std::vector> Ranges; + std::vector FixIts; + }; + +private: std::unique_ptr LangOpts; std::unique_ptr CodeGenOpts; // FIXME: The documentation on \c LoadFrom* member functions states that the @@ -113,15 +129,7 @@ class ASTUnit { bool HadModuleLoaderFatalFailure = false; bool StorePreamblesInMemory = false; - /// Utility struct for managing ASTWriter and its associated data streams. - struct ASTWriterData { - SmallString<128> Buffer; - llvm::BitstreamWriter Stream; - ASTWriter Writer; - - ASTWriterData(ModuleCache &ModCache, const CodeGenOptions &CGOpts) - : Stream(Buffer), Writer(Stream, Buffer, ModCache, CGOpts, {}) {} - }; + struct ASTWriterData; std::unique_ptr WriterData; FileSystemOptions FileSystemOpts; @@ -263,6 +271,11 @@ class ASTUnit { static void ConfigureDiags(IntrusiveRefCntPtr Diags, ASTUnit &AST, CaptureDiagsKind CaptureDiagnostics); + void TranslateStoredDiagnostics(FileManager &FileMgr, + SourceManager &SrcMan, + const SmallVectorImpl &Diags, + SmallVectorImpl &Out); + void clearFileLevelDecls(); public: @@ -821,24 +834,65 @@ class ASTUnit { bool IncludeBriefCommentsInCodeCompletion = false, bool UserFilesAreVolatile = false); - friend std::unique_ptr CreateASTUnitFromCommandLine( + /// LoadFromCommandLine - Create an ASTUnit from a vector of command line + /// arguments, which must specify exactly one source file. + /// + /// \param ArgBegin - The beginning of the argument vector. + /// + /// \param ArgEnd - The end of the argument vector. + /// + /// \param PCHContainerOps - The PCHContainerOperations to use for loading and + /// creating modules. + /// + /// \param Diags - The diagnostics engine to use for reporting errors; its + /// lifetime is expected to extend past that of the returned ASTUnit. + /// + /// \param ResourceFilesPath - The path to the compiler resource files. + /// + /// \param StorePreamblesInMemory - Whether to store PCH in memory. If false, + /// PCH are stored in temporary files. + /// + /// \param PreambleStoragePath - The path to a directory, in which to create + /// temporary PCH files. If empty, the default system temporary directory is + /// used. This parameter is ignored if \p StorePreamblesInMemory is true. + /// + /// \param ModuleFormat - If provided, uses the specific module format. + /// + /// \param ErrAST - If non-null and parsing failed without any AST to return + /// (e.g. because the PCH could not be loaded), this accepts the ASTUnit + /// mainly to allow the caller to see the diagnostics. + /// + /// \param VFS - A llvm::vfs::FileSystem to be used for all file accesses. + /// Note that preamble is saved to a temporary directory on a RealFileSystem, + /// so in order for it to be loaded correctly, VFS should have access to + /// it(i.e., be an overlay over RealFileSystem). RealFileSystem will be used + /// if \p VFS is nullptr. + /// + // FIXME: Move OnlyLocalDecls, UseBumpAllocator to setters on the ASTUnit, we + // shouldn't need to specify them at construction time. + static std::unique_ptr LoadFromCommandLine( const char **ArgBegin, const char **ArgEnd, std::shared_ptr PCHContainerOps, std::shared_ptr DiagOpts, IntrusiveRefCntPtr Diags, StringRef ResourceFilesPath, - bool StorePreamblesInMemory, StringRef PreambleStoragePath, - bool OnlyLocalDecls, CaptureDiagsKind CaptureDiagnostics, - ArrayRef RemappedFiles, - bool RemappedFilesKeepOriginalName, - unsigned PrecompilePreambleAfterNParses, TranslationUnitKind TUKind, - bool CacheCodeCompletionResults, - bool IncludeBriefCommentsInCodeCompletion, - bool AllowPCHWithCompilerErrors, - SkipFunctionBodiesScope SkipFunctionBodies, bool SingleFileParse, - bool UserFilesAreVolatile, bool ForSerialization, - bool RetainExcludedConditionalBlocks, - std::optional ModuleFormat, std::unique_ptr *ErrAST, - IntrusiveRefCntPtr VFS); + bool StorePreamblesInMemory = false, + StringRef PreambleStoragePath = StringRef(), bool OnlyLocalDecls = false, + CaptureDiagsKind CaptureDiagnostics = CaptureDiagsKind::None, + ArrayRef RemappedFiles = {}, + bool RemappedFilesKeepOriginalName = true, + unsigned PrecompilePreambleAfterNParses = 0, + TranslationUnitKind TUKind = TU_Complete, + bool CacheCodeCompletionResults = false, + bool IncludeBriefCommentsInCodeCompletion = false, + bool AllowPCHWithCompilerErrors = false, + SkipFunctionBodiesScope SkipFunctionBodies = + SkipFunctionBodiesScope::None, + bool SingleFileParse = false, bool UserFilesAreVolatile = false, + bool ForSerialization = false, + bool RetainExcludedConditionalBlocks = false, + std::optional ModuleFormat = std::nullopt, + std::unique_ptr *ErrAST = nullptr, + IntrusiveRefCntPtr VFS = nullptr); /// Reparse the source files using the same command-line options that /// were originally used to produce this translation unit. @@ -909,44 +963,6 @@ class ASTUnit { bool serialize(raw_ostream &OS); }; -/// Diagnostic consumer that saves each diagnostic it is given. -class FilterAndStoreDiagnosticConsumer : public DiagnosticConsumer { - SmallVectorImpl *StoredDiags; - SmallVectorImpl *StandaloneDiags; - bool CaptureNonErrorsFromIncludes = true; - const LangOptions *LangOpts = nullptr; - SourceManager *SourceMgr = nullptr; - -public: - FilterAndStoreDiagnosticConsumer( - SmallVectorImpl *StoredDiags, - SmallVectorImpl *StandaloneDiags, - bool CaptureNonErrorsFromIncludes); - - void BeginSourceFile(const LangOptions &LangOpts, - const Preprocessor *PP = nullptr) override; - - void HandleDiagnostic(DiagnosticsEngine::Level Level, - const Diagnostic &Info) override; -}; - -/// RAII object that optionally captures and filters diagnostics, if -/// there is no diagnostic client to capture them already. -class CaptureDroppedDiagnostics { - DiagnosticsEngine &Diags; - FilterAndStoreDiagnosticConsumer Client; - DiagnosticConsumer *PreviousClient = nullptr; - std::unique_ptr OwningPreviousClient; - -public: - CaptureDroppedDiagnostics( - CaptureDiagsKind CaptureDiagnostics, DiagnosticsEngine &Diags, - SmallVectorImpl *StoredDiags, - SmallVectorImpl *StandaloneDiags); - - ~CaptureDroppedDiagnostics(); -}; - } // namespace clang #endif // LLVM_CLANG_FRONTEND_ASTUNIT_H diff --git a/clang/include/clang/Frontend/ChainedDiagnosticConsumer.h b/clang/include/clang/Frontend/ChainedDiagnosticConsumer.h index 839b5e7fa0a3e..ca284560754fd 100644 --- a/clang/include/clang/Frontend/ChainedDiagnosticConsumer.h +++ b/clang/include/clang/Frontend/ChainedDiagnosticConsumer.h @@ -66,6 +66,6 @@ class ChainedDiagnosticConsumer : public DiagnosticConsumer { } }; -} // namespace clang +} // end namspace clang #endif diff --git a/clang/include/clang/Frontend/CompilerInvocation.h b/clang/include/clang/Frontend/CompilerInvocation.h index 4977ddb307d21..b19a6e1a8acc3 100644 --- a/clang/include/clang/Frontend/CompilerInvocation.h +++ b/clang/include/clang/Frontend/CompilerInvocation.h @@ -299,6 +299,16 @@ class CompilerInvocation : public CompilerInvocationBase { DiagnosticsEngine &Diags, const char *Argv0 = nullptr); + /// Get the directory where the compiler headers + /// reside, relative to the compiler binary (found by the passed in + /// arguments). + /// + /// \param Argv0 - The program path (from argv[0]), for finding the builtin + /// compiler path. + /// \param MainAddr - The address of main (or some other function in the main + /// executable), for finding the builtin compiler path. + static std::string GetResourcesPath(const char *Argv0, void *MainAddr); + /// Populate \p Opts with the default set of pointer authentication-related /// options given \p LangOpts and \p Triple. /// diff --git a/clang/include/clang/Frontend/StandaloneDiagnostic.h b/clang/include/clang/Frontend/StandaloneDiagnostic.h deleted file mode 100644 index c23d5f95e0c2f..0000000000000 --- a/clang/include/clang/Frontend/StandaloneDiagnostic.h +++ /dev/null @@ -1,82 +0,0 @@ -//===--- StandaloneDiagnostic.h - Serializable Diagnostic -------*- 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 -// -//===----------------------------------------------------------------------===// -// -// A serializable diagnostic representation to retain diagnostics after their -// SourceManager has been destroyed. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_FRONTEND_STANDALONEDIAGNOSTICS_H -#define LLVM_CLANG_FRONTEND_STANDALONEDIAGNOSTICS_H - -#include "clang/Basic/DiagnosticIDs.h" -#include "clang/Basic/DiagnosticOptions.h" -#include "clang/Basic/SourceLocation.h" -#include "clang/Basic/SourceManager.h" -#include "clang/Basic/Specifiers.h" -#include "llvm/ADT/StringExtras.h" -#include -#include -#include - -namespace clang { - -/// Represents a StoredDiagnostic in a form that can be retained until after its -/// SourceManager has been destroyed. -/// -/// Source locations are stored as a combination of filename and offsets into -/// that file. -/// To report the diagnostic, it must first be translated back into a -/// StoredDiagnostic with a new associated SourceManager. -struct StandaloneDiagnostic { - /// Represents a CharSourceRange within a StandaloneDiagnostic. - struct SourceOffsetRange { - SourceOffsetRange(CharSourceRange Range, const SourceManager &SrcMgr, - const LangOptions &LangOpts); - - unsigned Begin = 0; - unsigned End = 0; - }; - - /// Represents a FixItHint within a StandaloneDiagnostic. - struct StandaloneFixIt { - StandaloneFixIt(const SourceManager &SrcMgr, const LangOptions &LangOpts, - const FixItHint &FixIt); - - SourceOffsetRange RemoveRange; - SourceOffsetRange InsertFromRange; - std::string CodeToInsert; - bool BeforePreviousInsertions; - }; - - StandaloneDiagnostic(const LangOptions &LangOpts, - const StoredDiagnostic &InDiag); - - DiagnosticsEngine::Level Level; - SrcMgr::CharacteristicKind FileKind; - unsigned ID = 0; - unsigned FileOffset = 0; - std::string Message; - std::string Filename; - std::vector Ranges; - std::vector FixIts; -}; - -/// Translates \c StandaloneDiag into a StoredDiagnostic, associating it with -/// the provided FileManager and SourceManager. -/// -/// This allows the diagnostic to be emitted using the diagnostics engine, since -/// StandaloneDiagnostics themselfs cannot be emitted directly. -StoredDiagnostic -translateStandaloneDiag(FileManager &FileMgr, SourceManager &SrcMgr, - const StandaloneDiagnostic &StandaloneDiag, - llvm::StringMap &SrcLocCache); - -} // namespace clang - -#endif // STANDALONEDIAGNOSTICS diff --git a/clang/include/clang/Frontend/Utils.h b/clang/include/clang/Frontend/Utils.h index 1c561b47b5c47..ed2703c76f18d 100644 --- a/clang/include/clang/Frontend/Utils.h +++ b/clang/include/clang/Frontend/Utils.h @@ -192,6 +192,51 @@ IntrusiveRefCntPtr createChainedIncludesSource(CompilerInstance &CI, IntrusiveRefCntPtr &OutReader); +/// Optional inputs to createInvocation. +struct CreateInvocationOptions { + /// Receives diagnostics encountered while parsing command-line flags. + /// If not provided, these are printed to stderr. + IntrusiveRefCntPtr Diags = nullptr; + /// Used e.g. to probe for system headers locations. + /// If not provided, the real filesystem is used. + /// FIXME: the driver does perform some non-virtualized IO. + IntrusiveRefCntPtr VFS = nullptr; + /// Whether to attempt to produce a non-null (possibly incorrect) invocation + /// if any errors were encountered. + /// By default, always return null on errors. + bool RecoverOnError = false; + /// Allow the driver to probe the filesystem for PCH files. + /// This is used to replace -include with -include-pch in the cc1 args. + /// FIXME: ProbePrecompiled=true is a poor, historical default. + /// It misbehaves if the PCH file is from GCC, has the wrong version, etc. + bool ProbePrecompiled = false; + /// If set, the target is populated with the cc1 args produced by the driver. + /// This may be populated even if createInvocation returns nullptr. + std::vector *CC1Args = nullptr; +}; + +/// Interpret clang arguments in preparation to parse a file. +/// +/// This simulates a number of steps Clang takes when its driver is invoked: +/// - choosing actions (e.g compile + link) to run +/// - probing the system for settings like standard library locations +/// - spawning a cc1 subprocess to compile code, with more explicit arguments +/// - in the cc1 process, assembling those arguments into a CompilerInvocation +/// which is used to configure the parser +/// +/// This simulation is lossy, e.g. in some situations one driver run would +/// result in multiple parses. (Multi-arch, CUDA, ...). +/// This function tries to select a reasonable invocation that tools should use. +/// +/// Args[0] should be the driver name, such as "clang" or "/usr/bin/g++". +/// Absolute path is preferred - this affects searching for system headers. +/// +/// May return nullptr if an invocation could not be determined. +/// See CreateInvocationOptions::ShouldRecoverOnErrors to try harder! +std::unique_ptr +createInvocation(ArrayRef Args, + CreateInvocationOptions Opts = {}); + } // namespace clang #endif // LLVM_CLANG_FRONTEND_UTILS_H diff --git a/clang/include/clang/Options/OptionUtils.h b/clang/include/clang/Options/OptionUtils.h index 02c9c27554db1..83c48bd7d6843 100644 --- a/clang/include/clang/Options/OptionUtils.h +++ b/clang/include/clang/Options/OptionUtils.h @@ -28,7 +28,6 @@ class ArgList; } // namespace llvm namespace clang { - /// Return the value of the last argument as an integer, or a default. If Diags /// is non-null, emits an error if the argument is given, but non-integral. int getLastArgIntValue(const llvm::opt::ArgList &Args, @@ -54,29 +53,6 @@ inline uint64_t getLastArgUInt64Value(const llvm::opt::ArgList &Args, return getLastArgUInt64Value(Args, Id, Default, &Diags, Base); } -// Parse -mprefer-vector-width=. Return the Value string if well-formed. -// Otherwise, return an empty string and issue a diagnosic message if needed. -StringRef parseMPreferVectorWidthOption(clang::DiagnosticsEngine &Diags, - const llvm::opt::ArgList &Args); - -// Parse -mrecip. Return the Value string if well-formed. -// Otherwise, return an empty string and issue a diagnosic message if needed. -StringRef parseMRecipOption(clang::DiagnosticsEngine &Diags, - const llvm::opt::ArgList &Args); - -/// Get the directory where the compiler headers reside, relative to the -/// compiler binary path \p BinaryPath. -std::string GetResourcesPath(StringRef BinaryPath); - -/// Get the directory where the compiler headers reside, relative to the -/// compiler binary path (found by the passed in arguments). -/// -/// \param Argv0 The program path (from argv[0]), for finding the builtin -/// compiler path. -/// \param MainAddr The address of main (or some other function in the main -/// executable), for finding the builtin compiler path. -std::string GetResourcesPath(const char *Argv0, void *MainAddr); - } // namespace clang #endif // LLVM_CLANG_OPTIONS_OPTIONUTILS_H diff --git a/clang/lib/CrossTU/CMakeLists.txt b/clang/lib/CrossTU/CMakeLists.txt index eef7a892701fb..3349fc283925d 100644 --- a/clang/lib/CrossTU/CMakeLists.txt +++ b/clang/lib/CrossTU/CMakeLists.txt @@ -9,7 +9,6 @@ add_clang_library(clangCrossTU LINK_LIBS clangAST clangBasic - clangDriver clangFrontend clangIndex ) diff --git a/clang/lib/CrossTU/CrossTranslationUnit.cpp b/clang/lib/CrossTU/CrossTranslationUnit.cpp index a3fc2cf6bfb3c..0287845a741ed 100644 --- a/clang/lib/CrossTU/CrossTranslationUnit.cpp +++ b/clang/lib/CrossTU/CrossTranslationUnit.cpp @@ -16,7 +16,6 @@ #include "clang/Basic/DiagnosticDriver.h" #include "clang/Basic/TargetInfo.h" #include "clang/CrossTU/CrossTUDiagnostic.h" -#include "clang/Driver/CreateASTUnitFromArgs.h" #include "clang/Frontend/ASTUnit.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/TextDiagnosticPrinter.h" @@ -620,7 +619,7 @@ CrossTranslationUnitContext::ASTLoader::loadFromSource( auto Diags = llvm::makeIntrusiveRefCnt(DiagID, *DiagOpts, DiagClient); - return CreateASTUnitFromCommandLine( + return ASTUnit::LoadFromCommandLine( CommandLineArgs.begin(), (CommandLineArgs.end()), CI.getPCHContainerOperations(), DiagOpts, Diags, CI.getHeaderSearchOpts().ResourceDir); diff --git a/clang/lib/Driver/CMakeLists.txt b/clang/lib/Driver/CMakeLists.txt index d987111827597..8052659e9836b 100644 --- a/clang/lib/Driver/CMakeLists.txt +++ b/clang/lib/Driver/CMakeLists.txt @@ -17,8 +17,6 @@ endif() add_clang_library(clangDriver Action.cpp Compilation.cpp - CreateASTUnitFromArgs.cpp - CreateInvocationFromArgs.cpp Distro.cpp Driver.cpp Job.cpp @@ -98,8 +96,6 @@ add_clang_library(clangDriver LINK_LIBS clangBasic - clangFrontend - clangSerialization clangLex clangOptions ${system_libs} diff --git a/clang/lib/Driver/CreateASTUnitFromArgs.cpp b/clang/lib/Driver/CreateASTUnitFromArgs.cpp deleted file mode 100644 index ea31a8ed07c5f..0000000000000 --- a/clang/lib/Driver/CreateASTUnitFromArgs.cpp +++ /dev/null @@ -1,166 +0,0 @@ -//===--- CreateASTUnitFromArgs.h - Create an ASTUnit from Args ------------===// -// -// 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 -// -//===----------------------------------------------------------------------===// -// -// Utility for creating an ASTUnit from a vector of command line arguments. -// -//===----------------------------------------------------------------------===// - -#include "clang/Driver/CreateASTUnitFromArgs.h" -#include "clang/Driver/CreateInvocationFromArgs.h" -#include "clang/Frontend/CompilerInvocation.h" -#include "clang/Lex/PreprocessorOptions.h" -#include "clang/Serialization/ModuleCache.h" -#include "llvm/Support/CrashRecoveryContext.h" - -using namespace clang; - -/// Create an ASTUnit from a vector of command line arguments, which must -/// specify exactly one source file. -/// -/// \param ArgBegin - The beginning of the argument vector. -/// -/// \param ArgEnd - The end of the argument vector. -/// -/// \param PCHContainerOps - The PCHContainerOperations to use for loading and -/// creating modules. -/// -/// \param Diags - The diagnostics engine to use for reporting errors; its -/// lifetime is expected to extend past that of the returned ASTUnit. -/// -/// \param ResourceFilesPath - The path to the compiler resource files. -/// -/// \param StorePreamblesInMemory - Whether to store PCH in memory. If false, -/// PCH are stored in temporary files. -/// -/// \param PreambleStoragePath - The path to a directory, in which to create -/// temporary PCH files. If empty, the default system temporary directory is -/// used. This parameter is ignored if \p StorePreamblesInMemory is true. -/// -/// \param ModuleFormat - If provided, uses the specific module format. -/// -/// \param ErrAST - If non-null and parsing failed without any AST to return -/// (e.g. because the PCH could not be loaded), this accepts the ASTUnit -/// mainly to allow the caller to see the diagnostics. -/// -/// \param VFS - A llvm::vfs::FileSystem to be used for all file accesses. -/// Note that preamble is saved to a temporary directory on a RealFileSystem, -/// so in order for it to be loaded correctly, VFS should have access to -/// it(i.e., be an overlay over RealFileSystem). RealFileSystem will be used -/// if \p VFS is nullptr. -/// -// FIXME: Move OnlyLocalDecls, UseBumpAllocator to setters on the ASTUnit, we -// shouldn't need to specify them at construction time. -std::unique_ptr clang::CreateASTUnitFromCommandLine( - const char **ArgBegin, const char **ArgEnd, - std::shared_ptr PCHContainerOps, - std::shared_ptr DiagOpts, - IntrusiveRefCntPtr Diags, StringRef ResourceFilesPath, - bool StorePreamblesInMemory, StringRef PreambleStoragePath, - bool OnlyLocalDecls, CaptureDiagsKind CaptureDiagnostics, - ArrayRef RemappedFiles, - bool RemappedFilesKeepOriginalName, unsigned PrecompilePreambleAfterNParses, - TranslationUnitKind TUKind, bool CacheCodeCompletionResults, - bool IncludeBriefCommentsInCodeCompletion, bool AllowPCHWithCompilerErrors, - SkipFunctionBodiesScope SkipFunctionBodies, bool SingleFileParse, - bool UserFilesAreVolatile, bool ForSerialization, - bool RetainExcludedConditionalBlocks, std::optional ModuleFormat, - std::unique_ptr *ErrAST, - IntrusiveRefCntPtr VFS) { - assert(Diags.get() && "no DiagnosticsEngine was provided"); - - // If no VFS was provided, create one that tracks the physical file system. - // If '-working-directory' was passed as an argument, 'createInvocation' will - // set this as the current working directory of the VFS. - if (!VFS) - VFS = llvm::vfs::createPhysicalFileSystem(); - - SmallVector StoredDiagnostics; - - std::shared_ptr CI; - - { - CaptureDroppedDiagnostics Capture(CaptureDiagnostics, *Diags, - &StoredDiagnostics, nullptr); - - CreateInvocationOptions CIOpts; - CIOpts.VFS = VFS; - CIOpts.Diags = Diags; - CIOpts.ProbePrecompiled = true; // FIXME: historical default. Needed? - CI = createInvocation(llvm::ArrayRef(ArgBegin, ArgEnd), std::move(CIOpts)); - if (!CI) - return nullptr; - } - - // Override any files that need remapping - for (const auto &RemappedFile : RemappedFiles) { - CI->getPreprocessorOpts().addRemappedFile(RemappedFile.first, - RemappedFile.second); - } - PreprocessorOptions &PPOpts = CI->getPreprocessorOpts(); - PPOpts.RemappedFilesKeepOriginalName = RemappedFilesKeepOriginalName; - PPOpts.AllowPCHWithCompilerErrors = AllowPCHWithCompilerErrors; - PPOpts.SingleFileParseMode = SingleFileParse; - PPOpts.RetainExcludedConditionalBlocks = RetainExcludedConditionalBlocks; - - // Override the resources path. - CI->getHeaderSearchOpts().ResourceDir = std::string(ResourceFilesPath); - - CI->getFrontendOpts().SkipFunctionBodies = - SkipFunctionBodies == SkipFunctionBodiesScope::PreambleAndMainFile; - - if (ModuleFormat) - CI->getHeaderSearchOpts().ModuleFormat = std::string(*ModuleFormat); - - // Create the AST unit. - std::unique_ptr AST; - AST.reset(new ASTUnit(false)); - AST->NumStoredDiagnosticsFromDriver = StoredDiagnostics.size(); - AST->StoredDiagnostics.swap(StoredDiagnostics); - ASTUnit::ConfigureDiags(Diags, *AST, CaptureDiagnostics); - AST->DiagOpts = DiagOpts; - AST->Diagnostics = Diags; - AST->FileSystemOpts = CI->getFileSystemOpts(); - AST->CodeGenOpts = std::make_unique(CI->getCodeGenOpts()); - VFS = createVFSFromCompilerInvocation(*CI, *Diags, VFS); - AST->FileMgr = - llvm::makeIntrusiveRefCnt(AST->FileSystemOpts, VFS); - AST->StorePreamblesInMemory = StorePreamblesInMemory; - AST->PreambleStoragePath = PreambleStoragePath; - AST->ModCache = createCrossProcessModuleCache(); - AST->OnlyLocalDecls = OnlyLocalDecls; - AST->CaptureDiagnostics = CaptureDiagnostics; - AST->TUKind = TUKind; - AST->ShouldCacheCodeCompletionResults = CacheCodeCompletionResults; - AST->IncludeBriefCommentsInCodeCompletion = - IncludeBriefCommentsInCodeCompletion; - AST->UserFilesAreVolatile = UserFilesAreVolatile; - AST->Invocation = CI; - AST->SkipFunctionBodies = SkipFunctionBodies; - if (ForSerialization) - AST->WriterData.reset( - new ASTUnit::ASTWriterData(*AST->ModCache, *AST->CodeGenOpts)); - // Zero out now to ease cleanup during crash recovery. - CI = nullptr; - Diags = nullptr; - - // Recover resources if we crash before exiting this method. - llvm::CrashRecoveryContextCleanupRegistrar ASTUnitCleanup(AST.get()); - - if (AST->LoadFromCompilerInvocation(std::move(PCHContainerOps), - PrecompilePreambleAfterNParses, VFS)) { - // Some error occurred, if caller wants to examine diagnostics, pass it the - // ASTUnit. - if (ErrAST) { - AST->StoredDiagnostics.swap(AST->FailedParseDiagnostics); - ErrAST->swap(AST); - } - return nullptr; - } - - return AST; -} diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index c6dd66d9efef3..de8d4601210ae 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -66,7 +66,6 @@ #include "clang/Driver/ToolChain.h" #include "clang/Driver/Types.h" #include "clang/Lex/DependencyDirectivesScanner.h" -#include "clang/Options/OptionUtils.h" #include "clang/Options/Options.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/STLExtras.h" @@ -126,6 +125,40 @@ template static bool usesInput(const ArgList &Args, F &&Fn) { }); } +// static +std::string Driver::GetResourcesPath(StringRef BinaryPath) { + // Since the resource directory is embedded in the module hash, it's important + // that all places that need it call this function, so that they get the + // exact same string ("a/../b/" and "b/" get different hashes, for example). + + // Dir is bin/ or lib/, depending on where BinaryPath is. + StringRef Dir = llvm::sys::path::parent_path(BinaryPath); + SmallString<128> P(Dir); + + StringRef ConfiguredResourceDir(CLANG_RESOURCE_DIR); + if (!ConfiguredResourceDir.empty()) { + // FIXME: We should fix the behavior of llvm::sys::path::append so we don't + // need to check for absolute paths here. + if (llvm::sys::path::is_absolute(ConfiguredResourceDir)) + P = ConfiguredResourceDir; + else + llvm::sys::path::append(P, ConfiguredResourceDir); + } else { + // On Windows, libclang.dll is in bin/. + // On non-Windows, libclang.so/.dylib is in lib/. + // With a static-library build of libclang, LibClangPath will contain the + // path of the embedding binary, which for LLVM binaries will be in bin/. + // ../lib gets us to lib/ in both cases. + P = llvm::sys::path::parent_path(Dir); + // This search path is also created in the COFF driver of lld, so any + // changes here also needs to happen in lld/COFF/Driver.cpp + llvm::sys::path::append(P, CLANG_INSTALL_LIBDIR_BASENAME, "clang", + CLANG_VERSION_MAJOR_STRING); + } + + return std::string(P); +} + CUIDOptions::CUIDOptions(llvm::opt::DerivedArgList &Args, const Driver &D) : UseCUID(Kind::Hash) { if (Arg *A = Args.getLastArg(options::OPT_fuse_cuid_EQ)) { diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 2f0aec3ec3c37..c5d40c9825fab 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -32,7 +32,6 @@ #include "clang/Driver/SanitizerArgs.h" #include "clang/Driver/Types.h" #include "clang/Driver/XRayArgs.h" -#include "clang/Options/OptionUtils.h" #include "clang/Options/Options.h" #include "llvm/ADT/ScopeExit.h" #include "llvm/ADT/SmallSet.h" diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp index d3539a594df11..4c036f0f8dee3 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -3398,6 +3398,169 @@ void tools::handleInterchangeLoopsArgs(const ArgList &Args, CmdArgs.push_back("-floop-interchange"); } +// Parse -mprefer-vector-width=. Return the Value string if well-formed. +// Otherwise, return an empty string and issue a diagnosic message if needed. +StringRef tools::parseMPreferVectorWidthOption(clang::DiagnosticsEngine &Diags, + const llvm::opt::ArgList &Args) { + Arg *A = Args.getLastArg(options::OPT_mprefer_vector_width_EQ); + if (!A) + return ""; + + StringRef Value = A->getValue(); + unsigned Width LLVM_ATTRIBUTE_UNINITIALIZED; + + // Only "none" and Integer values are accepted by + // -mprefer-vector-width=. + if (Value != "none" && Value.getAsInteger(10, Width)) { + Diags.Report(clang::diag::err_drv_invalid_value) + << A->getOption().getName() << Value; + return ""; + } + + return Value; +} + +// This is a helper function for validating the optional refinement step +// parameter in reciprocal argument strings. Return false if there is an error +// parsing the refinement step. Otherwise, return true and set the Position +// of the refinement step in the input string. +static bool getRefinementStep(StringRef In, clang::DiagnosticsEngine &Diags, + const Arg &A, size_t &Position) { + const char RefinementStepToken = ':'; + Position = In.find(RefinementStepToken); + if (Position != StringRef::npos) { + StringRef Option = A.getOption().getName(); + StringRef RefStep = In.substr(Position + 1); + // Allow exactly one numeric character for the additional refinement + // step parameter. This is reasonable for all currently-supported + // operations and architectures because we would expect that a larger value + // of refinement steps would cause the estimate "optimization" to + // under-perform the native operation. Also, if the estimate does not + // converge quickly, it probably will not ever converge, so further + // refinement steps will not produce a better answer. + if (RefStep.size() != 1) { + Diags.Report(diag::err_drv_invalid_value) << Option << RefStep; + return false; + } + char RefStepChar = RefStep[0]; + if (RefStepChar < '0' || RefStepChar > '9') { + Diags.Report(diag::err_drv_invalid_value) << Option << RefStep; + return false; + } + } + return true; +} + +// Parse -mrecip. Return the Value string if well-formed. +// Otherwise, return an empty string and issue a diagnosic message if needed. +StringRef tools::parseMRecipOption(clang::DiagnosticsEngine &Diags, + const ArgList &Args) { + StringRef DisabledPrefixIn = "!"; + StringRef DisabledPrefixOut = "!"; + StringRef EnabledPrefixOut = ""; + StringRef Out = ""; + + Arg *A = Args.getLastArg(options::OPT_mrecip, options::OPT_mrecip_EQ); + if (!A) + return ""; + + unsigned NumOptions = A->getNumValues(); + if (NumOptions == 0) { + // No option is the same as "all". + return "all"; + } + + // Pass through "all", "none", or "default" with an optional refinement step. + if (NumOptions == 1) { + StringRef Val = A->getValue(0); + size_t RefStepLoc; + if (!getRefinementStep(Val, Diags, *A, RefStepLoc)) + return ""; + StringRef ValBase = Val.slice(0, RefStepLoc); + if (ValBase == "all" || ValBase == "none" || ValBase == "default") { + return Val; + } + } + + // Each reciprocal type may be enabled or disabled individually. + // Check each input value for validity, concatenate them all back together, + // and pass through. + + llvm::StringMap OptionStrings; + OptionStrings.insert(std::make_pair("divd", false)); + OptionStrings.insert(std::make_pair("divf", false)); + OptionStrings.insert(std::make_pair("divh", false)); + OptionStrings.insert(std::make_pair("vec-divd", false)); + OptionStrings.insert(std::make_pair("vec-divf", false)); + OptionStrings.insert(std::make_pair("vec-divh", false)); + OptionStrings.insert(std::make_pair("sqrtd", false)); + OptionStrings.insert(std::make_pair("sqrtf", false)); + OptionStrings.insert(std::make_pair("sqrth", false)); + OptionStrings.insert(std::make_pair("vec-sqrtd", false)); + OptionStrings.insert(std::make_pair("vec-sqrtf", false)); + OptionStrings.insert(std::make_pair("vec-sqrth", false)); + + for (unsigned i = 0; i != NumOptions; ++i) { + StringRef Val = A->getValue(i); + + bool IsDisabled = Val.starts_with(DisabledPrefixIn); + // Ignore the disablement token for string matching. + if (IsDisabled) + Val = Val.substr(1); + + size_t RefStep; + if (!getRefinementStep(Val, Diags, *A, RefStep)) + return ""; + + StringRef ValBase = Val.slice(0, RefStep); + llvm::StringMap::iterator OptionIter = OptionStrings.find(ValBase); + if (OptionIter == OptionStrings.end()) { + // Try again specifying float suffix. + OptionIter = OptionStrings.find(ValBase.str() + 'f'); + if (OptionIter == OptionStrings.end()) { + // The input name did not match any known option string. + Diags.Report(diag::err_drv_unknown_argument) << Val; + return ""; + } + // The option was specified without a half or float or double suffix. + // Make sure that the double or half entry was not already specified. + // The float entry will be checked below. + if (OptionStrings[ValBase.str() + 'd'] || + OptionStrings[ValBase.str() + 'h']) { + Diags.Report(diag::err_drv_invalid_value) + << A->getOption().getName() << Val; + return ""; + } + } + + if (OptionIter->second == true) { + // Duplicate option specified. + Diags.Report(diag::err_drv_invalid_value) + << A->getOption().getName() << Val; + return ""; + } + + // Mark the matched option as found. Do not allow duplicate specifiers. + OptionIter->second = true; + + // If the precision was not specified, also mark the double and half entry + // as found. + if (ValBase.back() != 'f' && ValBase.back() != 'd' && + ValBase.back() != 'h') { + OptionStrings[ValBase.str() + 'd'] = true; + OptionStrings[ValBase.str() + 'h'] = true; + } + + // Build the output string. + StringRef Prefix = IsDisabled ? DisabledPrefixOut : EnabledPrefixOut; + Out = Args.MakeArgString(Out + Prefix + Val); + if (i != NumOptions - 1) + Out = Args.MakeArgString(Out + ","); + } + + return Out; +} + std::string tools::complexRangeKindToStr(LangOptions::ComplexRangeKind Range) { switch (Range) { case LangOptions::ComplexRangeKind::CX_Full: diff --git a/clang/lib/Driver/ToolChains/Flang.cpp b/clang/lib/Driver/ToolChains/Flang.cpp index 438de23be0103..cc4755cd6a9b0 100644 --- a/clang/lib/Driver/ToolChains/Flang.cpp +++ b/clang/lib/Driver/ToolChains/Flang.cpp @@ -11,7 +11,6 @@ #include "clang/Basic/CodeGenOptions.h" #include "clang/Driver/CommonArgs.h" -#include "clang/Options/OptionUtils.h" #include "clang/Options/Options.h" #include "llvm/Frontend/Debug/Options.h" #include "llvm/Support/Path.h" diff --git a/clang/lib/Frontend/ASTUnit.cpp b/clang/lib/Frontend/ASTUnit.cpp index e72317da64596..db13086bcb470 100644 --- a/clang/lib/Frontend/ASTUnit.cpp +++ b/clang/lib/Frontend/ASTUnit.cpp @@ -44,7 +44,6 @@ #include "clang/Frontend/FrontendOptions.h" #include "clang/Frontend/MultiplexConsumer.h" #include "clang/Frontend/PrecompiledPreamble.h" -#include "clang/Frontend/StandaloneDiagnostic.h" #include "clang/Frontend/Utils.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/HeaderSearchOptions.h" @@ -211,6 +210,15 @@ getBufferForFileHandlingRemapping(const CompilerInvocation &Invocation, return llvm::MemoryBuffer::getMemBufferCopy(Buffer->getBuffer(), FilePath); } +struct ASTUnit::ASTWriterData { + SmallString<128> Buffer; + llvm::BitstreamWriter Stream; + ASTWriter Writer; + + ASTWriterData(ModuleCache &ModCache, const CodeGenOptions &CGOpts) + : Stream(Buffer), Writer(Stream, Buffer, ModCache, CGOpts, {}) {} +}; + void ASTUnit::clearFileLevelDecls() { FileDecls.clear(); } @@ -573,24 +581,73 @@ class ASTInfoCollector : public ASTReaderListener { Counter = NewCounter; } }; -} // anonymous namespace -FilterAndStoreDiagnosticConsumer::FilterAndStoreDiagnosticConsumer( - SmallVectorImpl *StoredDiags, - SmallVectorImpl *StandaloneDiags, - bool CaptureNonErrorsFromIncludes) - : StoredDiags(StoredDiags), StandaloneDiags(StandaloneDiags), - CaptureNonErrorsFromIncludes(CaptureNonErrorsFromIncludes) { - assert((StoredDiags || StandaloneDiags) && - "No output collections were passed to StoredDiagnosticConsumer."); -} +/// Diagnostic consumer that saves each diagnostic it is given. +class FilterAndStoreDiagnosticConsumer : public DiagnosticConsumer { + SmallVectorImpl *StoredDiags; + SmallVectorImpl *StandaloneDiags; + bool CaptureNonErrorsFromIncludes = true; + const LangOptions *LangOpts = nullptr; + SourceManager *SourceMgr = nullptr; -void FilterAndStoreDiagnosticConsumer::BeginSourceFile( - const LangOptions &LangOpts, const Preprocessor *PP) { - this->LangOpts = &LangOpts; - if (PP) - SourceMgr = &PP->getSourceManager(); -} +public: + FilterAndStoreDiagnosticConsumer( + SmallVectorImpl *StoredDiags, + SmallVectorImpl *StandaloneDiags, + bool CaptureNonErrorsFromIncludes) + : StoredDiags(StoredDiags), StandaloneDiags(StandaloneDiags), + CaptureNonErrorsFromIncludes(CaptureNonErrorsFromIncludes) { + assert((StoredDiags || StandaloneDiags) && + "No output collections were passed to StoredDiagnosticConsumer."); + } + + void BeginSourceFile(const LangOptions &LangOpts, + const Preprocessor *PP = nullptr) override { + this->LangOpts = &LangOpts; + if (PP) + SourceMgr = &PP->getSourceManager(); + } + + void HandleDiagnostic(DiagnosticsEngine::Level Level, + const Diagnostic &Info) override; +}; + +/// RAII object that optionally captures and filters diagnostics, if +/// there is no diagnostic client to capture them already. +class CaptureDroppedDiagnostics { + DiagnosticsEngine &Diags; + FilterAndStoreDiagnosticConsumer Client; + DiagnosticConsumer *PreviousClient = nullptr; + std::unique_ptr OwningPreviousClient; + +public: + CaptureDroppedDiagnostics( + CaptureDiagsKind CaptureDiagnostics, DiagnosticsEngine &Diags, + SmallVectorImpl *StoredDiags, + SmallVectorImpl *StandaloneDiags) + : Diags(Diags), + Client(StoredDiags, StandaloneDiags, + CaptureDiagnostics != + CaptureDiagsKind::AllWithoutNonErrorsFromIncludes) { + if (CaptureDiagnostics != CaptureDiagsKind::None || + Diags.getClient() == nullptr) { + OwningPreviousClient = Diags.takeClient(); + PreviousClient = Diags.getClient(); + Diags.setClient(&Client, false); + } + } + + ~CaptureDroppedDiagnostics() { + if (Diags.getClient() == &Client) + Diags.setClient(PreviousClient, !!OwningPreviousClient.release()); + } +}; + +} // namespace + +static ASTUnit::StandaloneDiagnostic +makeStandaloneDiagnostic(const LangOptions &LangOpts, + const StoredDiagnostic &InDiag); static bool isInMainFile(const clang::Diagnostic &D) { if (!D.hasSourceManager() || !D.getLocation().isValid()) @@ -626,32 +683,12 @@ void FilterAndStoreDiagnosticConsumer::HandleDiagnostic( StoredDiag.emplace(Level, Info); ResultDiag = &*StoredDiag; } - StandaloneDiags->emplace_back(*LangOpts, *ResultDiag); + StandaloneDiags->push_back( + makeStandaloneDiagnostic(*LangOpts, *ResultDiag)); } } } -CaptureDroppedDiagnostics::CaptureDroppedDiagnostics( - CaptureDiagsKind CaptureDiagnostics, DiagnosticsEngine &Diags, - SmallVectorImpl *StoredDiags, - SmallVectorImpl *StandaloneDiags) - : Diags(Diags), - Client(StoredDiags, StandaloneDiags, - CaptureDiagnostics != - CaptureDiagsKind::AllWithoutNonErrorsFromIncludes) { - if (CaptureDiagnostics != CaptureDiagsKind::None || - Diags.getClient() == nullptr) { - OwningPreviousClient = Diags.takeClient(); - PreviousClient = Diags.getClient(); - Diags.setClient(&Client, false); - } -} - -CaptureDroppedDiagnostics::~CaptureDroppedDiagnostics() { - if (Diags.getClient() == &Client) - Diags.setClient(PreviousClient, !!OwningPreviousClient.release()); -} - IntrusiveRefCntPtr ASTUnit::getASTReader() const { return Reader; } @@ -1073,7 +1110,7 @@ class ASTUnitPreambleCallbacks : public PreambleCallbacks { unsigned Hash = 0; std::vector TopLevelDecls; std::vector TopLevelDeclIDs; - llvm::SmallVector PreambleDiags; + llvm::SmallVector PreambleDiags; }; } // namespace @@ -1222,17 +1259,10 @@ bool ASTUnit::Parse(std::shared_ptr PCHContainerOps, if (!Act->BeginSourceFile(*Clang, Clang->getFrontendOpts().Inputs[0])) return true; - if (SavedMainFileBuffer) { - StoredDiagnostics.clear(); - StoredDiagnostics.reserve(PreambleDiagnostics.size()); - llvm::transform(std::move(PreambleDiagnostics), - std::back_inserter(StoredDiagnostics), - [&](auto &&StandaloneDiag) { - return translateStandaloneDiag( - getFileManager(), getSourceManager(), - std::move(StandaloneDiag), PreambleSrcLocCache); - }); - } else + if (SavedMainFileBuffer) + TranslateStoredDiagnostics(getFileManager(), getSourceManager(), + PreambleDiagnostics, StoredDiagnostics); + else PreambleSrcLocCache.clear(); if (llvm::Error Err = Act->Execute()) { @@ -1251,6 +1281,51 @@ bool ASTUnit::Parse(std::shared_ptr PCHContainerOps, return false; } +static std::pair +makeStandaloneRange(CharSourceRange Range, const SourceManager &SM, + const LangOptions &LangOpts) { + CharSourceRange FileRange = Lexer::makeFileCharRange(Range, SM, LangOpts); + unsigned Offset = SM.getFileOffset(FileRange.getBegin()); + unsigned EndOffset = SM.getFileOffset(FileRange.getEnd()); + return std::make_pair(Offset, EndOffset); +} + +static ASTUnit::StandaloneFixIt makeStandaloneFixIt(const SourceManager &SM, + const LangOptions &LangOpts, + const FixItHint &InFix) { + ASTUnit::StandaloneFixIt OutFix; + OutFix.RemoveRange = makeStandaloneRange(InFix.RemoveRange, SM, LangOpts); + OutFix.InsertFromRange = makeStandaloneRange(InFix.InsertFromRange, SM, + LangOpts); + OutFix.CodeToInsert = InFix.CodeToInsert; + OutFix.BeforePreviousInsertions = InFix.BeforePreviousInsertions; + return OutFix; +} + +static ASTUnit::StandaloneDiagnostic +makeStandaloneDiagnostic(const LangOptions &LangOpts, + const StoredDiagnostic &InDiag) { + ASTUnit::StandaloneDiagnostic OutDiag; + OutDiag.ID = InDiag.getID(); + OutDiag.Level = InDiag.getLevel(); + OutDiag.Message = std::string(InDiag.getMessage()); + OutDiag.LocOffset = 0; + if (InDiag.getLocation().isInvalid()) + return OutDiag; + const SourceManager &SM = InDiag.getLocation().getManager(); + SourceLocation FileLoc = SM.getFileLoc(InDiag.getLocation()); + OutDiag.Filename = std::string(SM.getFilename(FileLoc)); + if (OutDiag.Filename.empty()) + return OutDiag; + OutDiag.LocOffset = SM.getFileOffset(FileLoc); + for (const auto &Range : InDiag.getRanges()) + OutDiag.Ranges.push_back(makeStandaloneRange(Range, SM, LangOpts)); + for (const auto &FixIt : InDiag.getFixIts()) + OutDiag.FixIts.push_back(makeStandaloneFixIt(SM, LangOpts, FixIt)); + + return OutDiag; +} + /// Attempt to build or re-use a precompiled preamble when (re-)parsing /// the source file. /// @@ -1705,6 +1780,116 @@ std::unique_ptr ASTUnit::LoadFromCompilerInvocation( return AST; } +std::unique_ptr ASTUnit::LoadFromCommandLine( + const char **ArgBegin, const char **ArgEnd, + std::shared_ptr PCHContainerOps, + std::shared_ptr DiagOpts, + IntrusiveRefCntPtr Diags, StringRef ResourceFilesPath, + bool StorePreamblesInMemory, StringRef PreambleStoragePath, + bool OnlyLocalDecls, CaptureDiagsKind CaptureDiagnostics, + ArrayRef RemappedFiles, bool RemappedFilesKeepOriginalName, + unsigned PrecompilePreambleAfterNParses, TranslationUnitKind TUKind, + bool CacheCodeCompletionResults, bool IncludeBriefCommentsInCodeCompletion, + bool AllowPCHWithCompilerErrors, SkipFunctionBodiesScope SkipFunctionBodies, + bool SingleFileParse, bool UserFilesAreVolatile, bool ForSerialization, + bool RetainExcludedConditionalBlocks, std::optional ModuleFormat, + std::unique_ptr *ErrAST, + IntrusiveRefCntPtr VFS) { + assert(Diags.get() && "no DiagnosticsEngine was provided"); + + // If no VFS was provided, create one that tracks the physical file system. + // If '-working-directory' was passed as an argument, 'createInvocation' will + // set this as the current working directory of the VFS. + if (!VFS) + VFS = llvm::vfs::createPhysicalFileSystem(); + + SmallVector StoredDiagnostics; + + std::shared_ptr CI; + + { + CaptureDroppedDiagnostics Capture(CaptureDiagnostics, *Diags, + &StoredDiagnostics, nullptr); + + CreateInvocationOptions CIOpts; + CIOpts.VFS = VFS; + CIOpts.Diags = Diags; + CIOpts.ProbePrecompiled = true; // FIXME: historical default. Needed? + CI = createInvocation(llvm::ArrayRef(ArgBegin, ArgEnd), std::move(CIOpts)); + if (!CI) + return nullptr; + } + + // Override any files that need remapping + for (const auto &RemappedFile : RemappedFiles) { + CI->getPreprocessorOpts().addRemappedFile(RemappedFile.first, + RemappedFile.second); + } + PreprocessorOptions &PPOpts = CI->getPreprocessorOpts(); + PPOpts.RemappedFilesKeepOriginalName = RemappedFilesKeepOriginalName; + PPOpts.AllowPCHWithCompilerErrors = AllowPCHWithCompilerErrors; + PPOpts.SingleFileParseMode = SingleFileParse; + PPOpts.RetainExcludedConditionalBlocks = RetainExcludedConditionalBlocks; + + // Override the resources path. + CI->getHeaderSearchOpts().ResourceDir = std::string(ResourceFilesPath); + + CI->getFrontendOpts().SkipFunctionBodies = + SkipFunctionBodies == SkipFunctionBodiesScope::PreambleAndMainFile; + + if (ModuleFormat) + CI->getHeaderSearchOpts().ModuleFormat = std::string(*ModuleFormat); + + // Create the AST unit. + std::unique_ptr AST; + AST.reset(new ASTUnit(false)); + AST->NumStoredDiagnosticsFromDriver = StoredDiagnostics.size(); + AST->StoredDiagnostics.swap(StoredDiagnostics); + ConfigureDiags(Diags, *AST, CaptureDiagnostics); + AST->DiagOpts = DiagOpts; + AST->Diagnostics = Diags; + AST->FileSystemOpts = CI->getFileSystemOpts(); + AST->CodeGenOpts = std::make_unique(CI->getCodeGenOpts()); + VFS = createVFSFromCompilerInvocation(*CI, *Diags, VFS); + AST->FileMgr = + llvm::makeIntrusiveRefCnt(AST->FileSystemOpts, VFS); + AST->StorePreamblesInMemory = StorePreamblesInMemory; + AST->PreambleStoragePath = PreambleStoragePath; + AST->ModCache = createCrossProcessModuleCache(); + AST->OnlyLocalDecls = OnlyLocalDecls; + AST->CaptureDiagnostics = CaptureDiagnostics; + AST->TUKind = TUKind; + AST->ShouldCacheCodeCompletionResults = CacheCodeCompletionResults; + AST->IncludeBriefCommentsInCodeCompletion + = IncludeBriefCommentsInCodeCompletion; + AST->UserFilesAreVolatile = UserFilesAreVolatile; + AST->Invocation = CI; + AST->SkipFunctionBodies = SkipFunctionBodies; + if (ForSerialization) + AST->WriterData.reset(new ASTWriterData(*AST->ModCache, *AST->CodeGenOpts)); + // Zero out now to ease cleanup during crash recovery. + CI = nullptr; + Diags = nullptr; + + // Recover resources if we crash before exiting this method. + llvm::CrashRecoveryContextCleanupRegistrar + ASTUnitCleanup(AST.get()); + + if (AST->LoadFromCompilerInvocation(std::move(PCHContainerOps), + PrecompilePreambleAfterNParses, + VFS)) { + // Some error occurred, if caller wants to examine diagnostics, pass it the + // ASTUnit. + if (ErrAST) { + AST->StoredDiagnostics.swap(AST->FailedParseDiagnostics); + ErrAST->swap(AST); + } + return nullptr; + } + + return AST; +} + bool ASTUnit::Reparse(std::shared_ptr PCHContainerOps, ArrayRef RemappedFiles, IntrusiveRefCntPtr VFS) { @@ -2223,6 +2408,65 @@ bool ASTUnit::serialize(raw_ostream &OS) { return serializeUnit(Writer, Buffer, getSema(), OS); } +void ASTUnit::TranslateStoredDiagnostics( + FileManager &FileMgr, + SourceManager &SrcMgr, + const SmallVectorImpl &Diags, + SmallVectorImpl &Out) { + // Map the standalone diagnostic into the new source manager. We also need to + // remap all the locations to the new view. This includes the diag location, + // any associated source ranges, and the source ranges of associated fix-its. + // FIXME: There should be a cleaner way to do this. + SmallVector Result; + Result.reserve(Diags.size()); + + for (const auto &SD : Diags) { + // Rebuild the StoredDiagnostic. + if (SD.Filename.empty()) + continue; + auto FE = FileMgr.getOptionalFileRef(SD.Filename); + if (!FE) + continue; + SourceLocation FileLoc; + auto ItFileID = PreambleSrcLocCache.find(SD.Filename); + if (ItFileID == PreambleSrcLocCache.end()) { + FileID FID = SrcMgr.translateFile(*FE); + FileLoc = SrcMgr.getLocForStartOfFile(FID); + PreambleSrcLocCache[SD.Filename] = FileLoc; + } else { + FileLoc = ItFileID->getValue(); + } + + if (FileLoc.isInvalid()) + continue; + SourceLocation L = FileLoc.getLocWithOffset(SD.LocOffset); + FullSourceLoc Loc(L, SrcMgr); + + SmallVector Ranges; + Ranges.reserve(SD.Ranges.size()); + for (const auto &Range : SD.Ranges) { + SourceLocation BL = FileLoc.getLocWithOffset(Range.first); + SourceLocation EL = FileLoc.getLocWithOffset(Range.second); + Ranges.push_back(CharSourceRange::getCharRange(BL, EL)); + } + + SmallVector FixIts; + FixIts.reserve(SD.FixIts.size()); + for (const auto &FixIt : SD.FixIts) { + FixIts.push_back(FixItHint()); + FixItHint &FH = FixIts.back(); + FH.CodeToInsert = FixIt.CodeToInsert; + SourceLocation BL = FileLoc.getLocWithOffset(FixIt.RemoveRange.first); + SourceLocation EL = FileLoc.getLocWithOffset(FixIt.RemoveRange.second); + FH.RemoveRange = CharSourceRange::getCharRange(BL, EL); + } + + Result.push_back(StoredDiagnostic(SD.Level, SD.ID, + SD.Message, Loc, Ranges, FixIts)); + } + Result.swap(Out); +} + void ASTUnit::addFileLevelDecl(Decl *D) { assert(D); diff --git a/clang/lib/Frontend/CMakeLists.txt b/clang/lib/Frontend/CMakeLists.txt index 634f239933605..dac9e0d26f393 100644 --- a/clang/lib/Frontend/CMakeLists.txt +++ b/clang/lib/Frontend/CMakeLists.txt @@ -17,6 +17,7 @@ add_clang_library(clangFrontend ChainedIncludesSource.cpp CompilerInstance.cpp CompilerInvocation.cpp + CreateInvocationFromCommandLine.cpp DependencyFile.cpp DependencyGraph.cpp DiagnosticRenderer.cpp @@ -35,7 +36,6 @@ add_clang_library(clangFrontend SARIFDiagnosticPrinter.cpp SerializedDiagnosticPrinter.cpp SerializedDiagnosticReader.cpp - StandaloneDiagnostic.cpp TestModuleFileExtension.cpp TextDiagnostic.cpp TextDiagnosticBuffer.cpp @@ -51,6 +51,7 @@ add_clang_library(clangFrontend clangAPINotes clangAST clangBasic + clangDriver clangOptions clangEdit clangLex diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 5f1c7afdc80a3..a7bb71565f7f9 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -3272,6 +3272,13 @@ static bool ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, return Diags.getNumErrors() == NumErrorsBefore; } +std::string CompilerInvocation::GetResourcesPath(const char *Argv0, + void *MainAddr) { + std::string ClangExecutable = + llvm::sys::fs::getMainExecutable(Argv0, MainAddr); + return Driver::GetResourcesPath(ClangExecutable); +} + static void GenerateHeaderSearchArgs(const HeaderSearchOptions &Opts, ArgumentConsumer Consumer) { const HeaderSearchOptions *HeaderSearchOpts = &Opts; diff --git a/clang/lib/Driver/CreateInvocationFromArgs.cpp b/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp similarity index 93% rename from clang/lib/Driver/CreateInvocationFromArgs.cpp rename to clang/lib/Frontend/CreateInvocationFromCommandLine.cpp index 516d61f1a1159..9db594bed1538 100644 --- a/clang/lib/Driver/CreateInvocationFromArgs.cpp +++ b/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp @@ -1,4 +1,4 @@ -//===--- CreateInvocationFromArgs.h - CompilerInvocation from Args --------===// +//===--- CreateInvocationFromCommandLine.cpp - CompilerInvocation from Args ==// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -10,9 +10,9 @@ // //===----------------------------------------------------------------------===// -#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Basic/DiagnosticFrontend.h" #include "clang/Basic/DiagnosticOptions.h" +#include "clang/Driver/Action.h" #include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" #include "clang/Driver/Tool.h" @@ -24,13 +24,12 @@ #include "llvm/Option/ArgList.h" #include "llvm/Support/VirtualFileSystem.h" #include "llvm/TargetParser/Host.h" - +using namespace clang; using namespace llvm::opt; -namespace clang { - std::unique_ptr -createInvocation(ArrayRef ArgList, CreateInvocationOptions Opts) { +clang::createInvocation(ArrayRef ArgList, + CreateInvocationOptions Opts) { assert(!ArgList.empty()); std::optional LocalDiagOpts; IntrusiveRefCntPtr Diags; @@ -79,7 +78,7 @@ createInvocation(ArrayRef ArgList, CreateInvocationOptions Opts) { const driver::JobList &Jobs = C->getJobs(); bool OffloadCompilation = false; if (Jobs.size() > 1) { - for (auto &A : C->getActions()) { + for (auto &A : C->getActions()){ // On MacOSX real actions may end up being wrapped in BindArchAction if (isa(A)) A = *A->input_begin(); @@ -115,5 +114,3 @@ createInvocation(ArrayRef ArgList, CreateInvocationOptions Opts) { return nullptr; return CI; } - -} // namespace clang diff --git a/clang/lib/Frontend/StandaloneDiagnostic.cpp b/clang/lib/Frontend/StandaloneDiagnostic.cpp deleted file mode 100644 index 4f19c91b7d266..0000000000000 --- a/clang/lib/Frontend/StandaloneDiagnostic.cpp +++ /dev/null @@ -1,117 +0,0 @@ -//===--- StandaloneDiagnostic.h - Serializable Diagnostic ------------- ---===// -// -// 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/Frontend/StandaloneDiagnostic.h" -#include "clang/Lex/Lexer.h" - -namespace clang { - -StandaloneDiagnostic::SourceOffsetRange::SourceOffsetRange( - CharSourceRange Range, const SourceManager &SrcMgr, - const LangOptions &LangOpts) { - const auto FileRange = Lexer::makeFileCharRange(Range, SrcMgr, LangOpts); - Begin = SrcMgr.getFileOffset(FileRange.getBegin()); - End = SrcMgr.getFileOffset(FileRange.getEnd()); -} - -StandaloneDiagnostic::StandaloneFixIt::StandaloneFixIt( - const SourceManager &SrcMgr, const LangOptions &LangOpts, - const FixItHint &FixIt) - : RemoveRange(FixIt.RemoveRange, SrcMgr, LangOpts), - InsertFromRange(FixIt.InsertFromRange, SrcMgr, LangOpts), - CodeToInsert(FixIt.CodeToInsert), - BeforePreviousInsertions(FixIt.BeforePreviousInsertions) {} - -StandaloneDiagnostic::StandaloneDiagnostic(const LangOptions &LangOpts, - const StoredDiagnostic &InDiag) - : Level(InDiag.getLevel()), ID(InDiag.getID()), - Message(InDiag.getMessage()) { - const FullSourceLoc &FullLoc = InDiag.getLocation(); - // This is not an invalid diagnostic; invalid SourceLocations are used to - // represent diagnostics without a specific SourceLocation. - if (FullLoc.isInvalid()) - return; - - const auto &SrcMgr = FullLoc.getManager(); - FileKind = SrcMgr.getFileCharacteristic(static_cast(FullLoc)); - const auto FileLoc = SrcMgr.getFileLoc(static_cast(FullLoc)); - FileOffset = SrcMgr.getFileOffset(FileLoc); - Filename = SrcMgr.getFilename(FileLoc); - assert(!Filename.empty() && "diagnostic with location has no source file?"); - - Ranges.reserve(InDiag.getRanges().size()); - for (const auto &Range : InDiag.getRanges()) - Ranges.emplace_back(Range, SrcMgr, LangOpts); - - FixIts.reserve(InDiag.getFixIts().size()); - for (const auto &FixIt : InDiag.getFixIts()) - FixIts.emplace_back(SrcMgr, LangOpts, FixIt); -} - -StoredDiagnostic -translateStandaloneDiag(FileManager &FileMgr, SourceManager &SrcMgr, - const StandaloneDiagnostic &StandaloneDiag, - llvm::StringMap &SrcLocCache) { - const auto FileRef = FileMgr.getOptionalFileRef(StandaloneDiag.Filename); - if (!FileRef) - return StoredDiagnostic(StandaloneDiag.Level, StandaloneDiag.ID, - StandaloneDiag.Message); - - // Try to get FileLoc from cache first - SourceLocation FileLoc; - auto It = SrcLocCache.find(StandaloneDiag.Filename); - if (It != SrcLocCache.end()) { - FileLoc = It->getValue(); - } - - // Cache miss - compute and cache the location - if (FileLoc.isInvalid()) { - const auto FileID = - SrcMgr.getOrCreateFileID(*FileRef, StandaloneDiag.FileKind); - FileLoc = SrcMgr.getLocForStartOfFile(FileID); - - if (FileLoc.isInvalid()) - return StoredDiagnostic(StandaloneDiag.Level, StandaloneDiag.ID, - StandaloneDiag.Message); - - SrcLocCache[StandaloneDiag.Filename] = FileLoc; - } - - const auto DiagLoc = FileLoc.getLocWithOffset(StandaloneDiag.FileOffset); - const FullSourceLoc Loc(DiagLoc, SrcMgr); - - auto ConvertOffsetRange = - [&](const StandaloneDiagnostic::SourceOffsetRange &Range) { - return CharSourceRange( - SourceRange(FileLoc.getLocWithOffset(Range.Begin), - FileLoc.getLocWithOffset(Range.End)), - /*IsTokenRange*/ false); - }; - - SmallVector TranslatedRanges; - TranslatedRanges.reserve(StandaloneDiag.Ranges.size()); - transform(StandaloneDiag.Ranges, std::back_inserter(TranslatedRanges), - ConvertOffsetRange); - - SmallVector TranslatedFixIts; - TranslatedFixIts.reserve(StandaloneDiag.FixIts.size()); - for (const auto &FixIt : StandaloneDiag.FixIts) { - FixItHint TranslatedFixIt; - TranslatedFixIt.CodeToInsert = FixIt.CodeToInsert; - TranslatedFixIt.RemoveRange = ConvertOffsetRange(FixIt.RemoveRange); - TranslatedFixIt.InsertFromRange = ConvertOffsetRange(FixIt.InsertFromRange); - TranslatedFixIt.BeforePreviousInsertions = FixIt.BeforePreviousInsertions; - TranslatedFixIts.push_back(std::move(TranslatedFixIt)); - } - - return StoredDiagnostic(StandaloneDiag.Level, StandaloneDiag.ID, - StandaloneDiag.Message, Loc, TranslatedRanges, - TranslatedFixIts); -} - -} // namespace clang diff --git a/clang/lib/Interpreter/CMakeLists.txt b/clang/lib/Interpreter/CMakeLists.txt index 9a597146b2fc4..37faa0302caaa 100644 --- a/clang/lib/Interpreter/CMakeLists.txt +++ b/clang/lib/Interpreter/CMakeLists.txt @@ -46,7 +46,6 @@ add_clang_library(clangInterpreter clangFrontend clangFrontendTool clangLex - clangOptions clangParse clangSema clangSerialization diff --git a/clang/lib/Interpreter/Interpreter.cpp b/clang/lib/Interpreter/Interpreter.cpp index 6cbc5e9910bcc..7764fa7dc92b9 100644 --- a/clang/lib/Interpreter/Interpreter.cpp +++ b/clang/lib/Interpreter/Interpreter.cpp @@ -42,7 +42,6 @@ #include "clang/Interpreter/Interpreter.h" #include "clang/Interpreter/Value.h" #include "clang/Lex/PreprocessorOptions.h" -#include "clang/Options/OptionUtils.h" #include "clang/Options/Options.h" #include "clang/Sema/Lookup.h" #include "clang/Serialization/ObjectFilePCHContainerReader.h" @@ -106,7 +105,7 @@ CreateCI(const llvm::opt::ArgStringList &Argv) { if (Clang->getHeaderSearchOpts().UseBuiltinIncludes && Clang->getHeaderSearchOpts().ResourceDir.empty()) Clang->getHeaderSearchOpts().ResourceDir = - GetResourcesPath(Argv[0], nullptr); + CompilerInvocation::GetResourcesPath(Argv[0], nullptr); Clang->createVirtualFileSystem(); diff --git a/clang/lib/Options/OptionUtils.cpp b/clang/lib/Options/OptionUtils.cpp index e5aefa012f679..fcafd3c83c6b3 100644 --- a/clang/lib/Options/OptionUtils.cpp +++ b/clang/lib/Options/OptionUtils.cpp @@ -9,12 +9,7 @@ #include "clang/Options/OptionUtils.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/DiagnosticDriver.h" -#include "clang/Basic/Version.h" -#include "clang/Config/config.h" -#include "clang/Options/Options.h" #include "llvm/Option/ArgList.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/Path.h" using namespace clang; using namespace llvm::opt; @@ -36,211 +31,17 @@ IntTy getLastArgIntValueImpl(const ArgList &Args, OptSpecifier Id, } } // namespace -int clang::getLastArgIntValue(const ArgList &Args, OptSpecifier Id, int Default, - DiagnosticsEngine *Diags, unsigned Base) { +namespace clang { + +int getLastArgIntValue(const ArgList &Args, OptSpecifier Id, int Default, + DiagnosticsEngine *Diags, unsigned Base) { return getLastArgIntValueImpl(Args, Id, Default, Diags, Base); } -uint64_t clang::getLastArgUInt64Value(const ArgList &Args, OptSpecifier Id, - uint64_t Default, - DiagnosticsEngine *Diags, unsigned Base) { +uint64_t getLastArgUInt64Value(const ArgList &Args, OptSpecifier Id, + uint64_t Default, DiagnosticsEngine *Diags, + unsigned Base) { return getLastArgIntValueImpl(Args, Id, Default, Diags, Base); } -StringRef clang::parseMPreferVectorWidthOption(clang::DiagnosticsEngine &Diags, - const llvm::opt::ArgList &Args) { - const Arg *A = Args.getLastArg(options::OPT_mprefer_vector_width_EQ); - if (!A) - return ""; - - StringRef Value = A->getValue(); - unsigned Width LLVM_ATTRIBUTE_UNINITIALIZED; - - // Only "none" and Integer values are accepted by - // -mprefer-vector-width=. - if (Value != "none" && Value.getAsInteger(10, Width)) { - Diags.Report(clang::diag::err_drv_invalid_value) - << A->getOption().getName() << Value; - return ""; - } - - return Value; -} - -// This is a helper function for validating the optional refinement step -// parameter in reciprocal argument strings. Return false if there is an error -// parsing the refinement step. Otherwise, return true and set the Position -// of the refinement step in the input string. -static bool getRefinementStep(StringRef In, clang::DiagnosticsEngine &Diags, - const Arg &A, size_t &Position) { - const char RefinementStepToken = ':'; - Position = In.find(RefinementStepToken); - if (Position != StringRef::npos) { - StringRef Option = A.getOption().getName(); - StringRef RefStep = In.substr(Position + 1); - // Allow exactly one numeric character for the additional refinement - // step parameter. This is reasonable for all currently-supported - // operations and architectures because we would expect that a larger value - // of refinement steps would cause the estimate "optimization" to - // under-perform the native operation. Also, if the estimate does not - // converge quickly, it probably will not ever converge, so further - // refinement steps will not produce a better answer. - if (RefStep.size() != 1) { - Diags.Report(diag::err_drv_invalid_value) << Option << RefStep; - return false; - } - char RefStepChar = RefStep[0]; - if (RefStepChar < '0' || RefStepChar > '9') { - Diags.Report(diag::err_drv_invalid_value) << Option << RefStep; - return false; - } - } - return true; -} - -StringRef clang::parseMRecipOption(clang::DiagnosticsEngine &Diags, - const ArgList &Args) { - StringRef DisabledPrefixIn = "!"; - StringRef DisabledPrefixOut = "!"; - StringRef EnabledPrefixOut = ""; - StringRef Out = ""; - - const Arg *A = Args.getLastArg(options::OPT_mrecip, options::OPT_mrecip_EQ); - if (!A) - return ""; - - const unsigned NumOptions = A->getNumValues(); - if (NumOptions == 0) { - // No option is the same as "all". - return "all"; - } - - // Pass through "all", "none", or "default" with an optional refinement step. - if (NumOptions == 1) { - StringRef Val = A->getValue(0); - size_t RefStepLoc; - if (!getRefinementStep(Val, Diags, *A, RefStepLoc)) - return ""; - StringRef ValBase = Val.slice(0, RefStepLoc); - if (ValBase == "all" || ValBase == "none" || ValBase == "default") { - return Val; - } - } - - // Each reciprocal type may be enabled or disabled individually. - // Check each input value for validity, concatenate them all back together, - // and pass through. - - llvm::StringMap OptionStrings; - OptionStrings.insert(std::make_pair("divd", false)); - OptionStrings.insert(std::make_pair("divf", false)); - OptionStrings.insert(std::make_pair("divh", false)); - OptionStrings.insert(std::make_pair("vec-divd", false)); - OptionStrings.insert(std::make_pair("vec-divf", false)); - OptionStrings.insert(std::make_pair("vec-divh", false)); - OptionStrings.insert(std::make_pair("sqrtd", false)); - OptionStrings.insert(std::make_pair("sqrtf", false)); - OptionStrings.insert(std::make_pair("sqrth", false)); - OptionStrings.insert(std::make_pair("vec-sqrtd", false)); - OptionStrings.insert(std::make_pair("vec-sqrtf", false)); - OptionStrings.insert(std::make_pair("vec-sqrth", false)); - - for (unsigned i = 0; i != NumOptions; ++i) { - StringRef Val = A->getValue(i); - - bool IsDisabled = Val.starts_with(DisabledPrefixIn); - // Ignore the disablement token for string matching. - if (IsDisabled) - Val = Val.substr(1); - - size_t RefStep; - if (!getRefinementStep(Val, Diags, *A, RefStep)) - return ""; - - StringRef ValBase = Val.slice(0, RefStep); - llvm::StringMap::iterator OptionIter = OptionStrings.find(ValBase); - if (OptionIter == OptionStrings.end()) { - // Try again specifying float suffix. - OptionIter = OptionStrings.find(ValBase.str() + 'f'); - if (OptionIter == OptionStrings.end()) { - // The input name did not match any known option string. - Diags.Report(diag::err_drv_unknown_argument) << Val; - return ""; - } - // The option was specified without a half or float or double suffix. - // Make sure that the double or half entry was not already specified. - // The float entry will be checked below. - if (OptionStrings[ValBase.str() + 'd'] || - OptionStrings[ValBase.str() + 'h']) { - Diags.Report(diag::err_drv_invalid_value) - << A->getOption().getName() << Val; - return ""; - } - } - - if (OptionIter->second == true) { - // Duplicate option specified. - Diags.Report(diag::err_drv_invalid_value) - << A->getOption().getName() << Val; - return ""; - } - - // Mark the matched option as found. Do not allow duplicate specifiers. - OptionIter->second = true; - - // If the precision was not specified, also mark the double and half entry - // as found. - if (ValBase.back() != 'f' && ValBase.back() != 'd' && - ValBase.back() != 'h') { - OptionStrings[ValBase.str() + 'd'] = true; - OptionStrings[ValBase.str() + 'h'] = true; - } - - // Build the output string. - StringRef Prefix = IsDisabled ? DisabledPrefixOut : EnabledPrefixOut; - Out = Args.MakeArgString(Out + Prefix + Val); - if (i != NumOptions - 1) - Out = Args.MakeArgString(Out + ","); - } - - return Out; -} - -std::string clang::GetResourcesPath(StringRef BinaryPath) { - // Since the resource directory is embedded in the module hash, it's important - // that all places that need it call this function, so that they get the - // exact same string ("a/../b/" and "b/" get different hashes, for example). - - // Dir is bin/ or lib/, depending on where BinaryPath is. - StringRef Dir = llvm::sys::path::parent_path(BinaryPath); - SmallString<128> P(Dir); - - StringRef ConfiguredResourceDir(CLANG_RESOURCE_DIR); - if (!ConfiguredResourceDir.empty()) { - // FIXME: We should fix the behavior of llvm::sys::path::append so we don't - // need to check for absolute paths here. - if (llvm::sys::path::is_absolute(ConfiguredResourceDir)) - P = ConfiguredResourceDir; - else - llvm::sys::path::append(P, ConfiguredResourceDir); - } else { - // On Windows, libclang.dll is in bin/. - // On non-Windows, libclang.so/.dylib is in lib/. - // With a static-library build of libclang, LibClangPath will contain the - // path of the embedding binary, which for LLVM binaries will be in bin/. - // ../lib gets us to lib/ in both cases. - P = llvm::sys::path::parent_path(Dir); - // This search path is also created in the COFF driver of lld, so any - // changes here also needs to happen in lld/COFF/Driver.cpp - llvm::sys::path::append(P, CLANG_INSTALL_LIBDIR_BASENAME, "clang", - CLANG_VERSION_MAJOR_STRING); - } - - return std::string(P); -} - -std::string clang::GetResourcesPath(const char *Argv0, void *MainAddr) { - const std::string ClangExecutable = - llvm::sys::fs::getMainExecutable(Argv0, MainAddr); - return GetResourcesPath(ClangExecutable); -} +} // namespace clang diff --git a/clang/lib/Tooling/Tooling.cpp b/clang/lib/Tooling/Tooling.cpp index 1d55f615de8a9..9bae12454d2dc 100644 --- a/clang/lib/Tooling/Tooling.cpp +++ b/clang/lib/Tooling/Tooling.cpp @@ -31,7 +31,6 @@ #include "clang/Frontend/TextDiagnosticPrinter.h" #include "clang/Lex/HeaderSearchOptions.h" #include "clang/Lex/PreprocessorOptions.h" -#include "clang/Options/OptionUtils.h" #include "clang/Options/Options.h" #include "clang/Tooling/ArgumentsAdjusters.h" #include "clang/Tooling/CompilationDatabase.h" @@ -511,7 +510,8 @@ static void injectResourceDir(CommandLineArguments &Args, const char *Argv0, // If there's no override in place add our resource dir. Args = getInsertArgumentAdjuster( - ("-resource-dir=" + GetResourcesPath(Argv0, MainAddr)).c_str())(Args, ""); + ("-resource-dir=" + CompilerInvocation::GetResourcesPath(Argv0, MainAddr)) + .c_str())(Args, ""); } int ClangTool::run(ToolAction *Action) { diff --git a/clang/tools/c-index-test/CMakeLists.txt b/clang/tools/c-index-test/CMakeLists.txt index 41e80e66ffa7a..24e7c9692ca56 100644 --- a/clang/tools/c-index-test/CMakeLists.txt +++ b/clang/tools/c-index-test/CMakeLists.txt @@ -27,7 +27,6 @@ else() libclang clangAST clangBasic - clangDriver clangFrontend clangIndex clangSerialization diff --git a/clang/tools/c-index-test/core_main.cpp b/clang/tools/c-index-test/core_main.cpp index c67479fd130ca..5a3086a7fc08f 100644 --- a/clang/tools/c-index-test/core_main.cpp +++ b/clang/tools/c-index-test/core_main.cpp @@ -8,7 +8,6 @@ #include "clang/AST/Mangle.h" #include "clang/Basic/LangOptions.h" -#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/ASTUnit.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/CompilerInvocation.h" diff --git a/clang/tools/diagtool/CMakeLists.txt b/clang/tools/diagtool/CMakeLists.txt index 09b2a81790f87..b49619c075c73 100644 --- a/clang/tools/diagtool/CMakeLists.txt +++ b/clang/tools/diagtool/CMakeLists.txt @@ -15,6 +15,5 @@ add_clang_tool(diagtool clang_target_link_libraries(diagtool PRIVATE clangBasic - clangDriver clangFrontend ) diff --git a/clang/tools/diagtool/ShowEnabledWarnings.cpp b/clang/tools/diagtool/ShowEnabledWarnings.cpp index 5b25e656dafa4..bea0288c09358 100644 --- a/clang/tools/diagtool/ShowEnabledWarnings.cpp +++ b/clang/tools/diagtool/ShowEnabledWarnings.cpp @@ -9,7 +9,6 @@ #include "DiagTool.h" #include "DiagnosticNames.h" #include "clang/Basic/LLVM.h" -#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/TextDiagnosticBuffer.h" #include "clang/Frontend/TextDiagnosticPrinter.h" diff --git a/clang/tools/driver/cc1_main.cpp b/clang/tools/driver/cc1_main.cpp index cc757039cafd0..92357487865ce 100644 --- a/clang/tools/driver/cc1_main.cpp +++ b/clang/tools/driver/cc1_main.cpp @@ -17,7 +17,6 @@ #include "clang/Basic/TargetOptions.h" #include "clang/CodeGen/ObjectFilePCHContainerWriter.h" #include "clang/Config/config.h" -#include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/CompilerInvocation.h" @@ -270,7 +269,7 @@ int cc1_main(ArrayRef Argv, const char *Argv0, void *MainAddr) { if (Clang->getHeaderSearchOpts().UseBuiltinIncludes && Clang->getHeaderSearchOpts().ResourceDir.empty()) Clang->getHeaderSearchOpts().ResourceDir = - GetResourcesPath(Argv0, MainAddr); + CompilerInvocation::GetResourcesPath(Argv0, MainAddr); /// Create the actual file system. Clang->createVirtualFileSystem(llvm::vfs::getRealFileSystem(), DiagsBuffer); diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp index 32e84248c1b27..f4d6fa72a1dfe 100644 --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -38,7 +38,6 @@ #include "clang/Basic/Stack.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/Version.h" -#include "clang/Driver/CreateASTUnitFromArgs.h" #include "clang/Frontend/ASTUnit.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Index/CommentToXML.h" @@ -4362,7 +4361,7 @@ clang_parseTranslationUnit_Impl(CXIndex CIdx, const char *source_filename, LibclangInvocationReporter InvocationReporter( *CXXIdx, LibclangInvocationReporter::OperationKind::ParseOperation, options, llvm::ArrayRef(*Args), /*InvocationArgs=*/{}, unsaved_files); - std::unique_ptr Unit = CreateASTUnitFromCommandLine( + std::unique_ptr Unit = ASTUnit::LoadFromCommandLine( Args->data(), Args->data() + Args->size(), CXXIdx->getPCHContainerOperations(), DiagOpts, Diags, CXXIdx->getClangResourcesPath(), CXXIdx->getStorePreamblesInMemory(), diff --git a/clang/tools/libclang/CIndexer.cpp b/clang/tools/libclang/CIndexer.cpp index 853a936b43e37..11d9312b64849 100644 --- a/clang/tools/libclang/CIndexer.cpp +++ b/clang/tools/libclang/CIndexer.cpp @@ -16,7 +16,6 @@ #include "clang/Basic/Version.h" #include "clang/Config/config.h" #include "clang/Driver/Driver.h" -#include "clang/Options/OptionUtils.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/FileSystem.h" @@ -138,7 +137,7 @@ const std::string &CIndexer::getClangResourcesPath() { #endif // Cache our result. - ResourcesPath = GetResourcesPath(LibClangPath); + ResourcesPath = driver::Driver::GetResourcesPath(LibClangPath); return ResourcesPath; } diff --git a/clang/tools/libclang/CMakeLists.txt b/clang/tools/libclang/CMakeLists.txt index b0105f5a5f79f..e0ff7605b68b8 100644 --- a/clang/tools/libclang/CMakeLists.txt +++ b/clang/tools/libclang/CMakeLists.txt @@ -65,7 +65,6 @@ set(LIBS clangFrontend clangIndex clangLex - clangOptions clangRewrite clangSema clangSerialization diff --git a/clang/tools/libclang/Indexing.cpp b/clang/tools/libclang/Indexing.cpp index 75323d70afcfe..c142f142d5071 100644 --- a/clang/tools/libclang/Indexing.cpp +++ b/clang/tools/libclang/Indexing.cpp @@ -15,7 +15,6 @@ #include "CXString.h" #include "CXTranslationUnit.h" #include "clang/AST/ASTConsumer.h" -#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/ASTUnit.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/CompilerInvocation.h" diff --git a/clang/unittests/Driver/DXCModeTest.cpp b/clang/unittests/Driver/DXCModeTest.cpp index 130da620b40b5..e0454f190b35a 100644 --- a/clang/unittests/Driver/DXCModeTest.cpp +++ b/clang/unittests/Driver/DXCModeTest.cpp @@ -15,7 +15,6 @@ #include "clang/Basic/LLVM.h" #include "clang/Basic/TargetOptions.h" #include "clang/Driver/Compilation.h" -#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Driver/Driver.h" #include "clang/Driver/ToolChain.h" #include "clang/Frontend/CompilerInstance.h" diff --git a/clang/unittests/Driver/ToolChainTest.cpp b/clang/unittests/Driver/ToolChainTest.cpp index 8f533790ec501..afa17ff219be2 100644 --- a/clang/unittests/Driver/ToolChainTest.cpp +++ b/clang/unittests/Driver/ToolChainTest.cpp @@ -17,7 +17,6 @@ #include "clang/Basic/TargetInfo.h" #include "clang/Basic/TargetOptions.h" #include "clang/Driver/Compilation.h" -#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Driver/Driver.h" #include "clang/Frontend/CompilerInstance.h" #include "llvm/ADT/ArrayRef.h" diff --git a/clang/unittests/Frontend/ASTUnitTest.cpp b/clang/unittests/Frontend/ASTUnitTest.cpp index bf9e4e184b5db..dfdbe90e72f1f 100644 --- a/clang/unittests/Frontend/ASTUnitTest.cpp +++ b/clang/unittests/Frontend/ASTUnitTest.cpp @@ -9,8 +9,6 @@ #include #include "clang/Basic/FileManager.h" -#include "clang/Driver/CreateASTUnitFromArgs.h" -#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/ASTUnit.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/CompilerInvocation.h" @@ -175,7 +173,7 @@ TEST_F(ASTUnitTest, LoadFromCommandLineEarlyError) { auto PCHContainerOps = std::make_shared(); std::unique_ptr ErrUnit; - std::unique_ptr AST = CreateASTUnitFromCommandLine( + std::unique_ptr AST = ASTUnit::LoadFromCommandLine( &Args[0], &Args[4], PCHContainerOps, DiagOpts, Diags, "", false, "", false, CaptureDiagsKind::All, {}, true, 0, TU_Complete, false, false, false, SkipFunctionBodiesScope::None, false, true, false, false, @@ -203,7 +201,7 @@ TEST_F(ASTUnitTest, LoadFromCommandLineWorkingDirectory) { auto PCHContainerOps = std::make_shared(); std::unique_ptr ErrUnit; - std::unique_ptr AST = CreateASTUnitFromCommandLine( + std::unique_ptr AST = ASTUnit::LoadFromCommandLine( &Args[0], &Args[4], PCHContainerOps, DiagOpts, Diags, "", false, "", false, CaptureDiagsKind::All, {}, true, 0, TU_Complete, false, false, false, SkipFunctionBodiesScope::None, false, true, false, false, diff --git a/clang/unittests/Frontend/CompilerInstanceTest.cpp b/clang/unittests/Frontend/CompilerInstanceTest.cpp index 39d35b48f394a..cd3fefa1ea994 100644 --- a/clang/unittests/Frontend/CompilerInstanceTest.cpp +++ b/clang/unittests/Frontend/CompilerInstanceTest.cpp @@ -8,7 +8,6 @@ #include "clang/Frontend/CompilerInstance.h" #include "clang/Basic/FileManager.h" -#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/CompilerInvocation.h" #include "clang/Frontend/FrontendActions.h" #include "clang/Frontend/TextDiagnosticPrinter.h" diff --git a/clang/unittests/Frontend/UtilsTest.cpp b/clang/unittests/Frontend/UtilsTest.cpp index a82733d57714a..fc411e4af705f 100644 --- a/clang/unittests/Frontend/UtilsTest.cpp +++ b/clang/unittests/Frontend/UtilsTest.cpp @@ -9,7 +9,6 @@ #include "clang/Frontend/Utils.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/TargetOptions.h" -#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/CompilerInvocation.h" #include "clang/Lex/PreprocessorOptions.h" diff --git a/clang/unittests/Sema/CMakeLists.txt b/clang/unittests/Sema/CMakeLists.txt index 188f6135a60ac..b61ed8c457635 100644 --- a/clang/unittests/Sema/CMakeLists.txt +++ b/clang/unittests/Sema/CMakeLists.txt @@ -13,7 +13,6 @@ add_distinct_clang_unittest(SemaTests clangAST clangASTMatchers clangBasic - clangDriver clangFrontend clangParse clangSema diff --git a/clang/unittests/Sema/SemaNoloadLookupTest.cpp b/clang/unittests/Sema/SemaNoloadLookupTest.cpp index 3944269eff502..e565372698e5e 100644 --- a/clang/unittests/Sema/SemaNoloadLookupTest.cpp +++ b/clang/unittests/Sema/SemaNoloadLookupTest.cpp @@ -10,7 +10,6 @@ #include "clang/AST/DeclarationName.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/ASTMatchers/ASTMatchers.h" -#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendAction.h" #include "clang/Frontend/FrontendActions.h" diff --git a/clang/unittests/Serialization/ForceCheckFileInputTest.cpp b/clang/unittests/Serialization/ForceCheckFileInputTest.cpp index b76dcfec96063..edf33ae04230b 100644 --- a/clang/unittests/Serialization/ForceCheckFileInputTest.cpp +++ b/clang/unittests/Serialization/ForceCheckFileInputTest.cpp @@ -9,7 +9,6 @@ #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/ASTMatchers/ASTMatchers.h" #include "clang/Basic/FileManager.h" -#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/CompilerInvocation.h" #include "clang/Frontend/FrontendActions.h" diff --git a/clang/unittests/Serialization/LoadSpecLazilyTest.cpp b/clang/unittests/Serialization/LoadSpecLazilyTest.cpp index f55925aeae1f2..d7b55491fddac 100644 --- a/clang/unittests/Serialization/LoadSpecLazilyTest.cpp +++ b/clang/unittests/Serialization/LoadSpecLazilyTest.cpp @@ -6,7 +6,6 @@ // //===----------------------------------------------------------------------===// -#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendAction.h" #include "clang/Frontend/FrontendActions.h" diff --git a/clang/unittests/Serialization/ModuleCacheTest.cpp b/clang/unittests/Serialization/ModuleCacheTest.cpp index df26e54588b9e..e9b8da3dba6af 100644 --- a/clang/unittests/Serialization/ModuleCacheTest.cpp +++ b/clang/unittests/Serialization/ModuleCacheTest.cpp @@ -7,7 +7,6 @@ //===----------------------------------------------------------------------===// #include "clang/Basic/FileManager.h" -#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/CompilerInvocation.h" #include "clang/Frontend/FrontendActions.h" diff --git a/clang/unittests/Serialization/NoCommentsTest.cpp b/clang/unittests/Serialization/NoCommentsTest.cpp index 444a082bba907..01bb6999a7c90 100644 --- a/clang/unittests/Serialization/NoCommentsTest.cpp +++ b/clang/unittests/Serialization/NoCommentsTest.cpp @@ -9,7 +9,6 @@ #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/ASTMatchers/ASTMatchers.h" #include "clang/Basic/FileManager.h" -#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/CompilerInvocation.h" #include "clang/Frontend/FrontendActions.h" diff --git a/clang/unittests/Serialization/PreambleInNamedModulesTest.cpp b/clang/unittests/Serialization/PreambleInNamedModulesTest.cpp index b826f20ce4d70..55ee72875ead2 100644 --- a/clang/unittests/Serialization/PreambleInNamedModulesTest.cpp +++ b/clang/unittests/Serialization/PreambleInNamedModulesTest.cpp @@ -6,7 +6,6 @@ // //===----------------------------------------------------------------------===// -#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/CompilerInvocation.h" #include "clang/Frontend/FrontendActions.h" diff --git a/clang/unittests/Serialization/VarDeclConstantInitTest.cpp b/clang/unittests/Serialization/VarDeclConstantInitTest.cpp index 2be01def49809..743f851fc5fe1 100644 --- a/clang/unittests/Serialization/VarDeclConstantInitTest.cpp +++ b/clang/unittests/Serialization/VarDeclConstantInitTest.cpp @@ -9,7 +9,6 @@ #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/ASTMatchers/ASTMatchers.h" #include "clang/Basic/FileManager.h" -#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/CompilerInvocation.h" #include "clang/Frontend/FrontendActions.h" diff --git a/clang/unittests/Tooling/Syntax/TokensTest.cpp b/clang/unittests/Tooling/Syntax/TokensTest.cpp index 468ca5ddd2c75..47184cbf5d768 100644 --- a/clang/unittests/Tooling/Syntax/TokensTest.cpp +++ b/clang/unittests/Tooling/Syntax/TokensTest.cpp @@ -20,7 +20,6 @@ #include "clang/Basic/SourceManager.h" #include "clang/Basic/TokenKinds.def" #include "clang/Basic/TokenKinds.h" -#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendAction.h" #include "clang/Frontend/Utils.h" diff --git a/clang/unittests/Tooling/Syntax/TreeTestBase.cpp b/clang/unittests/Tooling/Syntax/TreeTestBase.cpp index dad75854240ef..b2be64fc08f3d 100644 --- a/clang/unittests/Tooling/Syntax/TreeTestBase.cpp +++ b/clang/unittests/Tooling/Syntax/TreeTestBase.cpp @@ -13,7 +13,6 @@ #include "TreeTestBase.h" #include "clang/AST/ASTConsumer.h" #include "clang/Basic/LLVM.h" -#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/CompilerInvocation.h" #include "clang/Frontend/FrontendAction.h" diff --git a/flang/lib/Frontend/CMakeLists.txt b/flang/lib/Frontend/CMakeLists.txt index fb74b3dcb280e..bb0b4a39cec9b 100644 --- a/flang/lib/Frontend/CMakeLists.txt +++ b/flang/lib/Frontend/CMakeLists.txt @@ -75,6 +75,7 @@ add_flang_library(flangFrontend CLANG_LIBS clangBasic + clangDriver clangOptions ) diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp index b6c4e6303cdac..0c32f3914e04b 100644 --- a/flang/lib/Frontend/CompilerInvocation.cpp +++ b/flang/lib/Frontend/CompilerInvocation.cpp @@ -325,9 +325,10 @@ static void parseCodeGenArgs(Fortran::frontend::CodeGenOptions &opts, for (auto *a : args.filtered(clang::options::OPT_fpass_plugin_EQ)) opts.LLVMPassPlugins.push_back(a->getValue()); - opts.Reciprocals = clang::parseMRecipOption(diags, args); + opts.Reciprocals = clang::driver::tools::parseMRecipOption(diags, args); - opts.PreferVectorWidth = clang::parseMPreferVectorWidthOption(diags, args); + opts.PreferVectorWidth = + clang::driver::tools::parseMPreferVectorWidthOption(diags, args); // -fembed-offload-object option for (auto *a : args.filtered(clang::options::OPT_fembed_offload_object_EQ)) diff --git a/lldb/source/Commands/CommandObjectTarget.cpp b/lldb/source/Commands/CommandObjectTarget.cpp index 7f880d223d6c3..30bca639060e6 100644 --- a/lldb/source/Commands/CommandObjectTarget.cpp +++ b/lldb/source/Commands/CommandObjectTarget.cpp @@ -60,7 +60,6 @@ #include "lldb/lldb-forward.h" #include "lldb/lldb-private-enumerations.h" -#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/CompilerInvocation.h" #include "clang/Frontend/FrontendActions.h" diff --git a/lldb/source/Plugins/ExpressionParser/Clang/CMakeLists.txt b/lldb/source/Plugins/ExpressionParser/Clang/CMakeLists.txt index 759a7c4dd14fb..01d588ff6a78b 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/CMakeLists.txt +++ b/lldb/source/Plugins/ExpressionParser/Clang/CMakeLists.txt @@ -51,10 +51,10 @@ add_lldb_library(lldbPluginExpressionParserClang CLANG_LIBS clangAST clangCodeGen + clangDriver clangEdit clangFrontend clangLex - clangOptions clangParse clangRewrite clangRewriteFrontend diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangHost.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangHost.cpp index 660a21e3c6a8d..6de851081598f 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangHost.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangHost.cpp @@ -10,7 +10,7 @@ #include "clang/Basic/Version.h" #include "clang/Config/config.h" -#include "clang/Options/OptionUtils.h" +#include "clang/Driver/Driver.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" @@ -53,7 +53,7 @@ static bool DefaultComputeClangResourceDirectory(FileSpec &lldb_shlib_spec, std::string raw_path = lldb_shlib_spec.GetPath(); llvm::StringRef parent_dir = llvm::sys::path::parent_path(raw_path); static const std::string clang_resource_path = - clang::GetResourcesPath("bin/lldb"); + clang::driver::Driver::GetResourcesPath("bin/lldb"); static const llvm::StringRef kResourceDirSuffixes[] = { // LLVM.org's build of LLDB uses the clang resource directory placed diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp index ce8dc50b84a31..e37c84efefdc9 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp @@ -10,7 +10,6 @@ #include "clang/Basic/DiagnosticFrontend.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/TargetInfo.h" -#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendActions.h" #include "clang/Frontend/TextDiagnosticPrinter.h" diff --git a/lldb/unittests/Expression/ClangParserTest.cpp b/lldb/unittests/Expression/ClangParserTest.cpp index c949026e87cd8..fab4487c73719 100644 --- a/lldb/unittests/Expression/ClangParserTest.cpp +++ b/lldb/unittests/Expression/ClangParserTest.cpp @@ -8,7 +8,7 @@ #include "clang/Basic/Version.h" #include "clang/Config/config.h" -#include "clang/Options/OptionUtils.h" +#include "clang/Driver/Driver.h" #include "Plugins/ExpressionParser/Clang/ClangHost.h" #include "TestingSupport/SubsystemRAII.h" @@ -43,7 +43,7 @@ TEST_F(ClangHostTest, ComputeClangResourceDirectory) { std::string path_to_liblldb = "C:\\foo\\bar\\lib\\"; #endif std::string path_to_clang_dir = - clang::GetResourcesPath(path_to_liblldb + "liblldb"); + clang::driver::Driver::GetResourcesPath(path_to_liblldb + "liblldb"); llvm::SmallString<256> path_to_clang_lib_dir_real; llvm::sys::fs::real_path(path_to_clang_dir, path_to_clang_lib_dir_real); From 5a9c62ba48ea2fa899e3ff54d6b4779c1902f34b Mon Sep 17 00:00:00 2001 From: Vishruth Thimmaiah Date: Tue, 25 Nov 2025 01:06:43 +0530 Subject: [PATCH 04/50] [CIR][X86] Add support for `kshiftl`/`kshiftr` builtins (#168591) Adds support for the `__builtin_ia32_kshiftli` and `__builtin_ia32_kshiftri` X86 builtins. Part of #167765 --------- Signed-off-by: vishruth-thimmaiah --- clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp | 72 ++++++++++- .../test/CIR/CodeGen/X86/avx512bw-builtins.c | 117 ++++++++++++++++++ 2 files changed, 187 insertions(+), 2 deletions(-) create mode 100644 clang/test/CIR/CodeGen/X86/avx512bw-builtins.c diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp index 978fee7dbec9d..e7aa8a234efd9 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp @@ -68,6 +68,28 @@ static mlir::Value emitVectorFCmp(CIRGenBuilderTy &builder, return bitCast; } +static mlir::Value getMaskVecValue(CIRGenFunction &cgf, const CallExpr *expr, + mlir::Value mask, unsigned numElems) { + + CIRGenBuilderTy &builder = cgf.getBuilder(); + auto maskTy = cir::VectorType::get( + builder.getUIntNTy(1), cast(mask.getType()).getWidth()); + mlir::Value maskVec = builder.createBitcast(mask, maskTy); + + // If we have less than 8 elements, then the starting mask was an i8 and + // we need to extract down to the right number of elements. + if (numElems < 8) { + SmallVector indices; + mlir::Type i32Ty = builder.getSInt32Ty(); + for (auto i : llvm::seq(0, numElems)) + indices.push_back(cir::IntAttr::get(i32Ty, i)); + + maskVec = builder.createVecShuffle(cgf.getLoc(expr->getExprLoc()), maskVec, + maskVec, indices); + } + return maskVec; +} + mlir::Value CIRGenFunction::emitX86BuiltinExpr(unsigned builtinID, const CallExpr *expr) { if (builtinID == Builtin::BI__builtin_cpu_is) { @@ -575,14 +597,60 @@ mlir::Value CIRGenFunction::emitX86BuiltinExpr(unsigned builtinID, case X86::BI__builtin_ia32_psrldqi128_byteshift: case X86::BI__builtin_ia32_psrldqi256_byteshift: case X86::BI__builtin_ia32_psrldqi512_byteshift: + cgm.errorNYI(expr->getSourceRange(), + std::string("unimplemented X86 builtin call: ") + + getContext().BuiltinInfo.getName(builtinID)); + return {}; case X86::BI__builtin_ia32_kshiftliqi: case X86::BI__builtin_ia32_kshiftlihi: case X86::BI__builtin_ia32_kshiftlisi: - case X86::BI__builtin_ia32_kshiftlidi: + case X86::BI__builtin_ia32_kshiftlidi: { + unsigned shiftVal = + ops[1].getDefiningOp().getIntValue().getZExtValue() & + 0xff; + unsigned numElems = cast(ops[0].getType()).getWidth(); + + if (shiftVal >= numElems) + return builder.getNullValue(ops[0].getType(), getLoc(expr->getExprLoc())); + + mlir::Value in = getMaskVecValue(*this, expr, ops[0], numElems); + + SmallVector indices; + mlir::Type i32Ty = builder.getSInt32Ty(); + for (auto i : llvm::seq(0, numElems)) + indices.push_back(cir::IntAttr::get(i32Ty, numElems + i - shiftVal)); + + mlir::Value zero = + builder.getNullValue(in.getType(), getLoc(expr->getExprLoc())); + mlir::Value sv = + builder.createVecShuffle(getLoc(expr->getExprLoc()), zero, in, indices); + return builder.createBitcast(sv, ops[0].getType()); + } case X86::BI__builtin_ia32_kshiftriqi: case X86::BI__builtin_ia32_kshiftrihi: case X86::BI__builtin_ia32_kshiftrisi: - case X86::BI__builtin_ia32_kshiftridi: + case X86::BI__builtin_ia32_kshiftridi: { + unsigned shiftVal = + ops[1].getDefiningOp().getIntValue().getZExtValue() & + 0xff; + unsigned numElems = cast(ops[0].getType()).getWidth(); + + if (shiftVal >= numElems) + return builder.getNullValue(ops[0].getType(), getLoc(expr->getExprLoc())); + + mlir::Value in = getMaskVecValue(*this, expr, ops[0], numElems); + + SmallVector indices; + mlir::Type i32Ty = builder.getSInt32Ty(); + for (auto i : llvm::seq(0, numElems)) + indices.push_back(cir::IntAttr::get(i32Ty, i + shiftVal)); + + mlir::Value zero = + builder.getNullValue(in.getType(), getLoc(expr->getExprLoc())); + mlir::Value sv = + builder.createVecShuffle(getLoc(expr->getExprLoc()), in, zero, indices); + return builder.createBitcast(sv, ops[0].getType()); + } case X86::BI__builtin_ia32_vprotbi: case X86::BI__builtin_ia32_vprotwi: case X86::BI__builtin_ia32_vprotdi: diff --git a/clang/test/CIR/CodeGen/X86/avx512bw-builtins.c b/clang/test/CIR/CodeGen/X86/avx512bw-builtins.c new file mode 100644 index 0000000000000..3522e2c7e50bf --- /dev/null +++ b/clang/test/CIR/CodeGen/X86/avx512bw-builtins.c @@ -0,0 +1,117 @@ +// RUN: %clang_cc1 -x c -flax-vector-conversions=none -ffreestanding %s -triple=x86_64-unknown-linux -target-feature +avx512bw -fclangir -emit-cir -o %t.cir -Wall -Werror +// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s +// RUN: %clang_cc1 -x c -flax-vector-conversions=none -ffreestanding %s -triple=x86_64-unknown-linux -target-feature +avx512bw -fclangir -emit-llvm -o %t.ll -Wall -Werror +// RUN: FileCheck --check-prefix=LLVM --input-file=%t.ll %s + +// RUN: %clang_cc1 -x c++ -flax-vector-conversions=none -ffreestanding %s -triple=x86_64-unknown-linux -target-feature +avx512bw -fno-signed-char -fclangir -emit-cir -o %t.cir -Wall -Werror +// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s +// RUN: %clang_cc1 -x c++ -flax-vector-conversions=none -ffreestanding %s -triple=x86_64-unknown-linux -target-feature +avx512bw -fno-signed-char -fclangir -emit-llvm -o %t.ll -Wall -Werror +// RUN: FileCheck --check-prefix=LLVM --input-file=%t.ll %s + +// RUN: %clang_cc1 -x c -flax-vector-conversions=none -ffreestanding %s -triple=x86_64-unknown-linux -target-feature +avx512bw -emit-llvm -o - -Wall -Werror | FileCheck %s -check-prefix=OGCG +// RUN: %clang_cc1 -x c++ -flax-vector-conversions=none -ffreestanding %s -triple=x86_64-unknown-linux -target-feature +avx512bw -emit-llvm -o - -Wall -Werror | FileCheck %s -check-prefix=OGCG + +// This test mimics clang/test/CodeGen/X86/avx512bw-builtins.c, which eventually +// CIR shall be able to support fully. + +#include + +__mmask32 test_kshiftli_mask32(__mmask32 A) { + // CIR-LABEL: test_kshiftli_mask32 + // CIR: [[VAL:%.*]] = cir.cast bitcast %{{.*}} : !u32i -> !cir.vector<32 x !cir.int> + // CIR: [[SHIFT:%.*]] = cir.const #cir.zero : !cir.vector<32 x !cir.int> + // CIR: %{{.*}} = cir.vec.shuffle([[SHIFT]], [[VAL]] : !cir.vector<32 x !cir.int>) [#cir.int<1> : !s32i, #cir.int<2> : !s32i, #cir.int<3> : !s32i, #cir.int<4> : !s32i, #cir.int<5> : !s32i, #cir.int<6> : !s32i, #cir.int<7> : !s32i, #cir.int<8> : !s32i, #cir.int<9> : !s32i, #cir.int<10> : !s32i, #cir.int<11> : !s32i, #cir.int<12> : !s32i, #cir.int<13> : !s32i, #cir.int<14> : !s32i, #cir.int<15> : !s32i, #cir.int<16> : !s32i, #cir.int<17> : !s32i, #cir.int<18> : !s32i, #cir.int<19> : !s32i, #cir.int<20> : !s32i, #cir.int<21> : !s32i, #cir.int<22> : !s32i, #cir.int<23> : !s32i, #cir.int<24> : !s32i, #cir.int<25> : !s32i, #cir.int<26> : !s32i, #cir.int<27> : !s32i, #cir.int<28> : !s32i, #cir.int<29> : !s32i, #cir.int<30> : !s32i, #cir.int<31> : !s32i, #cir.int<32> : !s32i] : !cir.vector<32 x !cir.int> + + // LLVM-LABEL: test_kshiftli_mask32 + // LLVM: [[VAL:%.*]] = bitcast i32 %{{.*}} to <32 x i1> + // LLVM: [[RES:%.*]] = shufflevector <32 x i1> zeroinitializer, <32 x i1> [[VAL]], <32 x i32> + + // OGCG-LABEL: test_kshiftli_mask32 + // OGCG: [[VAL:%.*]] = bitcast i32 %{{.*}} to <32 x i1> + // OGCG: [[RES:%.*]] = shufflevector <32 x i1> zeroinitializer, <32 x i1> [[VAL]], <32 x i32> + return _kshiftli_mask32(A, 31); +} + +__mmask32 test_kshiftri_mask32(__mmask32 A) { + // CIR-LABEL: test_kshiftri_mask32 + // CIR: [[VAL:%.*]] = cir.cast bitcast %{{.*}} : !u32i -> !cir.vector<32 x !cir.int> + // CIR: [[SHIFT:%.*]] = cir.const #cir.zero : !cir.vector<32 x !cir.int> + // CIR: %{{.*}} = cir.vec.shuffle([[VAL]], [[SHIFT]] : !cir.vector<32 x !cir.int>) [#cir.int<31> : !s32i, #cir.int<32> : !s32i, #cir.int<33> : !s32i, #cir.int<34> : !s32i, #cir.int<35> : !s32i, #cir.int<36> : !s32i, #cir.int<37> : !s32i, #cir.int<38> : !s32i, #cir.int<39> : !s32i, #cir.int<40> : !s32i, #cir.int<41> : !s32i, #cir.int<42> : !s32i, #cir.int<43> : !s32i, #cir.int<44> : !s32i, #cir.int<45> : !s32i, #cir.int<46> : !s32i, #cir.int<47> : !s32i, #cir.int<48> : !s32i, #cir.int<49> : !s32i, #cir.int<50> : !s32i, #cir.int<51> : !s32i, #cir.int<52> : !s32i, #cir.int<53> : !s32i, #cir.int<54> : !s32i, #cir.int<55> : !s32i, #cir.int<56> : !s32i, #cir.int<57> : !s32i, #cir.int<58> : !s32i, #cir.int<59> : !s32i, #cir.int<60> : !s32i, #cir.int<61> : !s32i, #cir.int<62> : !s32i] : !cir.vector<32 x !cir.int> + + // LLVM-LABEL: test_kshiftri_mask32 + // LLVM: [[VAL:%.*]] = bitcast i32 %{{.*}} to <32 x i1> + // LLVM: [[RES:%.*]] = shufflevector <32 x i1> [[VAL]], <32 x i1> zeroinitializer, <32 x i32> + + // OGCG-LABEL: test_kshiftri_mask32 + // OGCG: [[VAL:%.*]] = bitcast i32 %{{.*}} to <32 x i1> + // OGCG: [[RES:%.*]] = shufflevector <32 x i1> [[VAL]], <32 x i1> zeroinitializer, <32 x i32> + return _kshiftri_mask32(A, 31); +} + +__mmask64 test_kshiftli_mask64(__mmask64 A) { + // CIR-LABEL: test_kshiftli_mask64 + // CIR: [[VAL:%.*]] = cir.cast bitcast %{{.*}} : !u64i -> !cir.vector<64 x !cir.int> + // CIR: [[SHIFT:%.*]] = cir.const #cir.zero : !cir.vector<64 x !cir.int> + // CIR: %{{.*}} = cir.vec.shuffle([[SHIFT]], [[VAL]] : !cir.vector<64 x !cir.int>) [#cir.int<32> : !s32i, #cir.int<33> : !s32i, #cir.int<34> : !s32i, #cir.int<35> : !s32i, #cir.int<36> : !s32i, #cir.int<37> : !s32i, #cir.int<38> : !s32i, #cir.int<39> : !s32i, #cir.int<40> : !s32i, #cir.int<41> : !s32i, #cir.int<42> : !s32i, #cir.int<43> : !s32i, #cir.int<44> : !s32i, #cir.int<45> : !s32i, #cir.int<46> : !s32i, #cir.int<47> : !s32i, #cir.int<48> : !s32i, #cir.int<49> : !s32i, #cir.int<50> : !s32i, #cir.int<51> : !s32i, #cir.int<52> : !s32i, #cir.int<53> : !s32i, #cir.int<54> : !s32i, #cir.int<55> : !s32i, #cir.int<56> : !s32i, #cir.int<57> : !s32i, #cir.int<58> : !s32i, #cir.int<59> : !s32i, #cir.int<60> : !s32i, #cir.int<61> : !s32i, #cir.int<62> : !s32i, #cir.int<63> : !s32i, #cir.int<64> : !s32i, #cir.int<65> : !s32i, #cir.int<66> : !s32i, #cir.int<67> : !s32i, #cir.int<68> : !s32i, #cir.int<69> : !s32i, #cir.int<70> : !s32i, #cir.int<71> : !s32i, #cir.int<72> : !s32i, #cir.int<73> : !s32i, #cir.int<74> : !s32i, #cir.int<75> : !s32i, #cir.int<76> : !s32i, #cir.int<77> : !s32i, #cir.int<78> : !s32i, #cir.int<79> : !s32i, #cir.int<80> : !s32i, #cir.int<81> : !s32i, #cir.int<82> : !s32i, #cir.int<83> : !s32i, #cir.int<84> : !s32i, #cir.int<85> : !s32i, #cir.int<86> : !s32i, #cir.int<87> : !s32i, #cir.int<88> : !s32i, #cir.int<89> : !s32i, #cir.int<90> : !s32i, #cir.int<91> : !s32i, #cir.int<92> : !s32i, #cir.int<93> : !s32i, #cir.int<94> : !s32i, #cir.int<95> : !s32i] : !cir.vector<64 x !cir.int> + + // LLVM-LABEL: test_kshiftli_mask64 + // LLVM: [[VAL:%.*]] = bitcast i64 %{{.*}} to <64 x i1> + // LLVM: [[RES:%.*]] = shufflevector <64 x i1> zeroinitializer, <64 x i1> [[VAL]], <64 x i32> + + // OGCG-LABEL: test_kshiftli_mask64 + // OGCG: [[VAL:%.*]] = bitcast i64 %{{.*}} to <64 x i1> + // OGCG: [[RES:%.*]] = shufflevector <64 x i1> zeroinitializer, <64 x i1> [[VAL]], <64 x i32> + return _kshiftli_mask64(A, 32); +} + +__mmask64 test_kshiftri_mask64(__mmask64 A) { + // CIR-LABEL: test_kshiftri_mask64 + // CIR: [[VAL:%.*]] = cir.cast bitcast %{{.*}} : !u64i -> !cir.vector<64 x !cir.int> + // CIR: [[SHIFT:%.*]] = cir.const #cir.zero : !cir.vector<64 x !cir.int> + // CIR: %{{.*}} = cir.vec.shuffle([[VAL]], [[SHIFT]] : !cir.vector<64 x !cir.int>) [#cir.int<32> : !s32i, #cir.int<33> : !s32i, #cir.int<34> : !s32i, #cir.int<35> : !s32i, #cir.int<36> : !s32i, #cir.int<37> : !s32i, #cir.int<38> : !s32i, #cir.int<39> : !s32i, #cir.int<40> : !s32i, #cir.int<41> : !s32i, #cir.int<42> : !s32i, #cir.int<43> : !s32i, #cir.int<44> : !s32i, #cir.int<45> : !s32i, #cir.int<46> : !s32i, #cir.int<47> : !s32i, #cir.int<48> : !s32i, #cir.int<49> : !s32i, #cir.int<50> : !s32i, #cir.int<51> : !s32i, #cir.int<52> : !s32i, #cir.int<53> : !s32i, #cir.int<54> : !s32i, #cir.int<55> : !s32i, #cir.int<56> : !s32i, #cir.int<57> : !s32i, #cir.int<58> : !s32i, #cir.int<59> : !s32i, #cir.int<60> : !s32i, #cir.int<61> : !s32i, #cir.int<62> : !s32i, #cir.int<63> : !s32i, #cir.int<64> : !s32i, #cir.int<65> : !s32i, #cir.int<66> : !s32i, #cir.int<67> : !s32i, #cir.int<68> : !s32i, #cir.int<69> : !s32i, #cir.int<70> : !s32i, #cir.int<71> : !s32i, #cir.int<72> : !s32i, #cir.int<73> : !s32i, #cir.int<74> : !s32i, #cir.int<75> : !s32i, #cir.int<76> : !s32i, #cir.int<77> : !s32i, #cir.int<78> : !s32i, #cir.int<79> : !s32i, #cir.int<80> : !s32i, #cir.int<81> : !s32i, #cir.int<82> : !s32i, #cir.int<83> : !s32i, #cir.int<84> : !s32i, #cir.int<85> : !s32i, #cir.int<86> : !s32i, #cir.int<87> : !s32i, #cir.int<88> : !s32i, #cir.int<89> : !s32i, #cir.int<90> : !s32i, #cir.int<91> : !s32i, #cir.int<92> : !s32i, #cir.int<93> : !s32i, #cir.int<94> : !s32i, #cir.int<95> : !s32i] : !cir.vector<64 x !cir.int> + + // LLVM-LABEL: test_kshiftri_mask64 + // LLVM: [[VAL:%.*]] = bitcast i64 %{{.*}} to <64 x i1> + // LLVM: [[RES:%.*]] = shufflevector <64 x i1> [[VAL]], <64 x i1> zeroinitializer, <64 x i32> + + // OGCG-LABEL: test_kshiftri_mask64 + // OGCG: [[VAL:%.*]] = bitcast i64 %{{.*}} to <64 x i1> + // OGCG: [[RES:%.*]] = shufflevector <64 x i1> [[VAL]], <64 x i1> zeroinitializer, <64 x i32> + return _kshiftri_mask64(A, 32); +} + +__mmask32 test_kshiftli_mask32_out_of_range(__mmask32 A) { + // CIR-LABEL: test_kshiftli_mask32_out_of_range + // CIR: [[VAL:%.*]] = cir.const #cir.int<0> : !u32i + // CIR: cir.store [[VAL]], {{%.*}} : !u32i, !cir.ptr + // CIR: [[RES:%.*]] = cir.load {{%.*}} : !cir.ptr, !u32i + // CIR: cir.return [[RES]] : !u32i + + // LLVM-LABEL: test_kshiftli_mask32_out_of_range + // LLVM: store i32 0, ptr [[VAL:%.*]], align 4 + // LLVM: [[RES:%.*]] = load i32, ptr [[VAL]], align 4 + // LLVM: ret i32 [[RES]] + + // OGCG-LABEL: test_kshiftli_mask32_out_of_range + // OGCG: ret i32 0 + + return _kshiftli_mask32(A, 33); +} + +__mmask32 test_kshiftri_mask32_out_of_range(__mmask32 A) { + // CIR-LABEL: test_kshiftri_mask32_out_of_range + // CIR: [[VAL:%.*]] = cir.const #cir.int<0> : !u32i + // CIR: cir.store [[VAL]], {{%.*}} : !u32i, !cir.ptr + // CIR: [[RES:%.*]] = cir.load {{%.*}} : !cir.ptr, !u32i + // CIR: cir.return [[RES]] : !u32i + + // LLVM-LABEL: test_kshiftri_mask32_out_of_range + // LLVM: store i32 0, ptr [[VAL:%.*]], align 4 + // LLVM: [[RES:%.*]] = load i32, ptr [[VAL]], align 4 + // LLVM: ret i32 [[RES]] + + // OGCG-LABEL: test_kshiftri_mask32_out_of_range + // OGCG: ret i32 0 + + return _kshiftri_mask32(A, 33); +} From 5c15f579234f0ac4e40037ebc7e250499525ac48 Mon Sep 17 00:00:00 2001 From: Shilei Tian Date: Mon, 24 Nov 2025 14:40:03 -0500 Subject: [PATCH 05/50] Reapply " [clang] Refactor to remove clangDriver dependency from clangFrontend and flangFrontend (#165277)" This reverts commit 40334b8632f6d065e6672ada1c4342d07ecce629. Unfortunately the revert breaks the build. --- clang-tools-extra/clangd/CompileCommands.cpp | 3 +- clang-tools-extra/clangd/Compiler.cpp | 1 + clang/docs/ReleaseNotes.rst | 2 + clang/include/clang/Driver/CommonArgs.h | 10 - .../clang/Driver/CreateASTUnitFromArgs.h | 80 ++++ .../clang/Driver/CreateInvocationFromArgs.h | 76 ++++ clang/include/clang/Driver/Driver.h | 5 - clang/include/clang/Frontend/ASTUnit.h | 146 ++++---- .../Frontend/ChainedDiagnosticConsumer.h | 2 +- .../clang/Frontend/CompilerInvocation.h | 10 - .../clang/Frontend/StandaloneDiagnostic.h | 82 +++++ clang/include/clang/Frontend/Utils.h | 45 --- clang/include/clang/Options/OptionUtils.h | 24 ++ clang/lib/CrossTU/CMakeLists.txt | 1 + clang/lib/CrossTU/CrossTranslationUnit.cpp | 3 +- clang/lib/Driver/CMakeLists.txt | 4 + clang/lib/Driver/CreateASTUnitFromArgs.cpp | 166 +++++++++ .../CreateInvocationFromArgs.cpp} | 15 +- clang/lib/Driver/Driver.cpp | 35 +- clang/lib/Driver/ToolChains/Clang.cpp | 1 + clang/lib/Driver/ToolChains/CommonArgs.cpp | 163 --------- clang/lib/Driver/ToolChains/Flang.cpp | 1 + clang/lib/Frontend/ASTUnit.cpp | 346 +++--------------- clang/lib/Frontend/CMakeLists.txt | 3 +- clang/lib/Frontend/CompilerInvocation.cpp | 7 - clang/lib/Frontend/StandaloneDiagnostic.cpp | 117 ++++++ clang/lib/Interpreter/CMakeLists.txt | 1 + clang/lib/Interpreter/Interpreter.cpp | 3 +- clang/lib/Options/OptionUtils.cpp | 215 ++++++++++- clang/lib/Tooling/Tooling.cpp | 4 +- clang/tools/c-index-test/CMakeLists.txt | 1 + clang/tools/c-index-test/core_main.cpp | 1 + clang/tools/diagtool/CMakeLists.txt | 1 + clang/tools/diagtool/ShowEnabledWarnings.cpp | 1 + clang/tools/driver/cc1_main.cpp | 3 +- clang/tools/libclang/CIndex.cpp | 3 +- clang/tools/libclang/CIndexer.cpp | 3 +- clang/tools/libclang/CMakeLists.txt | 1 + clang/tools/libclang/Indexing.cpp | 1 + clang/unittests/Driver/DXCModeTest.cpp | 1 + clang/unittests/Driver/ToolChainTest.cpp | 1 + clang/unittests/Frontend/ASTUnitTest.cpp | 6 +- .../Frontend/CompilerInstanceTest.cpp | 1 + clang/unittests/Frontend/UtilsTest.cpp | 1 + clang/unittests/Sema/CMakeLists.txt | 1 + clang/unittests/Sema/SemaNoloadLookupTest.cpp | 1 + .../Serialization/ForceCheckFileInputTest.cpp | 1 + .../Serialization/LoadSpecLazilyTest.cpp | 1 + .../Serialization/ModuleCacheTest.cpp | 1 + .../Serialization/NoCommentsTest.cpp | 1 + .../PreambleInNamedModulesTest.cpp | 1 + .../Serialization/VarDeclConstantInitTest.cpp | 1 + clang/unittests/Tooling/Syntax/TokensTest.cpp | 1 + .../unittests/Tooling/Syntax/TreeTestBase.cpp | 1 + flang/lib/Frontend/CMakeLists.txt | 1 - flang/lib/Frontend/CompilerInvocation.cpp | 5 +- lldb/source/Commands/CommandObjectTarget.cpp | 1 + .../ExpressionParser/Clang/CMakeLists.txt | 2 +- .../ExpressionParser/Clang/ClangHost.cpp | 4 +- .../Clang/ClangModulesDeclVendor.cpp | 1 + lldb/unittests/Expression/ClangParserTest.cpp | 4 +- 61 files changed, 937 insertions(+), 687 deletions(-) create mode 100644 clang/include/clang/Driver/CreateASTUnitFromArgs.h create mode 100644 clang/include/clang/Driver/CreateInvocationFromArgs.h create mode 100644 clang/include/clang/Frontend/StandaloneDiagnostic.h create mode 100644 clang/lib/Driver/CreateASTUnitFromArgs.cpp rename clang/lib/{Frontend/CreateInvocationFromCommandLine.cpp => Driver/CreateInvocationFromArgs.cpp} (93%) create mode 100644 clang/lib/Frontend/StandaloneDiagnostic.cpp diff --git a/clang-tools-extra/clangd/CompileCommands.cpp b/clang-tools-extra/clangd/CompileCommands.cpp index 7990f2719e9a0..4eda330716f21 100644 --- a/clang-tools-extra/clangd/CompileCommands.cpp +++ b/clang-tools-extra/clangd/CompileCommands.cpp @@ -132,8 +132,7 @@ std::optional detectSysroot() { std::string detectStandardResourceDir() { static int StaticForMainAddr; // Just an address in this process. - return CompilerInvocation::GetResourcesPath("clangd", - (void *)&StaticForMainAddr); + return GetResourcesPath("clangd", (void *)&StaticForMainAddr); } // The path passed to argv[0] is important: diff --git a/clang-tools-extra/clangd/Compiler.cpp b/clang-tools-extra/clangd/Compiler.cpp index 6ebc2eac25745..9ea7df139382a 100644 --- a/clang-tools-extra/clangd/Compiler.cpp +++ b/clang-tools-extra/clangd/Compiler.cpp @@ -9,6 +9,7 @@ #include "Compiler.h" #include "support/Logger.h" #include "clang/Basic/TargetInfo.h" +#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/CompilerInvocation.h" #include "clang/Lex/PreprocessorOptions.h" #include "clang/Serialization/PCHContainerOperations.h" diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 51f07256c5d9f..b12e4539dc3a6 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -84,6 +84,8 @@ Potentially Breaking Changes - Downstream projects that previously linked only against ``clangDriver`` may now (also) need to link against the new ``clangOptions`` library, since options-related code has been moved out of the Driver into a separate library. +- The ``clangFrontend`` library no longer depends on ``clangDriver``, which may + break downstream projects that relied on this transitive dependency. C/C++ Language Potentially Breaking Changes ------------------------------------------- diff --git a/clang/include/clang/Driver/CommonArgs.h b/clang/include/clang/Driver/CommonArgs.h index ac17d6211d882..264bd4965f9ad 100644 --- a/clang/include/clang/Driver/CommonArgs.h +++ b/clang/include/clang/Driver/CommonArgs.h @@ -291,16 +291,6 @@ void handleVectorizeLoopsArgs(const llvm::opt::ArgList &Args, void handleVectorizeSLPArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs); -// Parse -mprefer-vector-width=. Return the Value string if well-formed. -// Otherwise, return an empty string and issue a diagnosic message if needed. -StringRef parseMPreferVectorWidthOption(clang::DiagnosticsEngine &Diags, - const llvm::opt::ArgList &Args); - -// Parse -mrecip. Return the Value string if well-formed. -// Otherwise, return an empty string and issue a diagnosic message if needed. -StringRef parseMRecipOption(clang::DiagnosticsEngine &Diags, - const llvm::opt::ArgList &Args); - // Convert ComplexRangeKind to a string that can be passed as a frontend option. std::string complexRangeKindToStr(LangOptions::ComplexRangeKind Range); diff --git a/clang/include/clang/Driver/CreateASTUnitFromArgs.h b/clang/include/clang/Driver/CreateASTUnitFromArgs.h new file mode 100644 index 0000000000000..30575cc04ca7c --- /dev/null +++ b/clang/include/clang/Driver/CreateASTUnitFromArgs.h @@ -0,0 +1,80 @@ +//===-- CreateInvocationFromArgs.h - Create an ASTUnit from Args-*- 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 +// +//===----------------------------------------------------------------------===// +// +// Utility for creating an ASTUnit from a vector of command line arguments. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_DRIVER_CREATEASTUNITFROMARGS_H +#define LLVM_CLANG_DRIVER_CREATEASTUNITFROMARGS_H + +#include "clang/Frontend/ASTUnit.h" + +namespace clang { + +/// Create an ASTUnit from a vector of command line arguments, which must +/// specify exactly one source file. +/// +/// \param ArgBegin - The beginning of the argument vector. +/// +/// \param ArgEnd - The end of the argument vector. +/// +/// \param PCHContainerOps - The PCHContainerOperations to use for loading and +/// creating modules. +/// +/// \param Diags - The diagnostics engine to use for reporting errors; its +/// lifetime is expected to extend past that of the returned ASTUnit. +/// +/// \param ResourceFilesPath - The path to the compiler resource files. +/// +/// \param StorePreamblesInMemory - Whether to store PCH in memory. If false, +/// PCH are stored in temporary files. +/// +/// \param PreambleStoragePath - The path to a directory, in which to create +/// temporary PCH files. If empty, the default system temporary directory is +/// used. This parameter is ignored if \p StorePreamblesInMemory is true. +/// +/// \param ModuleFormat - If provided, uses the specific module format. +/// +/// \param ErrAST - If non-null and parsing failed without any AST to return +/// (e.g. because the PCH could not be loaded), this accepts the ASTUnit +/// mainly to allow the caller to see the diagnostics. +/// +/// \param VFS - A llvm::vfs::FileSystem to be used for all file accesses. +/// Note that preamble is saved to a temporary directory on a RealFileSystem, +/// so in order for it to be loaded correctly, VFS should have access to +/// it(i.e., be an overlay over RealFileSystem). RealFileSystem will be used +/// if \p VFS is nullptr. +/// +// FIXME: Move OnlyLocalDecls, UseBumpAllocator to setters on the ASTUnit, we +// shouldn't need to specify them at construction time. +std::unique_ptr CreateASTUnitFromCommandLine( + const char **ArgBegin, const char **ArgEnd, + std::shared_ptr PCHContainerOps, + std::shared_ptr DiagOpts, + IntrusiveRefCntPtr Diags, StringRef ResourceFilesPath, + bool StorePreamblesInMemory = false, + StringRef PreambleStoragePath = StringRef(), bool OnlyLocalDecls = false, + CaptureDiagsKind CaptureDiagnostics = CaptureDiagsKind::None, + ArrayRef RemappedFiles = {}, + bool RemappedFilesKeepOriginalName = true, + unsigned PrecompilePreambleAfterNParses = 0, + TranslationUnitKind TUKind = TU_Complete, + bool CacheCodeCompletionResults = false, + bool IncludeBriefCommentsInCodeCompletion = false, + bool AllowPCHWithCompilerErrors = false, + SkipFunctionBodiesScope SkipFunctionBodies = SkipFunctionBodiesScope::None, + bool SingleFileParse = false, bool UserFilesAreVolatile = false, + bool ForSerialization = false, bool RetainExcludedConditionalBlocks = false, + std::optional ModuleFormat = std::nullopt, + std::unique_ptr *ErrAST = nullptr, + IntrusiveRefCntPtr VFS = nullptr); + +} // namespace clang + +#endif // LLVM_CLANG_DRIVER_CREATEASTUNITFROMARGS_H diff --git a/clang/include/clang/Driver/CreateInvocationFromArgs.h b/clang/include/clang/Driver/CreateInvocationFromArgs.h new file mode 100644 index 0000000000000..0e0f67373ce87 --- /dev/null +++ b/clang/include/clang/Driver/CreateInvocationFromArgs.h @@ -0,0 +1,76 @@ +//===--- CreateInvocationFromArgs.h - CompilerInvocation from Args --------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// Utility for creating a CompilerInvocation from command-line arguments, for +// tools to use in preparation to parse a file. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_DRIVER_CREATEINVOCATIONFROMARGS_H +#define LLVM_CLANG_DRIVER_CREATEINVOCATIONFROMARGS_H + +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/LLVM.h" +#include "llvm/Support/VirtualFileSystem.h" +#include +#include +#include + +namespace clang { + +class CompilerInvocation; +class DiagnosticsEngine; + +/// Optional inputs to createInvocation. +struct CreateInvocationOptions { + /// Receives diagnostics encountered while parsing command-line flags. + /// If not provided, these are printed to stderr. + IntrusiveRefCntPtr Diags = nullptr; + /// Used e.g. to probe for system headers locations. + /// If not provided, the real filesystem is used. + /// FIXME: the driver does perform some non-virtualized IO. + IntrusiveRefCntPtr VFS = nullptr; + /// Whether to attempt to produce a non-null (possibly incorrect) invocation + /// if any errors were encountered. + /// By default, always return null on errors. + bool RecoverOnError = false; + /// Allow the driver to probe the filesystem for PCH files. + /// This is used to replace -include with -include-pch in the cc1 args. + /// FIXME: ProbePrecompiled=true is a poor, historical default. + /// It misbehaves if the PCH file is from GCC, has the wrong version, etc. + bool ProbePrecompiled = false; + /// If set, the target is populated with the cc1 args produced by the driver. + /// This may be populated even if createInvocation returns nullptr. + std::vector *CC1Args = nullptr; +}; + +/// Interpret clang arguments in preparation to parse a file. +/// +/// This simulates a number of steps Clang takes when its driver is invoked: +/// - choosing actions (e.g compile + link) to run +/// - probing the system for settings like standard library locations +/// - spawning a cc1 subprocess to compile code, with more explicit arguments +/// - in the cc1 process, assembling those arguments into a CompilerInvocation +/// which is used to configure the parser +/// +/// This simulation is lossy, e.g. in some situations one driver run would +/// result in multiple parses. (Multi-arch, CUDA, ...). +/// This function tries to select a reasonable invocation that tools should use. +/// +/// Args[0] should be the driver name, such as "clang" or "/usr/bin/g++". +/// Absolute path is preferred - this affects searching for system headers. +/// +/// May return nullptr if an invocation could not be determined. +/// See CreateInvocationOptions::RecoverOnError to try harder! +std::unique_ptr +createInvocation(ArrayRef Args, + CreateInvocationOptions Opts = {}); + +} // namespace clang + +#endif // LLVM_CLANG_DRIVER_CREATEINVOCATIONFROMARGS_H diff --git a/clang/include/clang/Driver/Driver.h b/clang/include/clang/Driver/Driver.h index aa86bffb802a4..76a6c5a128efb 100644 --- a/clang/include/clang/Driver/Driver.h +++ b/clang/include/clang/Driver/Driver.h @@ -406,11 +406,6 @@ class Driver { SmallString<128> &CrashDiagDir); public: - - /// Takes the path to a binary that's either in bin/ or lib/ and returns - /// the path to clang's resource directory. - static std::string GetResourcesPath(StringRef BinaryPath); - Driver(StringRef ClangExecutable, StringRef TargetTriple, DiagnosticsEngine &Diags, std::string Title = "clang LLVM compiler", IntrusiveRefCntPtr VFS = nullptr); diff --git a/clang/include/clang/Frontend/ASTUnit.h b/clang/include/clang/Frontend/ASTUnit.h index 3cea159afa33c..341460e1962cb 100644 --- a/clang/include/clang/Frontend/ASTUnit.h +++ b/clang/include/clang/Frontend/ASTUnit.h @@ -22,12 +22,14 @@ #include "clang/Basic/SourceLocation.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetOptions.h" +#include "clang/Frontend/PrecompiledPreamble.h" +#include "clang/Frontend/StandaloneDiagnostic.h" #include "clang/Lex/HeaderSearchOptions.h" #include "clang/Lex/ModuleLoader.h" #include "clang/Lex/PreprocessingRecord.h" #include "clang/Sema/CodeCompleteConsumer.h" #include "clang/Serialization/ASTBitCodes.h" -#include "clang/Frontend/PrecompiledPreamble.h" +#include "clang/Serialization/ASTWriter.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/IntrusiveRefCntPtr.h" @@ -36,6 +38,7 @@ #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/iterator_range.h" +#include "llvm/Bitstream/BitstreamWriter.h" #include #include #include @@ -88,25 +91,6 @@ enum class CaptureDiagsKind { None, All, AllWithoutNonErrorsFromIncludes }; /// Utility class for loading a ASTContext from an AST file. class ASTUnit { -public: - struct StandaloneFixIt { - std::pair RemoveRange; - std::pair InsertFromRange; - std::string CodeToInsert; - bool BeforePreviousInsertions; - }; - - struct StandaloneDiagnostic { - unsigned ID; - DiagnosticsEngine::Level Level; - std::string Message; - std::string Filename; - unsigned LocOffset; - std::vector> Ranges; - std::vector FixIts; - }; - -private: std::unique_ptr LangOpts; std::unique_ptr CodeGenOpts; // FIXME: The documentation on \c LoadFrom* member functions states that the @@ -129,7 +113,15 @@ class ASTUnit { bool HadModuleLoaderFatalFailure = false; bool StorePreamblesInMemory = false; - struct ASTWriterData; + /// Utility struct for managing ASTWriter and its associated data streams. + struct ASTWriterData { + SmallString<128> Buffer; + llvm::BitstreamWriter Stream; + ASTWriter Writer; + + ASTWriterData(ModuleCache &ModCache, const CodeGenOptions &CGOpts) + : Stream(Buffer), Writer(Stream, Buffer, ModCache, CGOpts, {}) {} + }; std::unique_ptr WriterData; FileSystemOptions FileSystemOpts; @@ -271,11 +263,6 @@ class ASTUnit { static void ConfigureDiags(IntrusiveRefCntPtr Diags, ASTUnit &AST, CaptureDiagsKind CaptureDiagnostics); - void TranslateStoredDiagnostics(FileManager &FileMgr, - SourceManager &SrcMan, - const SmallVectorImpl &Diags, - SmallVectorImpl &Out); - void clearFileLevelDecls(); public: @@ -834,65 +821,24 @@ class ASTUnit { bool IncludeBriefCommentsInCodeCompletion = false, bool UserFilesAreVolatile = false); - /// LoadFromCommandLine - Create an ASTUnit from a vector of command line - /// arguments, which must specify exactly one source file. - /// - /// \param ArgBegin - The beginning of the argument vector. - /// - /// \param ArgEnd - The end of the argument vector. - /// - /// \param PCHContainerOps - The PCHContainerOperations to use for loading and - /// creating modules. - /// - /// \param Diags - The diagnostics engine to use for reporting errors; its - /// lifetime is expected to extend past that of the returned ASTUnit. - /// - /// \param ResourceFilesPath - The path to the compiler resource files. - /// - /// \param StorePreamblesInMemory - Whether to store PCH in memory. If false, - /// PCH are stored in temporary files. - /// - /// \param PreambleStoragePath - The path to a directory, in which to create - /// temporary PCH files. If empty, the default system temporary directory is - /// used. This parameter is ignored if \p StorePreamblesInMemory is true. - /// - /// \param ModuleFormat - If provided, uses the specific module format. - /// - /// \param ErrAST - If non-null and parsing failed without any AST to return - /// (e.g. because the PCH could not be loaded), this accepts the ASTUnit - /// mainly to allow the caller to see the diagnostics. - /// - /// \param VFS - A llvm::vfs::FileSystem to be used for all file accesses. - /// Note that preamble is saved to a temporary directory on a RealFileSystem, - /// so in order for it to be loaded correctly, VFS should have access to - /// it(i.e., be an overlay over RealFileSystem). RealFileSystem will be used - /// if \p VFS is nullptr. - /// - // FIXME: Move OnlyLocalDecls, UseBumpAllocator to setters on the ASTUnit, we - // shouldn't need to specify them at construction time. - static std::unique_ptr LoadFromCommandLine( + friend std::unique_ptr CreateASTUnitFromCommandLine( const char **ArgBegin, const char **ArgEnd, std::shared_ptr PCHContainerOps, std::shared_ptr DiagOpts, IntrusiveRefCntPtr Diags, StringRef ResourceFilesPath, - bool StorePreamblesInMemory = false, - StringRef PreambleStoragePath = StringRef(), bool OnlyLocalDecls = false, - CaptureDiagsKind CaptureDiagnostics = CaptureDiagsKind::None, - ArrayRef RemappedFiles = {}, - bool RemappedFilesKeepOriginalName = true, - unsigned PrecompilePreambleAfterNParses = 0, - TranslationUnitKind TUKind = TU_Complete, - bool CacheCodeCompletionResults = false, - bool IncludeBriefCommentsInCodeCompletion = false, - bool AllowPCHWithCompilerErrors = false, - SkipFunctionBodiesScope SkipFunctionBodies = - SkipFunctionBodiesScope::None, - bool SingleFileParse = false, bool UserFilesAreVolatile = false, - bool ForSerialization = false, - bool RetainExcludedConditionalBlocks = false, - std::optional ModuleFormat = std::nullopt, - std::unique_ptr *ErrAST = nullptr, - IntrusiveRefCntPtr VFS = nullptr); + bool StorePreamblesInMemory, StringRef PreambleStoragePath, + bool OnlyLocalDecls, CaptureDiagsKind CaptureDiagnostics, + ArrayRef RemappedFiles, + bool RemappedFilesKeepOriginalName, + unsigned PrecompilePreambleAfterNParses, TranslationUnitKind TUKind, + bool CacheCodeCompletionResults, + bool IncludeBriefCommentsInCodeCompletion, + bool AllowPCHWithCompilerErrors, + SkipFunctionBodiesScope SkipFunctionBodies, bool SingleFileParse, + bool UserFilesAreVolatile, bool ForSerialization, + bool RetainExcludedConditionalBlocks, + std::optional ModuleFormat, std::unique_ptr *ErrAST, + IntrusiveRefCntPtr VFS); /// Reparse the source files using the same command-line options that /// were originally used to produce this translation unit. @@ -963,6 +909,44 @@ class ASTUnit { bool serialize(raw_ostream &OS); }; +/// Diagnostic consumer that saves each diagnostic it is given. +class FilterAndStoreDiagnosticConsumer : public DiagnosticConsumer { + SmallVectorImpl *StoredDiags; + SmallVectorImpl *StandaloneDiags; + bool CaptureNonErrorsFromIncludes = true; + const LangOptions *LangOpts = nullptr; + SourceManager *SourceMgr = nullptr; + +public: + FilterAndStoreDiagnosticConsumer( + SmallVectorImpl *StoredDiags, + SmallVectorImpl *StandaloneDiags, + bool CaptureNonErrorsFromIncludes); + + void BeginSourceFile(const LangOptions &LangOpts, + const Preprocessor *PP = nullptr) override; + + void HandleDiagnostic(DiagnosticsEngine::Level Level, + const Diagnostic &Info) override; +}; + +/// RAII object that optionally captures and filters diagnostics, if +/// there is no diagnostic client to capture them already. +class CaptureDroppedDiagnostics { + DiagnosticsEngine &Diags; + FilterAndStoreDiagnosticConsumer Client; + DiagnosticConsumer *PreviousClient = nullptr; + std::unique_ptr OwningPreviousClient; + +public: + CaptureDroppedDiagnostics( + CaptureDiagsKind CaptureDiagnostics, DiagnosticsEngine &Diags, + SmallVectorImpl *StoredDiags, + SmallVectorImpl *StandaloneDiags); + + ~CaptureDroppedDiagnostics(); +}; + } // namespace clang #endif // LLVM_CLANG_FRONTEND_ASTUNIT_H diff --git a/clang/include/clang/Frontend/ChainedDiagnosticConsumer.h b/clang/include/clang/Frontend/ChainedDiagnosticConsumer.h index ca284560754fd..839b5e7fa0a3e 100644 --- a/clang/include/clang/Frontend/ChainedDiagnosticConsumer.h +++ b/clang/include/clang/Frontend/ChainedDiagnosticConsumer.h @@ -66,6 +66,6 @@ class ChainedDiagnosticConsumer : public DiagnosticConsumer { } }; -} // end namspace clang +} // namespace clang #endif diff --git a/clang/include/clang/Frontend/CompilerInvocation.h b/clang/include/clang/Frontend/CompilerInvocation.h index b19a6e1a8acc3..4977ddb307d21 100644 --- a/clang/include/clang/Frontend/CompilerInvocation.h +++ b/clang/include/clang/Frontend/CompilerInvocation.h @@ -299,16 +299,6 @@ class CompilerInvocation : public CompilerInvocationBase { DiagnosticsEngine &Diags, const char *Argv0 = nullptr); - /// Get the directory where the compiler headers - /// reside, relative to the compiler binary (found by the passed in - /// arguments). - /// - /// \param Argv0 - The program path (from argv[0]), for finding the builtin - /// compiler path. - /// \param MainAddr - The address of main (or some other function in the main - /// executable), for finding the builtin compiler path. - static std::string GetResourcesPath(const char *Argv0, void *MainAddr); - /// Populate \p Opts with the default set of pointer authentication-related /// options given \p LangOpts and \p Triple. /// diff --git a/clang/include/clang/Frontend/StandaloneDiagnostic.h b/clang/include/clang/Frontend/StandaloneDiagnostic.h new file mode 100644 index 0000000000000..c23d5f95e0c2f --- /dev/null +++ b/clang/include/clang/Frontend/StandaloneDiagnostic.h @@ -0,0 +1,82 @@ +//===--- StandaloneDiagnostic.h - Serializable Diagnostic -------*- 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 +// +//===----------------------------------------------------------------------===// +// +// A serializable diagnostic representation to retain diagnostics after their +// SourceManager has been destroyed. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FRONTEND_STANDALONEDIAGNOSTICS_H +#define LLVM_CLANG_FRONTEND_STANDALONEDIAGNOSTICS_H + +#include "clang/Basic/DiagnosticIDs.h" +#include "clang/Basic/DiagnosticOptions.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/Specifiers.h" +#include "llvm/ADT/StringExtras.h" +#include +#include +#include + +namespace clang { + +/// Represents a StoredDiagnostic in a form that can be retained until after its +/// SourceManager has been destroyed. +/// +/// Source locations are stored as a combination of filename and offsets into +/// that file. +/// To report the diagnostic, it must first be translated back into a +/// StoredDiagnostic with a new associated SourceManager. +struct StandaloneDiagnostic { + /// Represents a CharSourceRange within a StandaloneDiagnostic. + struct SourceOffsetRange { + SourceOffsetRange(CharSourceRange Range, const SourceManager &SrcMgr, + const LangOptions &LangOpts); + + unsigned Begin = 0; + unsigned End = 0; + }; + + /// Represents a FixItHint within a StandaloneDiagnostic. + struct StandaloneFixIt { + StandaloneFixIt(const SourceManager &SrcMgr, const LangOptions &LangOpts, + const FixItHint &FixIt); + + SourceOffsetRange RemoveRange; + SourceOffsetRange InsertFromRange; + std::string CodeToInsert; + bool BeforePreviousInsertions; + }; + + StandaloneDiagnostic(const LangOptions &LangOpts, + const StoredDiagnostic &InDiag); + + DiagnosticsEngine::Level Level; + SrcMgr::CharacteristicKind FileKind; + unsigned ID = 0; + unsigned FileOffset = 0; + std::string Message; + std::string Filename; + std::vector Ranges; + std::vector FixIts; +}; + +/// Translates \c StandaloneDiag into a StoredDiagnostic, associating it with +/// the provided FileManager and SourceManager. +/// +/// This allows the diagnostic to be emitted using the diagnostics engine, since +/// StandaloneDiagnostics themselfs cannot be emitted directly. +StoredDiagnostic +translateStandaloneDiag(FileManager &FileMgr, SourceManager &SrcMgr, + const StandaloneDiagnostic &StandaloneDiag, + llvm::StringMap &SrcLocCache); + +} // namespace clang + +#endif // STANDALONEDIAGNOSTICS diff --git a/clang/include/clang/Frontend/Utils.h b/clang/include/clang/Frontend/Utils.h index ed2703c76f18d..1c561b47b5c47 100644 --- a/clang/include/clang/Frontend/Utils.h +++ b/clang/include/clang/Frontend/Utils.h @@ -192,51 +192,6 @@ IntrusiveRefCntPtr createChainedIncludesSource(CompilerInstance &CI, IntrusiveRefCntPtr &OutReader); -/// Optional inputs to createInvocation. -struct CreateInvocationOptions { - /// Receives diagnostics encountered while parsing command-line flags. - /// If not provided, these are printed to stderr. - IntrusiveRefCntPtr Diags = nullptr; - /// Used e.g. to probe for system headers locations. - /// If not provided, the real filesystem is used. - /// FIXME: the driver does perform some non-virtualized IO. - IntrusiveRefCntPtr VFS = nullptr; - /// Whether to attempt to produce a non-null (possibly incorrect) invocation - /// if any errors were encountered. - /// By default, always return null on errors. - bool RecoverOnError = false; - /// Allow the driver to probe the filesystem for PCH files. - /// This is used to replace -include with -include-pch in the cc1 args. - /// FIXME: ProbePrecompiled=true is a poor, historical default. - /// It misbehaves if the PCH file is from GCC, has the wrong version, etc. - bool ProbePrecompiled = false; - /// If set, the target is populated with the cc1 args produced by the driver. - /// This may be populated even if createInvocation returns nullptr. - std::vector *CC1Args = nullptr; -}; - -/// Interpret clang arguments in preparation to parse a file. -/// -/// This simulates a number of steps Clang takes when its driver is invoked: -/// - choosing actions (e.g compile + link) to run -/// - probing the system for settings like standard library locations -/// - spawning a cc1 subprocess to compile code, with more explicit arguments -/// - in the cc1 process, assembling those arguments into a CompilerInvocation -/// which is used to configure the parser -/// -/// This simulation is lossy, e.g. in some situations one driver run would -/// result in multiple parses. (Multi-arch, CUDA, ...). -/// This function tries to select a reasonable invocation that tools should use. -/// -/// Args[0] should be the driver name, such as "clang" or "/usr/bin/g++". -/// Absolute path is preferred - this affects searching for system headers. -/// -/// May return nullptr if an invocation could not be determined. -/// See CreateInvocationOptions::ShouldRecoverOnErrors to try harder! -std::unique_ptr -createInvocation(ArrayRef Args, - CreateInvocationOptions Opts = {}); - } // namespace clang #endif // LLVM_CLANG_FRONTEND_UTILS_H diff --git a/clang/include/clang/Options/OptionUtils.h b/clang/include/clang/Options/OptionUtils.h index 83c48bd7d6843..02c9c27554db1 100644 --- a/clang/include/clang/Options/OptionUtils.h +++ b/clang/include/clang/Options/OptionUtils.h @@ -28,6 +28,7 @@ class ArgList; } // namespace llvm namespace clang { + /// Return the value of the last argument as an integer, or a default. If Diags /// is non-null, emits an error if the argument is given, but non-integral. int getLastArgIntValue(const llvm::opt::ArgList &Args, @@ -53,6 +54,29 @@ inline uint64_t getLastArgUInt64Value(const llvm::opt::ArgList &Args, return getLastArgUInt64Value(Args, Id, Default, &Diags, Base); } +// Parse -mprefer-vector-width=. Return the Value string if well-formed. +// Otherwise, return an empty string and issue a diagnosic message if needed. +StringRef parseMPreferVectorWidthOption(clang::DiagnosticsEngine &Diags, + const llvm::opt::ArgList &Args); + +// Parse -mrecip. Return the Value string if well-formed. +// Otherwise, return an empty string and issue a diagnosic message if needed. +StringRef parseMRecipOption(clang::DiagnosticsEngine &Diags, + const llvm::opt::ArgList &Args); + +/// Get the directory where the compiler headers reside, relative to the +/// compiler binary path \p BinaryPath. +std::string GetResourcesPath(StringRef BinaryPath); + +/// Get the directory where the compiler headers reside, relative to the +/// compiler binary path (found by the passed in arguments). +/// +/// \param Argv0 The program path (from argv[0]), for finding the builtin +/// compiler path. +/// \param MainAddr The address of main (or some other function in the main +/// executable), for finding the builtin compiler path. +std::string GetResourcesPath(const char *Argv0, void *MainAddr); + } // namespace clang #endif // LLVM_CLANG_OPTIONS_OPTIONUTILS_H diff --git a/clang/lib/CrossTU/CMakeLists.txt b/clang/lib/CrossTU/CMakeLists.txt index 3349fc283925d..eef7a892701fb 100644 --- a/clang/lib/CrossTU/CMakeLists.txt +++ b/clang/lib/CrossTU/CMakeLists.txt @@ -9,6 +9,7 @@ add_clang_library(clangCrossTU LINK_LIBS clangAST clangBasic + clangDriver clangFrontend clangIndex ) diff --git a/clang/lib/CrossTU/CrossTranslationUnit.cpp b/clang/lib/CrossTU/CrossTranslationUnit.cpp index 0287845a741ed..a3fc2cf6bfb3c 100644 --- a/clang/lib/CrossTU/CrossTranslationUnit.cpp +++ b/clang/lib/CrossTU/CrossTranslationUnit.cpp @@ -16,6 +16,7 @@ #include "clang/Basic/DiagnosticDriver.h" #include "clang/Basic/TargetInfo.h" #include "clang/CrossTU/CrossTUDiagnostic.h" +#include "clang/Driver/CreateASTUnitFromArgs.h" #include "clang/Frontend/ASTUnit.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/TextDiagnosticPrinter.h" @@ -619,7 +620,7 @@ CrossTranslationUnitContext::ASTLoader::loadFromSource( auto Diags = llvm::makeIntrusiveRefCnt(DiagID, *DiagOpts, DiagClient); - return ASTUnit::LoadFromCommandLine( + return CreateASTUnitFromCommandLine( CommandLineArgs.begin(), (CommandLineArgs.end()), CI.getPCHContainerOperations(), DiagOpts, Diags, CI.getHeaderSearchOpts().ResourceDir); diff --git a/clang/lib/Driver/CMakeLists.txt b/clang/lib/Driver/CMakeLists.txt index 8052659e9836b..d987111827597 100644 --- a/clang/lib/Driver/CMakeLists.txt +++ b/clang/lib/Driver/CMakeLists.txt @@ -17,6 +17,8 @@ endif() add_clang_library(clangDriver Action.cpp Compilation.cpp + CreateASTUnitFromArgs.cpp + CreateInvocationFromArgs.cpp Distro.cpp Driver.cpp Job.cpp @@ -96,6 +98,8 @@ add_clang_library(clangDriver LINK_LIBS clangBasic + clangFrontend + clangSerialization clangLex clangOptions ${system_libs} diff --git a/clang/lib/Driver/CreateASTUnitFromArgs.cpp b/clang/lib/Driver/CreateASTUnitFromArgs.cpp new file mode 100644 index 0000000000000..ea31a8ed07c5f --- /dev/null +++ b/clang/lib/Driver/CreateASTUnitFromArgs.cpp @@ -0,0 +1,166 @@ +//===--- CreateASTUnitFromArgs.h - Create an ASTUnit from Args ------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// Utility for creating an ASTUnit from a vector of command line arguments. +// +//===----------------------------------------------------------------------===// + +#include "clang/Driver/CreateASTUnitFromArgs.h" +#include "clang/Driver/CreateInvocationFromArgs.h" +#include "clang/Frontend/CompilerInvocation.h" +#include "clang/Lex/PreprocessorOptions.h" +#include "clang/Serialization/ModuleCache.h" +#include "llvm/Support/CrashRecoveryContext.h" + +using namespace clang; + +/// Create an ASTUnit from a vector of command line arguments, which must +/// specify exactly one source file. +/// +/// \param ArgBegin - The beginning of the argument vector. +/// +/// \param ArgEnd - The end of the argument vector. +/// +/// \param PCHContainerOps - The PCHContainerOperations to use for loading and +/// creating modules. +/// +/// \param Diags - The diagnostics engine to use for reporting errors; its +/// lifetime is expected to extend past that of the returned ASTUnit. +/// +/// \param ResourceFilesPath - The path to the compiler resource files. +/// +/// \param StorePreamblesInMemory - Whether to store PCH in memory. If false, +/// PCH are stored in temporary files. +/// +/// \param PreambleStoragePath - The path to a directory, in which to create +/// temporary PCH files. If empty, the default system temporary directory is +/// used. This parameter is ignored if \p StorePreamblesInMemory is true. +/// +/// \param ModuleFormat - If provided, uses the specific module format. +/// +/// \param ErrAST - If non-null and parsing failed without any AST to return +/// (e.g. because the PCH could not be loaded), this accepts the ASTUnit +/// mainly to allow the caller to see the diagnostics. +/// +/// \param VFS - A llvm::vfs::FileSystem to be used for all file accesses. +/// Note that preamble is saved to a temporary directory on a RealFileSystem, +/// so in order for it to be loaded correctly, VFS should have access to +/// it(i.e., be an overlay over RealFileSystem). RealFileSystem will be used +/// if \p VFS is nullptr. +/// +// FIXME: Move OnlyLocalDecls, UseBumpAllocator to setters on the ASTUnit, we +// shouldn't need to specify them at construction time. +std::unique_ptr clang::CreateASTUnitFromCommandLine( + const char **ArgBegin, const char **ArgEnd, + std::shared_ptr PCHContainerOps, + std::shared_ptr DiagOpts, + IntrusiveRefCntPtr Diags, StringRef ResourceFilesPath, + bool StorePreamblesInMemory, StringRef PreambleStoragePath, + bool OnlyLocalDecls, CaptureDiagsKind CaptureDiagnostics, + ArrayRef RemappedFiles, + bool RemappedFilesKeepOriginalName, unsigned PrecompilePreambleAfterNParses, + TranslationUnitKind TUKind, bool CacheCodeCompletionResults, + bool IncludeBriefCommentsInCodeCompletion, bool AllowPCHWithCompilerErrors, + SkipFunctionBodiesScope SkipFunctionBodies, bool SingleFileParse, + bool UserFilesAreVolatile, bool ForSerialization, + bool RetainExcludedConditionalBlocks, std::optional ModuleFormat, + std::unique_ptr *ErrAST, + IntrusiveRefCntPtr VFS) { + assert(Diags.get() && "no DiagnosticsEngine was provided"); + + // If no VFS was provided, create one that tracks the physical file system. + // If '-working-directory' was passed as an argument, 'createInvocation' will + // set this as the current working directory of the VFS. + if (!VFS) + VFS = llvm::vfs::createPhysicalFileSystem(); + + SmallVector StoredDiagnostics; + + std::shared_ptr CI; + + { + CaptureDroppedDiagnostics Capture(CaptureDiagnostics, *Diags, + &StoredDiagnostics, nullptr); + + CreateInvocationOptions CIOpts; + CIOpts.VFS = VFS; + CIOpts.Diags = Diags; + CIOpts.ProbePrecompiled = true; // FIXME: historical default. Needed? + CI = createInvocation(llvm::ArrayRef(ArgBegin, ArgEnd), std::move(CIOpts)); + if (!CI) + return nullptr; + } + + // Override any files that need remapping + for (const auto &RemappedFile : RemappedFiles) { + CI->getPreprocessorOpts().addRemappedFile(RemappedFile.first, + RemappedFile.second); + } + PreprocessorOptions &PPOpts = CI->getPreprocessorOpts(); + PPOpts.RemappedFilesKeepOriginalName = RemappedFilesKeepOriginalName; + PPOpts.AllowPCHWithCompilerErrors = AllowPCHWithCompilerErrors; + PPOpts.SingleFileParseMode = SingleFileParse; + PPOpts.RetainExcludedConditionalBlocks = RetainExcludedConditionalBlocks; + + // Override the resources path. + CI->getHeaderSearchOpts().ResourceDir = std::string(ResourceFilesPath); + + CI->getFrontendOpts().SkipFunctionBodies = + SkipFunctionBodies == SkipFunctionBodiesScope::PreambleAndMainFile; + + if (ModuleFormat) + CI->getHeaderSearchOpts().ModuleFormat = std::string(*ModuleFormat); + + // Create the AST unit. + std::unique_ptr AST; + AST.reset(new ASTUnit(false)); + AST->NumStoredDiagnosticsFromDriver = StoredDiagnostics.size(); + AST->StoredDiagnostics.swap(StoredDiagnostics); + ASTUnit::ConfigureDiags(Diags, *AST, CaptureDiagnostics); + AST->DiagOpts = DiagOpts; + AST->Diagnostics = Diags; + AST->FileSystemOpts = CI->getFileSystemOpts(); + AST->CodeGenOpts = std::make_unique(CI->getCodeGenOpts()); + VFS = createVFSFromCompilerInvocation(*CI, *Diags, VFS); + AST->FileMgr = + llvm::makeIntrusiveRefCnt(AST->FileSystemOpts, VFS); + AST->StorePreamblesInMemory = StorePreamblesInMemory; + AST->PreambleStoragePath = PreambleStoragePath; + AST->ModCache = createCrossProcessModuleCache(); + AST->OnlyLocalDecls = OnlyLocalDecls; + AST->CaptureDiagnostics = CaptureDiagnostics; + AST->TUKind = TUKind; + AST->ShouldCacheCodeCompletionResults = CacheCodeCompletionResults; + AST->IncludeBriefCommentsInCodeCompletion = + IncludeBriefCommentsInCodeCompletion; + AST->UserFilesAreVolatile = UserFilesAreVolatile; + AST->Invocation = CI; + AST->SkipFunctionBodies = SkipFunctionBodies; + if (ForSerialization) + AST->WriterData.reset( + new ASTUnit::ASTWriterData(*AST->ModCache, *AST->CodeGenOpts)); + // Zero out now to ease cleanup during crash recovery. + CI = nullptr; + Diags = nullptr; + + // Recover resources if we crash before exiting this method. + llvm::CrashRecoveryContextCleanupRegistrar ASTUnitCleanup(AST.get()); + + if (AST->LoadFromCompilerInvocation(std::move(PCHContainerOps), + PrecompilePreambleAfterNParses, VFS)) { + // Some error occurred, if caller wants to examine diagnostics, pass it the + // ASTUnit. + if (ErrAST) { + AST->StoredDiagnostics.swap(AST->FailedParseDiagnostics); + ErrAST->swap(AST); + } + return nullptr; + } + + return AST; +} diff --git a/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp b/clang/lib/Driver/CreateInvocationFromArgs.cpp similarity index 93% rename from clang/lib/Frontend/CreateInvocationFromCommandLine.cpp rename to clang/lib/Driver/CreateInvocationFromArgs.cpp index 9db594bed1538..516d61f1a1159 100644 --- a/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp +++ b/clang/lib/Driver/CreateInvocationFromArgs.cpp @@ -1,4 +1,4 @@ -//===--- CreateInvocationFromCommandLine.cpp - CompilerInvocation from Args ==// +//===--- CreateInvocationFromArgs.h - CompilerInvocation from Args --------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -10,9 +10,9 @@ // //===----------------------------------------------------------------------===// +#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Basic/DiagnosticFrontend.h" #include "clang/Basic/DiagnosticOptions.h" -#include "clang/Driver/Action.h" #include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" #include "clang/Driver/Tool.h" @@ -24,12 +24,13 @@ #include "llvm/Option/ArgList.h" #include "llvm/Support/VirtualFileSystem.h" #include "llvm/TargetParser/Host.h" -using namespace clang; + using namespace llvm::opt; +namespace clang { + std::unique_ptr -clang::createInvocation(ArrayRef ArgList, - CreateInvocationOptions Opts) { +createInvocation(ArrayRef ArgList, CreateInvocationOptions Opts) { assert(!ArgList.empty()); std::optional LocalDiagOpts; IntrusiveRefCntPtr Diags; @@ -78,7 +79,7 @@ clang::createInvocation(ArrayRef ArgList, const driver::JobList &Jobs = C->getJobs(); bool OffloadCompilation = false; if (Jobs.size() > 1) { - for (auto &A : C->getActions()){ + for (auto &A : C->getActions()) { // On MacOSX real actions may end up being wrapped in BindArchAction if (isa(A)) A = *A->input_begin(); @@ -114,3 +115,5 @@ clang::createInvocation(ArrayRef ArgList, return nullptr; return CI; } + +} // namespace clang diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index de8d4601210ae..c6dd66d9efef3 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -66,6 +66,7 @@ #include "clang/Driver/ToolChain.h" #include "clang/Driver/Types.h" #include "clang/Lex/DependencyDirectivesScanner.h" +#include "clang/Options/OptionUtils.h" #include "clang/Options/Options.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/STLExtras.h" @@ -125,40 +126,6 @@ template static bool usesInput(const ArgList &Args, F &&Fn) { }); } -// static -std::string Driver::GetResourcesPath(StringRef BinaryPath) { - // Since the resource directory is embedded in the module hash, it's important - // that all places that need it call this function, so that they get the - // exact same string ("a/../b/" and "b/" get different hashes, for example). - - // Dir is bin/ or lib/, depending on where BinaryPath is. - StringRef Dir = llvm::sys::path::parent_path(BinaryPath); - SmallString<128> P(Dir); - - StringRef ConfiguredResourceDir(CLANG_RESOURCE_DIR); - if (!ConfiguredResourceDir.empty()) { - // FIXME: We should fix the behavior of llvm::sys::path::append so we don't - // need to check for absolute paths here. - if (llvm::sys::path::is_absolute(ConfiguredResourceDir)) - P = ConfiguredResourceDir; - else - llvm::sys::path::append(P, ConfiguredResourceDir); - } else { - // On Windows, libclang.dll is in bin/. - // On non-Windows, libclang.so/.dylib is in lib/. - // With a static-library build of libclang, LibClangPath will contain the - // path of the embedding binary, which for LLVM binaries will be in bin/. - // ../lib gets us to lib/ in both cases. - P = llvm::sys::path::parent_path(Dir); - // This search path is also created in the COFF driver of lld, so any - // changes here also needs to happen in lld/COFF/Driver.cpp - llvm::sys::path::append(P, CLANG_INSTALL_LIBDIR_BASENAME, "clang", - CLANG_VERSION_MAJOR_STRING); - } - - return std::string(P); -} - CUIDOptions::CUIDOptions(llvm::opt::DerivedArgList &Args, const Driver &D) : UseCUID(Kind::Hash) { if (Arg *A = Args.getLastArg(options::OPT_fuse_cuid_EQ)) { diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index c5d40c9825fab..2f0aec3ec3c37 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -32,6 +32,7 @@ #include "clang/Driver/SanitizerArgs.h" #include "clang/Driver/Types.h" #include "clang/Driver/XRayArgs.h" +#include "clang/Options/OptionUtils.h" #include "clang/Options/Options.h" #include "llvm/ADT/ScopeExit.h" #include "llvm/ADT/SmallSet.h" diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp index 4c036f0f8dee3..d3539a594df11 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -3398,169 +3398,6 @@ void tools::handleInterchangeLoopsArgs(const ArgList &Args, CmdArgs.push_back("-floop-interchange"); } -// Parse -mprefer-vector-width=. Return the Value string if well-formed. -// Otherwise, return an empty string and issue a diagnosic message if needed. -StringRef tools::parseMPreferVectorWidthOption(clang::DiagnosticsEngine &Diags, - const llvm::opt::ArgList &Args) { - Arg *A = Args.getLastArg(options::OPT_mprefer_vector_width_EQ); - if (!A) - return ""; - - StringRef Value = A->getValue(); - unsigned Width LLVM_ATTRIBUTE_UNINITIALIZED; - - // Only "none" and Integer values are accepted by - // -mprefer-vector-width=. - if (Value != "none" && Value.getAsInteger(10, Width)) { - Diags.Report(clang::diag::err_drv_invalid_value) - << A->getOption().getName() << Value; - return ""; - } - - return Value; -} - -// This is a helper function for validating the optional refinement step -// parameter in reciprocal argument strings. Return false if there is an error -// parsing the refinement step. Otherwise, return true and set the Position -// of the refinement step in the input string. -static bool getRefinementStep(StringRef In, clang::DiagnosticsEngine &Diags, - const Arg &A, size_t &Position) { - const char RefinementStepToken = ':'; - Position = In.find(RefinementStepToken); - if (Position != StringRef::npos) { - StringRef Option = A.getOption().getName(); - StringRef RefStep = In.substr(Position + 1); - // Allow exactly one numeric character for the additional refinement - // step parameter. This is reasonable for all currently-supported - // operations and architectures because we would expect that a larger value - // of refinement steps would cause the estimate "optimization" to - // under-perform the native operation. Also, if the estimate does not - // converge quickly, it probably will not ever converge, so further - // refinement steps will not produce a better answer. - if (RefStep.size() != 1) { - Diags.Report(diag::err_drv_invalid_value) << Option << RefStep; - return false; - } - char RefStepChar = RefStep[0]; - if (RefStepChar < '0' || RefStepChar > '9') { - Diags.Report(diag::err_drv_invalid_value) << Option << RefStep; - return false; - } - } - return true; -} - -// Parse -mrecip. Return the Value string if well-formed. -// Otherwise, return an empty string and issue a diagnosic message if needed. -StringRef tools::parseMRecipOption(clang::DiagnosticsEngine &Diags, - const ArgList &Args) { - StringRef DisabledPrefixIn = "!"; - StringRef DisabledPrefixOut = "!"; - StringRef EnabledPrefixOut = ""; - StringRef Out = ""; - - Arg *A = Args.getLastArg(options::OPT_mrecip, options::OPT_mrecip_EQ); - if (!A) - return ""; - - unsigned NumOptions = A->getNumValues(); - if (NumOptions == 0) { - // No option is the same as "all". - return "all"; - } - - // Pass through "all", "none", or "default" with an optional refinement step. - if (NumOptions == 1) { - StringRef Val = A->getValue(0); - size_t RefStepLoc; - if (!getRefinementStep(Val, Diags, *A, RefStepLoc)) - return ""; - StringRef ValBase = Val.slice(0, RefStepLoc); - if (ValBase == "all" || ValBase == "none" || ValBase == "default") { - return Val; - } - } - - // Each reciprocal type may be enabled or disabled individually. - // Check each input value for validity, concatenate them all back together, - // and pass through. - - llvm::StringMap OptionStrings; - OptionStrings.insert(std::make_pair("divd", false)); - OptionStrings.insert(std::make_pair("divf", false)); - OptionStrings.insert(std::make_pair("divh", false)); - OptionStrings.insert(std::make_pair("vec-divd", false)); - OptionStrings.insert(std::make_pair("vec-divf", false)); - OptionStrings.insert(std::make_pair("vec-divh", false)); - OptionStrings.insert(std::make_pair("sqrtd", false)); - OptionStrings.insert(std::make_pair("sqrtf", false)); - OptionStrings.insert(std::make_pair("sqrth", false)); - OptionStrings.insert(std::make_pair("vec-sqrtd", false)); - OptionStrings.insert(std::make_pair("vec-sqrtf", false)); - OptionStrings.insert(std::make_pair("vec-sqrth", false)); - - for (unsigned i = 0; i != NumOptions; ++i) { - StringRef Val = A->getValue(i); - - bool IsDisabled = Val.starts_with(DisabledPrefixIn); - // Ignore the disablement token for string matching. - if (IsDisabled) - Val = Val.substr(1); - - size_t RefStep; - if (!getRefinementStep(Val, Diags, *A, RefStep)) - return ""; - - StringRef ValBase = Val.slice(0, RefStep); - llvm::StringMap::iterator OptionIter = OptionStrings.find(ValBase); - if (OptionIter == OptionStrings.end()) { - // Try again specifying float suffix. - OptionIter = OptionStrings.find(ValBase.str() + 'f'); - if (OptionIter == OptionStrings.end()) { - // The input name did not match any known option string. - Diags.Report(diag::err_drv_unknown_argument) << Val; - return ""; - } - // The option was specified without a half or float or double suffix. - // Make sure that the double or half entry was not already specified. - // The float entry will be checked below. - if (OptionStrings[ValBase.str() + 'd'] || - OptionStrings[ValBase.str() + 'h']) { - Diags.Report(diag::err_drv_invalid_value) - << A->getOption().getName() << Val; - return ""; - } - } - - if (OptionIter->second == true) { - // Duplicate option specified. - Diags.Report(diag::err_drv_invalid_value) - << A->getOption().getName() << Val; - return ""; - } - - // Mark the matched option as found. Do not allow duplicate specifiers. - OptionIter->second = true; - - // If the precision was not specified, also mark the double and half entry - // as found. - if (ValBase.back() != 'f' && ValBase.back() != 'd' && - ValBase.back() != 'h') { - OptionStrings[ValBase.str() + 'd'] = true; - OptionStrings[ValBase.str() + 'h'] = true; - } - - // Build the output string. - StringRef Prefix = IsDisabled ? DisabledPrefixOut : EnabledPrefixOut; - Out = Args.MakeArgString(Out + Prefix + Val); - if (i != NumOptions - 1) - Out = Args.MakeArgString(Out + ","); - } - - return Out; -} - std::string tools::complexRangeKindToStr(LangOptions::ComplexRangeKind Range) { switch (Range) { case LangOptions::ComplexRangeKind::CX_Full: diff --git a/clang/lib/Driver/ToolChains/Flang.cpp b/clang/lib/Driver/ToolChains/Flang.cpp index cc4755cd6a9b0..438de23be0103 100644 --- a/clang/lib/Driver/ToolChains/Flang.cpp +++ b/clang/lib/Driver/ToolChains/Flang.cpp @@ -11,6 +11,7 @@ #include "clang/Basic/CodeGenOptions.h" #include "clang/Driver/CommonArgs.h" +#include "clang/Options/OptionUtils.h" #include "clang/Options/Options.h" #include "llvm/Frontend/Debug/Options.h" #include "llvm/Support/Path.h" diff --git a/clang/lib/Frontend/ASTUnit.cpp b/clang/lib/Frontend/ASTUnit.cpp index db13086bcb470..e72317da64596 100644 --- a/clang/lib/Frontend/ASTUnit.cpp +++ b/clang/lib/Frontend/ASTUnit.cpp @@ -44,6 +44,7 @@ #include "clang/Frontend/FrontendOptions.h" #include "clang/Frontend/MultiplexConsumer.h" #include "clang/Frontend/PrecompiledPreamble.h" +#include "clang/Frontend/StandaloneDiagnostic.h" #include "clang/Frontend/Utils.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/HeaderSearchOptions.h" @@ -210,15 +211,6 @@ getBufferForFileHandlingRemapping(const CompilerInvocation &Invocation, return llvm::MemoryBuffer::getMemBufferCopy(Buffer->getBuffer(), FilePath); } -struct ASTUnit::ASTWriterData { - SmallString<128> Buffer; - llvm::BitstreamWriter Stream; - ASTWriter Writer; - - ASTWriterData(ModuleCache &ModCache, const CodeGenOptions &CGOpts) - : Stream(Buffer), Writer(Stream, Buffer, ModCache, CGOpts, {}) {} -}; - void ASTUnit::clearFileLevelDecls() { FileDecls.clear(); } @@ -581,73 +573,24 @@ class ASTInfoCollector : public ASTReaderListener { Counter = NewCounter; } }; +} // anonymous namespace -/// Diagnostic consumer that saves each diagnostic it is given. -class FilterAndStoreDiagnosticConsumer : public DiagnosticConsumer { - SmallVectorImpl *StoredDiags; - SmallVectorImpl *StandaloneDiags; - bool CaptureNonErrorsFromIncludes = true; - const LangOptions *LangOpts = nullptr; - SourceManager *SourceMgr = nullptr; - -public: - FilterAndStoreDiagnosticConsumer( - SmallVectorImpl *StoredDiags, - SmallVectorImpl *StandaloneDiags, - bool CaptureNonErrorsFromIncludes) - : StoredDiags(StoredDiags), StandaloneDiags(StandaloneDiags), - CaptureNonErrorsFromIncludes(CaptureNonErrorsFromIncludes) { - assert((StoredDiags || StandaloneDiags) && - "No output collections were passed to StoredDiagnosticConsumer."); - } - - void BeginSourceFile(const LangOptions &LangOpts, - const Preprocessor *PP = nullptr) override { - this->LangOpts = &LangOpts; - if (PP) - SourceMgr = &PP->getSourceManager(); - } - - void HandleDiagnostic(DiagnosticsEngine::Level Level, - const Diagnostic &Info) override; -}; - -/// RAII object that optionally captures and filters diagnostics, if -/// there is no diagnostic client to capture them already. -class CaptureDroppedDiagnostics { - DiagnosticsEngine &Diags; - FilterAndStoreDiagnosticConsumer Client; - DiagnosticConsumer *PreviousClient = nullptr; - std::unique_ptr OwningPreviousClient; - -public: - CaptureDroppedDiagnostics( - CaptureDiagsKind CaptureDiagnostics, DiagnosticsEngine &Diags, - SmallVectorImpl *StoredDiags, - SmallVectorImpl *StandaloneDiags) - : Diags(Diags), - Client(StoredDiags, StandaloneDiags, - CaptureDiagnostics != - CaptureDiagsKind::AllWithoutNonErrorsFromIncludes) { - if (CaptureDiagnostics != CaptureDiagsKind::None || - Diags.getClient() == nullptr) { - OwningPreviousClient = Diags.takeClient(); - PreviousClient = Diags.getClient(); - Diags.setClient(&Client, false); - } - } - - ~CaptureDroppedDiagnostics() { - if (Diags.getClient() == &Client) - Diags.setClient(PreviousClient, !!OwningPreviousClient.release()); - } -}; - -} // namespace +FilterAndStoreDiagnosticConsumer::FilterAndStoreDiagnosticConsumer( + SmallVectorImpl *StoredDiags, + SmallVectorImpl *StandaloneDiags, + bool CaptureNonErrorsFromIncludes) + : StoredDiags(StoredDiags), StandaloneDiags(StandaloneDiags), + CaptureNonErrorsFromIncludes(CaptureNonErrorsFromIncludes) { + assert((StoredDiags || StandaloneDiags) && + "No output collections were passed to StoredDiagnosticConsumer."); +} -static ASTUnit::StandaloneDiagnostic -makeStandaloneDiagnostic(const LangOptions &LangOpts, - const StoredDiagnostic &InDiag); +void FilterAndStoreDiagnosticConsumer::BeginSourceFile( + const LangOptions &LangOpts, const Preprocessor *PP) { + this->LangOpts = &LangOpts; + if (PP) + SourceMgr = &PP->getSourceManager(); +} static bool isInMainFile(const clang::Diagnostic &D) { if (!D.hasSourceManager() || !D.getLocation().isValid()) @@ -683,12 +626,32 @@ void FilterAndStoreDiagnosticConsumer::HandleDiagnostic( StoredDiag.emplace(Level, Info); ResultDiag = &*StoredDiag; } - StandaloneDiags->push_back( - makeStandaloneDiagnostic(*LangOpts, *ResultDiag)); + StandaloneDiags->emplace_back(*LangOpts, *ResultDiag); } } } +CaptureDroppedDiagnostics::CaptureDroppedDiagnostics( + CaptureDiagsKind CaptureDiagnostics, DiagnosticsEngine &Diags, + SmallVectorImpl *StoredDiags, + SmallVectorImpl *StandaloneDiags) + : Diags(Diags), + Client(StoredDiags, StandaloneDiags, + CaptureDiagnostics != + CaptureDiagsKind::AllWithoutNonErrorsFromIncludes) { + if (CaptureDiagnostics != CaptureDiagsKind::None || + Diags.getClient() == nullptr) { + OwningPreviousClient = Diags.takeClient(); + PreviousClient = Diags.getClient(); + Diags.setClient(&Client, false); + } +} + +CaptureDroppedDiagnostics::~CaptureDroppedDiagnostics() { + if (Diags.getClient() == &Client) + Diags.setClient(PreviousClient, !!OwningPreviousClient.release()); +} + IntrusiveRefCntPtr ASTUnit::getASTReader() const { return Reader; } @@ -1110,7 +1073,7 @@ class ASTUnitPreambleCallbacks : public PreambleCallbacks { unsigned Hash = 0; std::vector TopLevelDecls; std::vector TopLevelDeclIDs; - llvm::SmallVector PreambleDiags; + llvm::SmallVector PreambleDiags; }; } // namespace @@ -1259,10 +1222,17 @@ bool ASTUnit::Parse(std::shared_ptr PCHContainerOps, if (!Act->BeginSourceFile(*Clang, Clang->getFrontendOpts().Inputs[0])) return true; - if (SavedMainFileBuffer) - TranslateStoredDiagnostics(getFileManager(), getSourceManager(), - PreambleDiagnostics, StoredDiagnostics); - else + if (SavedMainFileBuffer) { + StoredDiagnostics.clear(); + StoredDiagnostics.reserve(PreambleDiagnostics.size()); + llvm::transform(std::move(PreambleDiagnostics), + std::back_inserter(StoredDiagnostics), + [&](auto &&StandaloneDiag) { + return translateStandaloneDiag( + getFileManager(), getSourceManager(), + std::move(StandaloneDiag), PreambleSrcLocCache); + }); + } else PreambleSrcLocCache.clear(); if (llvm::Error Err = Act->Execute()) { @@ -1281,51 +1251,6 @@ bool ASTUnit::Parse(std::shared_ptr PCHContainerOps, return false; } -static std::pair -makeStandaloneRange(CharSourceRange Range, const SourceManager &SM, - const LangOptions &LangOpts) { - CharSourceRange FileRange = Lexer::makeFileCharRange(Range, SM, LangOpts); - unsigned Offset = SM.getFileOffset(FileRange.getBegin()); - unsigned EndOffset = SM.getFileOffset(FileRange.getEnd()); - return std::make_pair(Offset, EndOffset); -} - -static ASTUnit::StandaloneFixIt makeStandaloneFixIt(const SourceManager &SM, - const LangOptions &LangOpts, - const FixItHint &InFix) { - ASTUnit::StandaloneFixIt OutFix; - OutFix.RemoveRange = makeStandaloneRange(InFix.RemoveRange, SM, LangOpts); - OutFix.InsertFromRange = makeStandaloneRange(InFix.InsertFromRange, SM, - LangOpts); - OutFix.CodeToInsert = InFix.CodeToInsert; - OutFix.BeforePreviousInsertions = InFix.BeforePreviousInsertions; - return OutFix; -} - -static ASTUnit::StandaloneDiagnostic -makeStandaloneDiagnostic(const LangOptions &LangOpts, - const StoredDiagnostic &InDiag) { - ASTUnit::StandaloneDiagnostic OutDiag; - OutDiag.ID = InDiag.getID(); - OutDiag.Level = InDiag.getLevel(); - OutDiag.Message = std::string(InDiag.getMessage()); - OutDiag.LocOffset = 0; - if (InDiag.getLocation().isInvalid()) - return OutDiag; - const SourceManager &SM = InDiag.getLocation().getManager(); - SourceLocation FileLoc = SM.getFileLoc(InDiag.getLocation()); - OutDiag.Filename = std::string(SM.getFilename(FileLoc)); - if (OutDiag.Filename.empty()) - return OutDiag; - OutDiag.LocOffset = SM.getFileOffset(FileLoc); - for (const auto &Range : InDiag.getRanges()) - OutDiag.Ranges.push_back(makeStandaloneRange(Range, SM, LangOpts)); - for (const auto &FixIt : InDiag.getFixIts()) - OutDiag.FixIts.push_back(makeStandaloneFixIt(SM, LangOpts, FixIt)); - - return OutDiag; -} - /// Attempt to build or re-use a precompiled preamble when (re-)parsing /// the source file. /// @@ -1780,116 +1705,6 @@ std::unique_ptr ASTUnit::LoadFromCompilerInvocation( return AST; } -std::unique_ptr ASTUnit::LoadFromCommandLine( - const char **ArgBegin, const char **ArgEnd, - std::shared_ptr PCHContainerOps, - std::shared_ptr DiagOpts, - IntrusiveRefCntPtr Diags, StringRef ResourceFilesPath, - bool StorePreamblesInMemory, StringRef PreambleStoragePath, - bool OnlyLocalDecls, CaptureDiagsKind CaptureDiagnostics, - ArrayRef RemappedFiles, bool RemappedFilesKeepOriginalName, - unsigned PrecompilePreambleAfterNParses, TranslationUnitKind TUKind, - bool CacheCodeCompletionResults, bool IncludeBriefCommentsInCodeCompletion, - bool AllowPCHWithCompilerErrors, SkipFunctionBodiesScope SkipFunctionBodies, - bool SingleFileParse, bool UserFilesAreVolatile, bool ForSerialization, - bool RetainExcludedConditionalBlocks, std::optional ModuleFormat, - std::unique_ptr *ErrAST, - IntrusiveRefCntPtr VFS) { - assert(Diags.get() && "no DiagnosticsEngine was provided"); - - // If no VFS was provided, create one that tracks the physical file system. - // If '-working-directory' was passed as an argument, 'createInvocation' will - // set this as the current working directory of the VFS. - if (!VFS) - VFS = llvm::vfs::createPhysicalFileSystem(); - - SmallVector StoredDiagnostics; - - std::shared_ptr CI; - - { - CaptureDroppedDiagnostics Capture(CaptureDiagnostics, *Diags, - &StoredDiagnostics, nullptr); - - CreateInvocationOptions CIOpts; - CIOpts.VFS = VFS; - CIOpts.Diags = Diags; - CIOpts.ProbePrecompiled = true; // FIXME: historical default. Needed? - CI = createInvocation(llvm::ArrayRef(ArgBegin, ArgEnd), std::move(CIOpts)); - if (!CI) - return nullptr; - } - - // Override any files that need remapping - for (const auto &RemappedFile : RemappedFiles) { - CI->getPreprocessorOpts().addRemappedFile(RemappedFile.first, - RemappedFile.second); - } - PreprocessorOptions &PPOpts = CI->getPreprocessorOpts(); - PPOpts.RemappedFilesKeepOriginalName = RemappedFilesKeepOriginalName; - PPOpts.AllowPCHWithCompilerErrors = AllowPCHWithCompilerErrors; - PPOpts.SingleFileParseMode = SingleFileParse; - PPOpts.RetainExcludedConditionalBlocks = RetainExcludedConditionalBlocks; - - // Override the resources path. - CI->getHeaderSearchOpts().ResourceDir = std::string(ResourceFilesPath); - - CI->getFrontendOpts().SkipFunctionBodies = - SkipFunctionBodies == SkipFunctionBodiesScope::PreambleAndMainFile; - - if (ModuleFormat) - CI->getHeaderSearchOpts().ModuleFormat = std::string(*ModuleFormat); - - // Create the AST unit. - std::unique_ptr AST; - AST.reset(new ASTUnit(false)); - AST->NumStoredDiagnosticsFromDriver = StoredDiagnostics.size(); - AST->StoredDiagnostics.swap(StoredDiagnostics); - ConfigureDiags(Diags, *AST, CaptureDiagnostics); - AST->DiagOpts = DiagOpts; - AST->Diagnostics = Diags; - AST->FileSystemOpts = CI->getFileSystemOpts(); - AST->CodeGenOpts = std::make_unique(CI->getCodeGenOpts()); - VFS = createVFSFromCompilerInvocation(*CI, *Diags, VFS); - AST->FileMgr = - llvm::makeIntrusiveRefCnt(AST->FileSystemOpts, VFS); - AST->StorePreamblesInMemory = StorePreamblesInMemory; - AST->PreambleStoragePath = PreambleStoragePath; - AST->ModCache = createCrossProcessModuleCache(); - AST->OnlyLocalDecls = OnlyLocalDecls; - AST->CaptureDiagnostics = CaptureDiagnostics; - AST->TUKind = TUKind; - AST->ShouldCacheCodeCompletionResults = CacheCodeCompletionResults; - AST->IncludeBriefCommentsInCodeCompletion - = IncludeBriefCommentsInCodeCompletion; - AST->UserFilesAreVolatile = UserFilesAreVolatile; - AST->Invocation = CI; - AST->SkipFunctionBodies = SkipFunctionBodies; - if (ForSerialization) - AST->WriterData.reset(new ASTWriterData(*AST->ModCache, *AST->CodeGenOpts)); - // Zero out now to ease cleanup during crash recovery. - CI = nullptr; - Diags = nullptr; - - // Recover resources if we crash before exiting this method. - llvm::CrashRecoveryContextCleanupRegistrar - ASTUnitCleanup(AST.get()); - - if (AST->LoadFromCompilerInvocation(std::move(PCHContainerOps), - PrecompilePreambleAfterNParses, - VFS)) { - // Some error occurred, if caller wants to examine diagnostics, pass it the - // ASTUnit. - if (ErrAST) { - AST->StoredDiagnostics.swap(AST->FailedParseDiagnostics); - ErrAST->swap(AST); - } - return nullptr; - } - - return AST; -} - bool ASTUnit::Reparse(std::shared_ptr PCHContainerOps, ArrayRef RemappedFiles, IntrusiveRefCntPtr VFS) { @@ -2408,65 +2223,6 @@ bool ASTUnit::serialize(raw_ostream &OS) { return serializeUnit(Writer, Buffer, getSema(), OS); } -void ASTUnit::TranslateStoredDiagnostics( - FileManager &FileMgr, - SourceManager &SrcMgr, - const SmallVectorImpl &Diags, - SmallVectorImpl &Out) { - // Map the standalone diagnostic into the new source manager. We also need to - // remap all the locations to the new view. This includes the diag location, - // any associated source ranges, and the source ranges of associated fix-its. - // FIXME: There should be a cleaner way to do this. - SmallVector Result; - Result.reserve(Diags.size()); - - for (const auto &SD : Diags) { - // Rebuild the StoredDiagnostic. - if (SD.Filename.empty()) - continue; - auto FE = FileMgr.getOptionalFileRef(SD.Filename); - if (!FE) - continue; - SourceLocation FileLoc; - auto ItFileID = PreambleSrcLocCache.find(SD.Filename); - if (ItFileID == PreambleSrcLocCache.end()) { - FileID FID = SrcMgr.translateFile(*FE); - FileLoc = SrcMgr.getLocForStartOfFile(FID); - PreambleSrcLocCache[SD.Filename] = FileLoc; - } else { - FileLoc = ItFileID->getValue(); - } - - if (FileLoc.isInvalid()) - continue; - SourceLocation L = FileLoc.getLocWithOffset(SD.LocOffset); - FullSourceLoc Loc(L, SrcMgr); - - SmallVector Ranges; - Ranges.reserve(SD.Ranges.size()); - for (const auto &Range : SD.Ranges) { - SourceLocation BL = FileLoc.getLocWithOffset(Range.first); - SourceLocation EL = FileLoc.getLocWithOffset(Range.second); - Ranges.push_back(CharSourceRange::getCharRange(BL, EL)); - } - - SmallVector FixIts; - FixIts.reserve(SD.FixIts.size()); - for (const auto &FixIt : SD.FixIts) { - FixIts.push_back(FixItHint()); - FixItHint &FH = FixIts.back(); - FH.CodeToInsert = FixIt.CodeToInsert; - SourceLocation BL = FileLoc.getLocWithOffset(FixIt.RemoveRange.first); - SourceLocation EL = FileLoc.getLocWithOffset(FixIt.RemoveRange.second); - FH.RemoveRange = CharSourceRange::getCharRange(BL, EL); - } - - Result.push_back(StoredDiagnostic(SD.Level, SD.ID, - SD.Message, Loc, Ranges, FixIts)); - } - Result.swap(Out); -} - void ASTUnit::addFileLevelDecl(Decl *D) { assert(D); diff --git a/clang/lib/Frontend/CMakeLists.txt b/clang/lib/Frontend/CMakeLists.txt index dac9e0d26f393..634f239933605 100644 --- a/clang/lib/Frontend/CMakeLists.txt +++ b/clang/lib/Frontend/CMakeLists.txt @@ -17,7 +17,6 @@ add_clang_library(clangFrontend ChainedIncludesSource.cpp CompilerInstance.cpp CompilerInvocation.cpp - CreateInvocationFromCommandLine.cpp DependencyFile.cpp DependencyGraph.cpp DiagnosticRenderer.cpp @@ -36,6 +35,7 @@ add_clang_library(clangFrontend SARIFDiagnosticPrinter.cpp SerializedDiagnosticPrinter.cpp SerializedDiagnosticReader.cpp + StandaloneDiagnostic.cpp TestModuleFileExtension.cpp TextDiagnostic.cpp TextDiagnosticBuffer.cpp @@ -51,7 +51,6 @@ add_clang_library(clangFrontend clangAPINotes clangAST clangBasic - clangDriver clangOptions clangEdit clangLex diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index a7bb71565f7f9..5f1c7afdc80a3 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -3272,13 +3272,6 @@ static bool ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, return Diags.getNumErrors() == NumErrorsBefore; } -std::string CompilerInvocation::GetResourcesPath(const char *Argv0, - void *MainAddr) { - std::string ClangExecutable = - llvm::sys::fs::getMainExecutable(Argv0, MainAddr); - return Driver::GetResourcesPath(ClangExecutable); -} - static void GenerateHeaderSearchArgs(const HeaderSearchOptions &Opts, ArgumentConsumer Consumer) { const HeaderSearchOptions *HeaderSearchOpts = &Opts; diff --git a/clang/lib/Frontend/StandaloneDiagnostic.cpp b/clang/lib/Frontend/StandaloneDiagnostic.cpp new file mode 100644 index 0000000000000..4f19c91b7d266 --- /dev/null +++ b/clang/lib/Frontend/StandaloneDiagnostic.cpp @@ -0,0 +1,117 @@ +//===--- StandaloneDiagnostic.h - Serializable Diagnostic ------------- ---===// +// +// 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/Frontend/StandaloneDiagnostic.h" +#include "clang/Lex/Lexer.h" + +namespace clang { + +StandaloneDiagnostic::SourceOffsetRange::SourceOffsetRange( + CharSourceRange Range, const SourceManager &SrcMgr, + const LangOptions &LangOpts) { + const auto FileRange = Lexer::makeFileCharRange(Range, SrcMgr, LangOpts); + Begin = SrcMgr.getFileOffset(FileRange.getBegin()); + End = SrcMgr.getFileOffset(FileRange.getEnd()); +} + +StandaloneDiagnostic::StandaloneFixIt::StandaloneFixIt( + const SourceManager &SrcMgr, const LangOptions &LangOpts, + const FixItHint &FixIt) + : RemoveRange(FixIt.RemoveRange, SrcMgr, LangOpts), + InsertFromRange(FixIt.InsertFromRange, SrcMgr, LangOpts), + CodeToInsert(FixIt.CodeToInsert), + BeforePreviousInsertions(FixIt.BeforePreviousInsertions) {} + +StandaloneDiagnostic::StandaloneDiagnostic(const LangOptions &LangOpts, + const StoredDiagnostic &InDiag) + : Level(InDiag.getLevel()), ID(InDiag.getID()), + Message(InDiag.getMessage()) { + const FullSourceLoc &FullLoc = InDiag.getLocation(); + // This is not an invalid diagnostic; invalid SourceLocations are used to + // represent diagnostics without a specific SourceLocation. + if (FullLoc.isInvalid()) + return; + + const auto &SrcMgr = FullLoc.getManager(); + FileKind = SrcMgr.getFileCharacteristic(static_cast(FullLoc)); + const auto FileLoc = SrcMgr.getFileLoc(static_cast(FullLoc)); + FileOffset = SrcMgr.getFileOffset(FileLoc); + Filename = SrcMgr.getFilename(FileLoc); + assert(!Filename.empty() && "diagnostic with location has no source file?"); + + Ranges.reserve(InDiag.getRanges().size()); + for (const auto &Range : InDiag.getRanges()) + Ranges.emplace_back(Range, SrcMgr, LangOpts); + + FixIts.reserve(InDiag.getFixIts().size()); + for (const auto &FixIt : InDiag.getFixIts()) + FixIts.emplace_back(SrcMgr, LangOpts, FixIt); +} + +StoredDiagnostic +translateStandaloneDiag(FileManager &FileMgr, SourceManager &SrcMgr, + const StandaloneDiagnostic &StandaloneDiag, + llvm::StringMap &SrcLocCache) { + const auto FileRef = FileMgr.getOptionalFileRef(StandaloneDiag.Filename); + if (!FileRef) + return StoredDiagnostic(StandaloneDiag.Level, StandaloneDiag.ID, + StandaloneDiag.Message); + + // Try to get FileLoc from cache first + SourceLocation FileLoc; + auto It = SrcLocCache.find(StandaloneDiag.Filename); + if (It != SrcLocCache.end()) { + FileLoc = It->getValue(); + } + + // Cache miss - compute and cache the location + if (FileLoc.isInvalid()) { + const auto FileID = + SrcMgr.getOrCreateFileID(*FileRef, StandaloneDiag.FileKind); + FileLoc = SrcMgr.getLocForStartOfFile(FileID); + + if (FileLoc.isInvalid()) + return StoredDiagnostic(StandaloneDiag.Level, StandaloneDiag.ID, + StandaloneDiag.Message); + + SrcLocCache[StandaloneDiag.Filename] = FileLoc; + } + + const auto DiagLoc = FileLoc.getLocWithOffset(StandaloneDiag.FileOffset); + const FullSourceLoc Loc(DiagLoc, SrcMgr); + + auto ConvertOffsetRange = + [&](const StandaloneDiagnostic::SourceOffsetRange &Range) { + return CharSourceRange( + SourceRange(FileLoc.getLocWithOffset(Range.Begin), + FileLoc.getLocWithOffset(Range.End)), + /*IsTokenRange*/ false); + }; + + SmallVector TranslatedRanges; + TranslatedRanges.reserve(StandaloneDiag.Ranges.size()); + transform(StandaloneDiag.Ranges, std::back_inserter(TranslatedRanges), + ConvertOffsetRange); + + SmallVector TranslatedFixIts; + TranslatedFixIts.reserve(StandaloneDiag.FixIts.size()); + for (const auto &FixIt : StandaloneDiag.FixIts) { + FixItHint TranslatedFixIt; + TranslatedFixIt.CodeToInsert = FixIt.CodeToInsert; + TranslatedFixIt.RemoveRange = ConvertOffsetRange(FixIt.RemoveRange); + TranslatedFixIt.InsertFromRange = ConvertOffsetRange(FixIt.InsertFromRange); + TranslatedFixIt.BeforePreviousInsertions = FixIt.BeforePreviousInsertions; + TranslatedFixIts.push_back(std::move(TranslatedFixIt)); + } + + return StoredDiagnostic(StandaloneDiag.Level, StandaloneDiag.ID, + StandaloneDiag.Message, Loc, TranslatedRanges, + TranslatedFixIts); +} + +} // namespace clang diff --git a/clang/lib/Interpreter/CMakeLists.txt b/clang/lib/Interpreter/CMakeLists.txt index 37faa0302caaa..9a597146b2fc4 100644 --- a/clang/lib/Interpreter/CMakeLists.txt +++ b/clang/lib/Interpreter/CMakeLists.txt @@ -46,6 +46,7 @@ add_clang_library(clangInterpreter clangFrontend clangFrontendTool clangLex + clangOptions clangParse clangSema clangSerialization diff --git a/clang/lib/Interpreter/Interpreter.cpp b/clang/lib/Interpreter/Interpreter.cpp index 7764fa7dc92b9..6cbc5e9910bcc 100644 --- a/clang/lib/Interpreter/Interpreter.cpp +++ b/clang/lib/Interpreter/Interpreter.cpp @@ -42,6 +42,7 @@ #include "clang/Interpreter/Interpreter.h" #include "clang/Interpreter/Value.h" #include "clang/Lex/PreprocessorOptions.h" +#include "clang/Options/OptionUtils.h" #include "clang/Options/Options.h" #include "clang/Sema/Lookup.h" #include "clang/Serialization/ObjectFilePCHContainerReader.h" @@ -105,7 +106,7 @@ CreateCI(const llvm::opt::ArgStringList &Argv) { if (Clang->getHeaderSearchOpts().UseBuiltinIncludes && Clang->getHeaderSearchOpts().ResourceDir.empty()) Clang->getHeaderSearchOpts().ResourceDir = - CompilerInvocation::GetResourcesPath(Argv[0], nullptr); + GetResourcesPath(Argv[0], nullptr); Clang->createVirtualFileSystem(); diff --git a/clang/lib/Options/OptionUtils.cpp b/clang/lib/Options/OptionUtils.cpp index fcafd3c83c6b3..e5aefa012f679 100644 --- a/clang/lib/Options/OptionUtils.cpp +++ b/clang/lib/Options/OptionUtils.cpp @@ -9,7 +9,12 @@ #include "clang/Options/OptionUtils.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/DiagnosticDriver.h" +#include "clang/Basic/Version.h" +#include "clang/Config/config.h" +#include "clang/Options/Options.h" #include "llvm/Option/ArgList.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" using namespace clang; using namespace llvm::opt; @@ -31,17 +36,211 @@ IntTy getLastArgIntValueImpl(const ArgList &Args, OptSpecifier Id, } } // namespace -namespace clang { - -int getLastArgIntValue(const ArgList &Args, OptSpecifier Id, int Default, - DiagnosticsEngine *Diags, unsigned Base) { +int clang::getLastArgIntValue(const ArgList &Args, OptSpecifier Id, int Default, + DiagnosticsEngine *Diags, unsigned Base) { return getLastArgIntValueImpl(Args, Id, Default, Diags, Base); } -uint64_t getLastArgUInt64Value(const ArgList &Args, OptSpecifier Id, - uint64_t Default, DiagnosticsEngine *Diags, - unsigned Base) { +uint64_t clang::getLastArgUInt64Value(const ArgList &Args, OptSpecifier Id, + uint64_t Default, + DiagnosticsEngine *Diags, unsigned Base) { return getLastArgIntValueImpl(Args, Id, Default, Diags, Base); } -} // namespace clang +StringRef clang::parseMPreferVectorWidthOption(clang::DiagnosticsEngine &Diags, + const llvm::opt::ArgList &Args) { + const Arg *A = Args.getLastArg(options::OPT_mprefer_vector_width_EQ); + if (!A) + return ""; + + StringRef Value = A->getValue(); + unsigned Width LLVM_ATTRIBUTE_UNINITIALIZED; + + // Only "none" and Integer values are accepted by + // -mprefer-vector-width=. + if (Value != "none" && Value.getAsInteger(10, Width)) { + Diags.Report(clang::diag::err_drv_invalid_value) + << A->getOption().getName() << Value; + return ""; + } + + return Value; +} + +// This is a helper function for validating the optional refinement step +// parameter in reciprocal argument strings. Return false if there is an error +// parsing the refinement step. Otherwise, return true and set the Position +// of the refinement step in the input string. +static bool getRefinementStep(StringRef In, clang::DiagnosticsEngine &Diags, + const Arg &A, size_t &Position) { + const char RefinementStepToken = ':'; + Position = In.find(RefinementStepToken); + if (Position != StringRef::npos) { + StringRef Option = A.getOption().getName(); + StringRef RefStep = In.substr(Position + 1); + // Allow exactly one numeric character for the additional refinement + // step parameter. This is reasonable for all currently-supported + // operations and architectures because we would expect that a larger value + // of refinement steps would cause the estimate "optimization" to + // under-perform the native operation. Also, if the estimate does not + // converge quickly, it probably will not ever converge, so further + // refinement steps will not produce a better answer. + if (RefStep.size() != 1) { + Diags.Report(diag::err_drv_invalid_value) << Option << RefStep; + return false; + } + char RefStepChar = RefStep[0]; + if (RefStepChar < '0' || RefStepChar > '9') { + Diags.Report(diag::err_drv_invalid_value) << Option << RefStep; + return false; + } + } + return true; +} + +StringRef clang::parseMRecipOption(clang::DiagnosticsEngine &Diags, + const ArgList &Args) { + StringRef DisabledPrefixIn = "!"; + StringRef DisabledPrefixOut = "!"; + StringRef EnabledPrefixOut = ""; + StringRef Out = ""; + + const Arg *A = Args.getLastArg(options::OPT_mrecip, options::OPT_mrecip_EQ); + if (!A) + return ""; + + const unsigned NumOptions = A->getNumValues(); + if (NumOptions == 0) { + // No option is the same as "all". + return "all"; + } + + // Pass through "all", "none", or "default" with an optional refinement step. + if (NumOptions == 1) { + StringRef Val = A->getValue(0); + size_t RefStepLoc; + if (!getRefinementStep(Val, Diags, *A, RefStepLoc)) + return ""; + StringRef ValBase = Val.slice(0, RefStepLoc); + if (ValBase == "all" || ValBase == "none" || ValBase == "default") { + return Val; + } + } + + // Each reciprocal type may be enabled or disabled individually. + // Check each input value for validity, concatenate them all back together, + // and pass through. + + llvm::StringMap OptionStrings; + OptionStrings.insert(std::make_pair("divd", false)); + OptionStrings.insert(std::make_pair("divf", false)); + OptionStrings.insert(std::make_pair("divh", false)); + OptionStrings.insert(std::make_pair("vec-divd", false)); + OptionStrings.insert(std::make_pair("vec-divf", false)); + OptionStrings.insert(std::make_pair("vec-divh", false)); + OptionStrings.insert(std::make_pair("sqrtd", false)); + OptionStrings.insert(std::make_pair("sqrtf", false)); + OptionStrings.insert(std::make_pair("sqrth", false)); + OptionStrings.insert(std::make_pair("vec-sqrtd", false)); + OptionStrings.insert(std::make_pair("vec-sqrtf", false)); + OptionStrings.insert(std::make_pair("vec-sqrth", false)); + + for (unsigned i = 0; i != NumOptions; ++i) { + StringRef Val = A->getValue(i); + + bool IsDisabled = Val.starts_with(DisabledPrefixIn); + // Ignore the disablement token for string matching. + if (IsDisabled) + Val = Val.substr(1); + + size_t RefStep; + if (!getRefinementStep(Val, Diags, *A, RefStep)) + return ""; + + StringRef ValBase = Val.slice(0, RefStep); + llvm::StringMap::iterator OptionIter = OptionStrings.find(ValBase); + if (OptionIter == OptionStrings.end()) { + // Try again specifying float suffix. + OptionIter = OptionStrings.find(ValBase.str() + 'f'); + if (OptionIter == OptionStrings.end()) { + // The input name did not match any known option string. + Diags.Report(diag::err_drv_unknown_argument) << Val; + return ""; + } + // The option was specified without a half or float or double suffix. + // Make sure that the double or half entry was not already specified. + // The float entry will be checked below. + if (OptionStrings[ValBase.str() + 'd'] || + OptionStrings[ValBase.str() + 'h']) { + Diags.Report(diag::err_drv_invalid_value) + << A->getOption().getName() << Val; + return ""; + } + } + + if (OptionIter->second == true) { + // Duplicate option specified. + Diags.Report(diag::err_drv_invalid_value) + << A->getOption().getName() << Val; + return ""; + } + + // Mark the matched option as found. Do not allow duplicate specifiers. + OptionIter->second = true; + + // If the precision was not specified, also mark the double and half entry + // as found. + if (ValBase.back() != 'f' && ValBase.back() != 'd' && + ValBase.back() != 'h') { + OptionStrings[ValBase.str() + 'd'] = true; + OptionStrings[ValBase.str() + 'h'] = true; + } + + // Build the output string. + StringRef Prefix = IsDisabled ? DisabledPrefixOut : EnabledPrefixOut; + Out = Args.MakeArgString(Out + Prefix + Val); + if (i != NumOptions - 1) + Out = Args.MakeArgString(Out + ","); + } + + return Out; +} + +std::string clang::GetResourcesPath(StringRef BinaryPath) { + // Since the resource directory is embedded in the module hash, it's important + // that all places that need it call this function, so that they get the + // exact same string ("a/../b/" and "b/" get different hashes, for example). + + // Dir is bin/ or lib/, depending on where BinaryPath is. + StringRef Dir = llvm::sys::path::parent_path(BinaryPath); + SmallString<128> P(Dir); + + StringRef ConfiguredResourceDir(CLANG_RESOURCE_DIR); + if (!ConfiguredResourceDir.empty()) { + // FIXME: We should fix the behavior of llvm::sys::path::append so we don't + // need to check for absolute paths here. + if (llvm::sys::path::is_absolute(ConfiguredResourceDir)) + P = ConfiguredResourceDir; + else + llvm::sys::path::append(P, ConfiguredResourceDir); + } else { + // On Windows, libclang.dll is in bin/. + // On non-Windows, libclang.so/.dylib is in lib/. + // With a static-library build of libclang, LibClangPath will contain the + // path of the embedding binary, which for LLVM binaries will be in bin/. + // ../lib gets us to lib/ in both cases. + P = llvm::sys::path::parent_path(Dir); + // This search path is also created in the COFF driver of lld, so any + // changes here also needs to happen in lld/COFF/Driver.cpp + llvm::sys::path::append(P, CLANG_INSTALL_LIBDIR_BASENAME, "clang", + CLANG_VERSION_MAJOR_STRING); + } + + return std::string(P); +} + +std::string clang::GetResourcesPath(const char *Argv0, void *MainAddr) { + const std::string ClangExecutable = + llvm::sys::fs::getMainExecutable(Argv0, MainAddr); + return GetResourcesPath(ClangExecutable); +} diff --git a/clang/lib/Tooling/Tooling.cpp b/clang/lib/Tooling/Tooling.cpp index 9bae12454d2dc..1d55f615de8a9 100644 --- a/clang/lib/Tooling/Tooling.cpp +++ b/clang/lib/Tooling/Tooling.cpp @@ -31,6 +31,7 @@ #include "clang/Frontend/TextDiagnosticPrinter.h" #include "clang/Lex/HeaderSearchOptions.h" #include "clang/Lex/PreprocessorOptions.h" +#include "clang/Options/OptionUtils.h" #include "clang/Options/Options.h" #include "clang/Tooling/ArgumentsAdjusters.h" #include "clang/Tooling/CompilationDatabase.h" @@ -510,8 +511,7 @@ static void injectResourceDir(CommandLineArguments &Args, const char *Argv0, // If there's no override in place add our resource dir. Args = getInsertArgumentAdjuster( - ("-resource-dir=" + CompilerInvocation::GetResourcesPath(Argv0, MainAddr)) - .c_str())(Args, ""); + ("-resource-dir=" + GetResourcesPath(Argv0, MainAddr)).c_str())(Args, ""); } int ClangTool::run(ToolAction *Action) { diff --git a/clang/tools/c-index-test/CMakeLists.txt b/clang/tools/c-index-test/CMakeLists.txt index 24e7c9692ca56..41e80e66ffa7a 100644 --- a/clang/tools/c-index-test/CMakeLists.txt +++ b/clang/tools/c-index-test/CMakeLists.txt @@ -27,6 +27,7 @@ else() libclang clangAST clangBasic + clangDriver clangFrontend clangIndex clangSerialization diff --git a/clang/tools/c-index-test/core_main.cpp b/clang/tools/c-index-test/core_main.cpp index 5a3086a7fc08f..c67479fd130ca 100644 --- a/clang/tools/c-index-test/core_main.cpp +++ b/clang/tools/c-index-test/core_main.cpp @@ -8,6 +8,7 @@ #include "clang/AST/Mangle.h" #include "clang/Basic/LangOptions.h" +#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/ASTUnit.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/CompilerInvocation.h" diff --git a/clang/tools/diagtool/CMakeLists.txt b/clang/tools/diagtool/CMakeLists.txt index b49619c075c73..09b2a81790f87 100644 --- a/clang/tools/diagtool/CMakeLists.txt +++ b/clang/tools/diagtool/CMakeLists.txt @@ -15,5 +15,6 @@ add_clang_tool(diagtool clang_target_link_libraries(diagtool PRIVATE clangBasic + clangDriver clangFrontend ) diff --git a/clang/tools/diagtool/ShowEnabledWarnings.cpp b/clang/tools/diagtool/ShowEnabledWarnings.cpp index bea0288c09358..5b25e656dafa4 100644 --- a/clang/tools/diagtool/ShowEnabledWarnings.cpp +++ b/clang/tools/diagtool/ShowEnabledWarnings.cpp @@ -9,6 +9,7 @@ #include "DiagTool.h" #include "DiagnosticNames.h" #include "clang/Basic/LLVM.h" +#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/TextDiagnosticBuffer.h" #include "clang/Frontend/TextDiagnosticPrinter.h" diff --git a/clang/tools/driver/cc1_main.cpp b/clang/tools/driver/cc1_main.cpp index 92357487865ce..cc757039cafd0 100644 --- a/clang/tools/driver/cc1_main.cpp +++ b/clang/tools/driver/cc1_main.cpp @@ -17,6 +17,7 @@ #include "clang/Basic/TargetOptions.h" #include "clang/CodeGen/ObjectFilePCHContainerWriter.h" #include "clang/Config/config.h" +#include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/CompilerInvocation.h" @@ -269,7 +270,7 @@ int cc1_main(ArrayRef Argv, const char *Argv0, void *MainAddr) { if (Clang->getHeaderSearchOpts().UseBuiltinIncludes && Clang->getHeaderSearchOpts().ResourceDir.empty()) Clang->getHeaderSearchOpts().ResourceDir = - CompilerInvocation::GetResourcesPath(Argv0, MainAddr); + GetResourcesPath(Argv0, MainAddr); /// Create the actual file system. Clang->createVirtualFileSystem(llvm::vfs::getRealFileSystem(), DiagsBuffer); diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp index f4d6fa72a1dfe..32e84248c1b27 100644 --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -38,6 +38,7 @@ #include "clang/Basic/Stack.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/Version.h" +#include "clang/Driver/CreateASTUnitFromArgs.h" #include "clang/Frontend/ASTUnit.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Index/CommentToXML.h" @@ -4361,7 +4362,7 @@ clang_parseTranslationUnit_Impl(CXIndex CIdx, const char *source_filename, LibclangInvocationReporter InvocationReporter( *CXXIdx, LibclangInvocationReporter::OperationKind::ParseOperation, options, llvm::ArrayRef(*Args), /*InvocationArgs=*/{}, unsaved_files); - std::unique_ptr Unit = ASTUnit::LoadFromCommandLine( + std::unique_ptr Unit = CreateASTUnitFromCommandLine( Args->data(), Args->data() + Args->size(), CXXIdx->getPCHContainerOperations(), DiagOpts, Diags, CXXIdx->getClangResourcesPath(), CXXIdx->getStorePreamblesInMemory(), diff --git a/clang/tools/libclang/CIndexer.cpp b/clang/tools/libclang/CIndexer.cpp index 11d9312b64849..853a936b43e37 100644 --- a/clang/tools/libclang/CIndexer.cpp +++ b/clang/tools/libclang/CIndexer.cpp @@ -16,6 +16,7 @@ #include "clang/Basic/Version.h" #include "clang/Config/config.h" #include "clang/Driver/Driver.h" +#include "clang/Options/OptionUtils.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/FileSystem.h" @@ -137,7 +138,7 @@ const std::string &CIndexer::getClangResourcesPath() { #endif // Cache our result. - ResourcesPath = driver::Driver::GetResourcesPath(LibClangPath); + ResourcesPath = GetResourcesPath(LibClangPath); return ResourcesPath; } diff --git a/clang/tools/libclang/CMakeLists.txt b/clang/tools/libclang/CMakeLists.txt index e0ff7605b68b8..b0105f5a5f79f 100644 --- a/clang/tools/libclang/CMakeLists.txt +++ b/clang/tools/libclang/CMakeLists.txt @@ -65,6 +65,7 @@ set(LIBS clangFrontend clangIndex clangLex + clangOptions clangRewrite clangSema clangSerialization diff --git a/clang/tools/libclang/Indexing.cpp b/clang/tools/libclang/Indexing.cpp index c142f142d5071..75323d70afcfe 100644 --- a/clang/tools/libclang/Indexing.cpp +++ b/clang/tools/libclang/Indexing.cpp @@ -15,6 +15,7 @@ #include "CXString.h" #include "CXTranslationUnit.h" #include "clang/AST/ASTConsumer.h" +#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/ASTUnit.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/CompilerInvocation.h" diff --git a/clang/unittests/Driver/DXCModeTest.cpp b/clang/unittests/Driver/DXCModeTest.cpp index e0454f190b35a..130da620b40b5 100644 --- a/clang/unittests/Driver/DXCModeTest.cpp +++ b/clang/unittests/Driver/DXCModeTest.cpp @@ -15,6 +15,7 @@ #include "clang/Basic/LLVM.h" #include "clang/Basic/TargetOptions.h" #include "clang/Driver/Compilation.h" +#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Driver/Driver.h" #include "clang/Driver/ToolChain.h" #include "clang/Frontend/CompilerInstance.h" diff --git a/clang/unittests/Driver/ToolChainTest.cpp b/clang/unittests/Driver/ToolChainTest.cpp index afa17ff219be2..8f533790ec501 100644 --- a/clang/unittests/Driver/ToolChainTest.cpp +++ b/clang/unittests/Driver/ToolChainTest.cpp @@ -17,6 +17,7 @@ #include "clang/Basic/TargetInfo.h" #include "clang/Basic/TargetOptions.h" #include "clang/Driver/Compilation.h" +#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Driver/Driver.h" #include "clang/Frontend/CompilerInstance.h" #include "llvm/ADT/ArrayRef.h" diff --git a/clang/unittests/Frontend/ASTUnitTest.cpp b/clang/unittests/Frontend/ASTUnitTest.cpp index dfdbe90e72f1f..bf9e4e184b5db 100644 --- a/clang/unittests/Frontend/ASTUnitTest.cpp +++ b/clang/unittests/Frontend/ASTUnitTest.cpp @@ -9,6 +9,8 @@ #include #include "clang/Basic/FileManager.h" +#include "clang/Driver/CreateASTUnitFromArgs.h" +#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/ASTUnit.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/CompilerInvocation.h" @@ -173,7 +175,7 @@ TEST_F(ASTUnitTest, LoadFromCommandLineEarlyError) { auto PCHContainerOps = std::make_shared(); std::unique_ptr ErrUnit; - std::unique_ptr AST = ASTUnit::LoadFromCommandLine( + std::unique_ptr AST = CreateASTUnitFromCommandLine( &Args[0], &Args[4], PCHContainerOps, DiagOpts, Diags, "", false, "", false, CaptureDiagsKind::All, {}, true, 0, TU_Complete, false, false, false, SkipFunctionBodiesScope::None, false, true, false, false, @@ -201,7 +203,7 @@ TEST_F(ASTUnitTest, LoadFromCommandLineWorkingDirectory) { auto PCHContainerOps = std::make_shared(); std::unique_ptr ErrUnit; - std::unique_ptr AST = ASTUnit::LoadFromCommandLine( + std::unique_ptr AST = CreateASTUnitFromCommandLine( &Args[0], &Args[4], PCHContainerOps, DiagOpts, Diags, "", false, "", false, CaptureDiagsKind::All, {}, true, 0, TU_Complete, false, false, false, SkipFunctionBodiesScope::None, false, true, false, false, diff --git a/clang/unittests/Frontend/CompilerInstanceTest.cpp b/clang/unittests/Frontend/CompilerInstanceTest.cpp index cd3fefa1ea994..39d35b48f394a 100644 --- a/clang/unittests/Frontend/CompilerInstanceTest.cpp +++ b/clang/unittests/Frontend/CompilerInstanceTest.cpp @@ -8,6 +8,7 @@ #include "clang/Frontend/CompilerInstance.h" #include "clang/Basic/FileManager.h" +#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/CompilerInvocation.h" #include "clang/Frontend/FrontendActions.h" #include "clang/Frontend/TextDiagnosticPrinter.h" diff --git a/clang/unittests/Frontend/UtilsTest.cpp b/clang/unittests/Frontend/UtilsTest.cpp index fc411e4af705f..a82733d57714a 100644 --- a/clang/unittests/Frontend/UtilsTest.cpp +++ b/clang/unittests/Frontend/UtilsTest.cpp @@ -9,6 +9,7 @@ #include "clang/Frontend/Utils.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/TargetOptions.h" +#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/CompilerInvocation.h" #include "clang/Lex/PreprocessorOptions.h" diff --git a/clang/unittests/Sema/CMakeLists.txt b/clang/unittests/Sema/CMakeLists.txt index b61ed8c457635..188f6135a60ac 100644 --- a/clang/unittests/Sema/CMakeLists.txt +++ b/clang/unittests/Sema/CMakeLists.txt @@ -13,6 +13,7 @@ add_distinct_clang_unittest(SemaTests clangAST clangASTMatchers clangBasic + clangDriver clangFrontend clangParse clangSema diff --git a/clang/unittests/Sema/SemaNoloadLookupTest.cpp b/clang/unittests/Sema/SemaNoloadLookupTest.cpp index e565372698e5e..3944269eff502 100644 --- a/clang/unittests/Sema/SemaNoloadLookupTest.cpp +++ b/clang/unittests/Sema/SemaNoloadLookupTest.cpp @@ -10,6 +10,7 @@ #include "clang/AST/DeclarationName.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendAction.h" #include "clang/Frontend/FrontendActions.h" diff --git a/clang/unittests/Serialization/ForceCheckFileInputTest.cpp b/clang/unittests/Serialization/ForceCheckFileInputTest.cpp index edf33ae04230b..b76dcfec96063 100644 --- a/clang/unittests/Serialization/ForceCheckFileInputTest.cpp +++ b/clang/unittests/Serialization/ForceCheckFileInputTest.cpp @@ -9,6 +9,7 @@ #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/ASTMatchers/ASTMatchers.h" #include "clang/Basic/FileManager.h" +#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/CompilerInvocation.h" #include "clang/Frontend/FrontendActions.h" diff --git a/clang/unittests/Serialization/LoadSpecLazilyTest.cpp b/clang/unittests/Serialization/LoadSpecLazilyTest.cpp index d7b55491fddac..f55925aeae1f2 100644 --- a/clang/unittests/Serialization/LoadSpecLazilyTest.cpp +++ b/clang/unittests/Serialization/LoadSpecLazilyTest.cpp @@ -6,6 +6,7 @@ // //===----------------------------------------------------------------------===// +#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendAction.h" #include "clang/Frontend/FrontendActions.h" diff --git a/clang/unittests/Serialization/ModuleCacheTest.cpp b/clang/unittests/Serialization/ModuleCacheTest.cpp index e9b8da3dba6af..df26e54588b9e 100644 --- a/clang/unittests/Serialization/ModuleCacheTest.cpp +++ b/clang/unittests/Serialization/ModuleCacheTest.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "clang/Basic/FileManager.h" +#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/CompilerInvocation.h" #include "clang/Frontend/FrontendActions.h" diff --git a/clang/unittests/Serialization/NoCommentsTest.cpp b/clang/unittests/Serialization/NoCommentsTest.cpp index 01bb6999a7c90..444a082bba907 100644 --- a/clang/unittests/Serialization/NoCommentsTest.cpp +++ b/clang/unittests/Serialization/NoCommentsTest.cpp @@ -9,6 +9,7 @@ #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/ASTMatchers/ASTMatchers.h" #include "clang/Basic/FileManager.h" +#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/CompilerInvocation.h" #include "clang/Frontend/FrontendActions.h" diff --git a/clang/unittests/Serialization/PreambleInNamedModulesTest.cpp b/clang/unittests/Serialization/PreambleInNamedModulesTest.cpp index 55ee72875ead2..b826f20ce4d70 100644 --- a/clang/unittests/Serialization/PreambleInNamedModulesTest.cpp +++ b/clang/unittests/Serialization/PreambleInNamedModulesTest.cpp @@ -6,6 +6,7 @@ // //===----------------------------------------------------------------------===// +#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/CompilerInvocation.h" #include "clang/Frontend/FrontendActions.h" diff --git a/clang/unittests/Serialization/VarDeclConstantInitTest.cpp b/clang/unittests/Serialization/VarDeclConstantInitTest.cpp index 743f851fc5fe1..2be01def49809 100644 --- a/clang/unittests/Serialization/VarDeclConstantInitTest.cpp +++ b/clang/unittests/Serialization/VarDeclConstantInitTest.cpp @@ -9,6 +9,7 @@ #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/ASTMatchers/ASTMatchers.h" #include "clang/Basic/FileManager.h" +#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/CompilerInvocation.h" #include "clang/Frontend/FrontendActions.h" diff --git a/clang/unittests/Tooling/Syntax/TokensTest.cpp b/clang/unittests/Tooling/Syntax/TokensTest.cpp index 47184cbf5d768..468ca5ddd2c75 100644 --- a/clang/unittests/Tooling/Syntax/TokensTest.cpp +++ b/clang/unittests/Tooling/Syntax/TokensTest.cpp @@ -20,6 +20,7 @@ #include "clang/Basic/SourceManager.h" #include "clang/Basic/TokenKinds.def" #include "clang/Basic/TokenKinds.h" +#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendAction.h" #include "clang/Frontend/Utils.h" diff --git a/clang/unittests/Tooling/Syntax/TreeTestBase.cpp b/clang/unittests/Tooling/Syntax/TreeTestBase.cpp index b2be64fc08f3d..dad75854240ef 100644 --- a/clang/unittests/Tooling/Syntax/TreeTestBase.cpp +++ b/clang/unittests/Tooling/Syntax/TreeTestBase.cpp @@ -13,6 +13,7 @@ #include "TreeTestBase.h" #include "clang/AST/ASTConsumer.h" #include "clang/Basic/LLVM.h" +#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/CompilerInvocation.h" #include "clang/Frontend/FrontendAction.h" diff --git a/flang/lib/Frontend/CMakeLists.txt b/flang/lib/Frontend/CMakeLists.txt index bb0b4a39cec9b..fb74b3dcb280e 100644 --- a/flang/lib/Frontend/CMakeLists.txt +++ b/flang/lib/Frontend/CMakeLists.txt @@ -75,7 +75,6 @@ add_flang_library(flangFrontend CLANG_LIBS clangBasic - clangDriver clangOptions ) diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp index 0c32f3914e04b..b6c4e6303cdac 100644 --- a/flang/lib/Frontend/CompilerInvocation.cpp +++ b/flang/lib/Frontend/CompilerInvocation.cpp @@ -325,10 +325,9 @@ static void parseCodeGenArgs(Fortran::frontend::CodeGenOptions &opts, for (auto *a : args.filtered(clang::options::OPT_fpass_plugin_EQ)) opts.LLVMPassPlugins.push_back(a->getValue()); - opts.Reciprocals = clang::driver::tools::parseMRecipOption(diags, args); + opts.Reciprocals = clang::parseMRecipOption(diags, args); - opts.PreferVectorWidth = - clang::driver::tools::parseMPreferVectorWidthOption(diags, args); + opts.PreferVectorWidth = clang::parseMPreferVectorWidthOption(diags, args); // -fembed-offload-object option for (auto *a : args.filtered(clang::options::OPT_fembed_offload_object_EQ)) diff --git a/lldb/source/Commands/CommandObjectTarget.cpp b/lldb/source/Commands/CommandObjectTarget.cpp index 30bca639060e6..7f880d223d6c3 100644 --- a/lldb/source/Commands/CommandObjectTarget.cpp +++ b/lldb/source/Commands/CommandObjectTarget.cpp @@ -60,6 +60,7 @@ #include "lldb/lldb-forward.h" #include "lldb/lldb-private-enumerations.h" +#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/CompilerInvocation.h" #include "clang/Frontend/FrontendActions.h" diff --git a/lldb/source/Plugins/ExpressionParser/Clang/CMakeLists.txt b/lldb/source/Plugins/ExpressionParser/Clang/CMakeLists.txt index 01d588ff6a78b..759a7c4dd14fb 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/CMakeLists.txt +++ b/lldb/source/Plugins/ExpressionParser/Clang/CMakeLists.txt @@ -51,10 +51,10 @@ add_lldb_library(lldbPluginExpressionParserClang CLANG_LIBS clangAST clangCodeGen - clangDriver clangEdit clangFrontend clangLex + clangOptions clangParse clangRewrite clangRewriteFrontend diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangHost.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangHost.cpp index 6de851081598f..660a21e3c6a8d 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangHost.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangHost.cpp @@ -10,7 +10,7 @@ #include "clang/Basic/Version.h" #include "clang/Config/config.h" -#include "clang/Driver/Driver.h" +#include "clang/Options/OptionUtils.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" @@ -53,7 +53,7 @@ static bool DefaultComputeClangResourceDirectory(FileSpec &lldb_shlib_spec, std::string raw_path = lldb_shlib_spec.GetPath(); llvm::StringRef parent_dir = llvm::sys::path::parent_path(raw_path); static const std::string clang_resource_path = - clang::driver::Driver::GetResourcesPath("bin/lldb"); + clang::GetResourcesPath("bin/lldb"); static const llvm::StringRef kResourceDirSuffixes[] = { // LLVM.org's build of LLDB uses the clang resource directory placed diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp index e37c84efefdc9..ce8dc50b84a31 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp @@ -10,6 +10,7 @@ #include "clang/Basic/DiagnosticFrontend.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/TargetInfo.h" +#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendActions.h" #include "clang/Frontend/TextDiagnosticPrinter.h" diff --git a/lldb/unittests/Expression/ClangParserTest.cpp b/lldb/unittests/Expression/ClangParserTest.cpp index fab4487c73719..c949026e87cd8 100644 --- a/lldb/unittests/Expression/ClangParserTest.cpp +++ b/lldb/unittests/Expression/ClangParserTest.cpp @@ -8,7 +8,7 @@ #include "clang/Basic/Version.h" #include "clang/Config/config.h" -#include "clang/Driver/Driver.h" +#include "clang/Options/OptionUtils.h" #include "Plugins/ExpressionParser/Clang/ClangHost.h" #include "TestingSupport/SubsystemRAII.h" @@ -43,7 +43,7 @@ TEST_F(ClangHostTest, ComputeClangResourceDirectory) { std::string path_to_liblldb = "C:\\foo\\bar\\lib\\"; #endif std::string path_to_clang_dir = - clang::driver::Driver::GetResourcesPath(path_to_liblldb + "liblldb"); + clang::GetResourcesPath(path_to_liblldb + "liblldb"); llvm::SmallString<256> path_to_clang_lib_dir_real; llvm::sys::fs::real_path(path_to_clang_dir, path_to_clang_lib_dir_real); From dea330b38d9c18b68219abdb52baaa72c9f1103d Mon Sep 17 00:00:00 2001 From: Naveen Seth Hanig Date: Mon, 24 Nov 2025 21:09:30 +0100 Subject: [PATCH 06/50] Revert " [clang] Refactor to remove clangDriver dependency from clangFrontend and flangFrontend (#165277)" (#169397) This reverts commit 3773bbe and relands the last revert attempt 40334b8. 3773bbe broke the build for the build configuration described in here: https://github.com/llvm/llvm-project/pull/165277#issuecomment-3572432250 --- clang-tools-extra/clangd/CompileCommands.cpp | 3 +- clang-tools-extra/clangd/Compiler.cpp | 1 - clang/docs/ReleaseNotes.rst | 2 - clang/include/clang/Driver/CommonArgs.h | 10 + .../clang/Driver/CreateASTUnitFromArgs.h | 80 ---- .../clang/Driver/CreateInvocationFromArgs.h | 76 ---- clang/include/clang/Driver/Driver.h | 4 + clang/include/clang/Frontend/ASTUnit.h | 144 ++++---- .../clang/Frontend/CompilerInvocation.h | 10 + .../clang/Frontend/StandaloneDiagnostic.h | 82 ----- clang/include/clang/Frontend/Utils.h | 45 +++ clang/include/clang/Options/OptionUtils.h | 24 -- clang/lib/CrossTU/CMakeLists.txt | 1 - clang/lib/CrossTU/CrossTranslationUnit.cpp | 3 +- clang/lib/Driver/CMakeLists.txt | 4 - clang/lib/Driver/CreateASTUnitFromArgs.cpp | 166 --------- clang/lib/Driver/Driver.cpp | 35 +- clang/lib/Driver/ToolChains/Clang.cpp | 1 - clang/lib/Driver/ToolChains/CommonArgs.cpp | 163 +++++++++ clang/lib/Driver/ToolChains/Flang.cpp | 1 - clang/lib/Frontend/ASTUnit.cpp | 343 +++++++++++++++--- clang/lib/Frontend/CMakeLists.txt | 3 +- clang/lib/Frontend/CompilerInvocation.cpp | 8 + .../CreateInvocationFromCommandLine.cpp} | 13 +- clang/lib/Frontend/StandaloneDiagnostic.cpp | 117 ------ clang/lib/Interpreter/CMakeLists.txt | 1 - clang/lib/Interpreter/Interpreter.cpp | 3 +- clang/lib/Options/OptionUtils.cpp | 215 +---------- clang/lib/Tooling/Tooling.cpp | 4 +- clang/tools/c-index-test/CMakeLists.txt | 1 - clang/tools/c-index-test/core_main.cpp | 1 - clang/tools/diagtool/CMakeLists.txt | 1 - clang/tools/diagtool/ShowEnabledWarnings.cpp | 1 - clang/tools/driver/cc1_main.cpp | 3 +- clang/tools/libclang/CIndex.cpp | 3 +- clang/tools/libclang/CIndexer.cpp | 3 +- clang/tools/libclang/CMakeLists.txt | 1 - clang/tools/libclang/Indexing.cpp | 1 - clang/unittests/Driver/DXCModeTest.cpp | 1 - clang/unittests/Driver/ToolChainTest.cpp | 1 - clang/unittests/Frontend/ASTUnitTest.cpp | 6 +- .../Frontend/CompilerInstanceTest.cpp | 1 - clang/unittests/Frontend/UtilsTest.cpp | 1 - clang/unittests/Sema/CMakeLists.txt | 1 - clang/unittests/Sema/SemaNoloadLookupTest.cpp | 1 - .../Serialization/ForceCheckFileInputTest.cpp | 1 - .../Serialization/LoadSpecLazilyTest.cpp | 1 - .../Serialization/ModuleCacheTest.cpp | 1 - .../Serialization/NoCommentsTest.cpp | 1 - .../PreambleInNamedModulesTest.cpp | 1 - .../Serialization/VarDeclConstantInitTest.cpp | 1 - clang/unittests/Tooling/Syntax/TokensTest.cpp | 1 - .../unittests/Tooling/Syntax/TreeTestBase.cpp | 1 - flang/lib/Frontend/CMakeLists.txt | 1 + flang/lib/Frontend/CompilerInvocation.cpp | 5 +- lldb/source/Commands/CommandObjectTarget.cpp | 1 - .../ExpressionParser/Clang/CMakeLists.txt | 2 +- .../ExpressionParser/Clang/ClangHost.cpp | 4 +- .../Clang/ClangModulesDeclVendor.cpp | 1 - lldb/unittests/Expression/ClangParserTest.cpp | 4 +- 60 files changed, 681 insertions(+), 934 deletions(-) delete mode 100644 clang/include/clang/Driver/CreateASTUnitFromArgs.h delete mode 100644 clang/include/clang/Driver/CreateInvocationFromArgs.h delete mode 100644 clang/include/clang/Frontend/StandaloneDiagnostic.h delete mode 100644 clang/lib/Driver/CreateASTUnitFromArgs.cpp rename clang/lib/{Driver/CreateInvocationFromArgs.cpp => Frontend/CreateInvocationFromCommandLine.cpp} (93%) delete mode 100644 clang/lib/Frontend/StandaloneDiagnostic.cpp diff --git a/clang-tools-extra/clangd/CompileCommands.cpp b/clang-tools-extra/clangd/CompileCommands.cpp index 4eda330716f21..7990f2719e9a0 100644 --- a/clang-tools-extra/clangd/CompileCommands.cpp +++ b/clang-tools-extra/clangd/CompileCommands.cpp @@ -132,7 +132,8 @@ std::optional detectSysroot() { std::string detectStandardResourceDir() { static int StaticForMainAddr; // Just an address in this process. - return GetResourcesPath("clangd", (void *)&StaticForMainAddr); + return CompilerInvocation::GetResourcesPath("clangd", + (void *)&StaticForMainAddr); } // The path passed to argv[0] is important: diff --git a/clang-tools-extra/clangd/Compiler.cpp b/clang-tools-extra/clangd/Compiler.cpp index 9ea7df139382a..6ebc2eac25745 100644 --- a/clang-tools-extra/clangd/Compiler.cpp +++ b/clang-tools-extra/clangd/Compiler.cpp @@ -9,7 +9,6 @@ #include "Compiler.h" #include "support/Logger.h" #include "clang/Basic/TargetInfo.h" -#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/CompilerInvocation.h" #include "clang/Lex/PreprocessorOptions.h" #include "clang/Serialization/PCHContainerOperations.h" diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index b12e4539dc3a6..51f07256c5d9f 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -84,8 +84,6 @@ Potentially Breaking Changes - Downstream projects that previously linked only against ``clangDriver`` may now (also) need to link against the new ``clangOptions`` library, since options-related code has been moved out of the Driver into a separate library. -- The ``clangFrontend`` library no longer depends on ``clangDriver``, which may - break downstream projects that relied on this transitive dependency. C/C++ Language Potentially Breaking Changes ------------------------------------------- diff --git a/clang/include/clang/Driver/CommonArgs.h b/clang/include/clang/Driver/CommonArgs.h index 264bd4965f9ad..ac17d6211d882 100644 --- a/clang/include/clang/Driver/CommonArgs.h +++ b/clang/include/clang/Driver/CommonArgs.h @@ -291,6 +291,16 @@ void handleVectorizeLoopsArgs(const llvm::opt::ArgList &Args, void handleVectorizeSLPArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs); +// Parse -mprefer-vector-width=. Return the Value string if well-formed. +// Otherwise, return an empty string and issue a diagnosic message if needed. +StringRef parseMPreferVectorWidthOption(clang::DiagnosticsEngine &Diags, + const llvm::opt::ArgList &Args); + +// Parse -mrecip. Return the Value string if well-formed. +// Otherwise, return an empty string and issue a diagnosic message if needed. +StringRef parseMRecipOption(clang::DiagnosticsEngine &Diags, + const llvm::opt::ArgList &Args); + // Convert ComplexRangeKind to a string that can be passed as a frontend option. std::string complexRangeKindToStr(LangOptions::ComplexRangeKind Range); diff --git a/clang/include/clang/Driver/CreateASTUnitFromArgs.h b/clang/include/clang/Driver/CreateASTUnitFromArgs.h deleted file mode 100644 index 30575cc04ca7c..0000000000000 --- a/clang/include/clang/Driver/CreateASTUnitFromArgs.h +++ /dev/null @@ -1,80 +0,0 @@ -//===-- CreateInvocationFromArgs.h - Create an ASTUnit from Args-*- 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 -// -//===----------------------------------------------------------------------===// -// -// Utility for creating an ASTUnit from a vector of command line arguments. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_DRIVER_CREATEASTUNITFROMARGS_H -#define LLVM_CLANG_DRIVER_CREATEASTUNITFROMARGS_H - -#include "clang/Frontend/ASTUnit.h" - -namespace clang { - -/// Create an ASTUnit from a vector of command line arguments, which must -/// specify exactly one source file. -/// -/// \param ArgBegin - The beginning of the argument vector. -/// -/// \param ArgEnd - The end of the argument vector. -/// -/// \param PCHContainerOps - The PCHContainerOperations to use for loading and -/// creating modules. -/// -/// \param Diags - The diagnostics engine to use for reporting errors; its -/// lifetime is expected to extend past that of the returned ASTUnit. -/// -/// \param ResourceFilesPath - The path to the compiler resource files. -/// -/// \param StorePreamblesInMemory - Whether to store PCH in memory. If false, -/// PCH are stored in temporary files. -/// -/// \param PreambleStoragePath - The path to a directory, in which to create -/// temporary PCH files. If empty, the default system temporary directory is -/// used. This parameter is ignored if \p StorePreamblesInMemory is true. -/// -/// \param ModuleFormat - If provided, uses the specific module format. -/// -/// \param ErrAST - If non-null and parsing failed without any AST to return -/// (e.g. because the PCH could not be loaded), this accepts the ASTUnit -/// mainly to allow the caller to see the diagnostics. -/// -/// \param VFS - A llvm::vfs::FileSystem to be used for all file accesses. -/// Note that preamble is saved to a temporary directory on a RealFileSystem, -/// so in order for it to be loaded correctly, VFS should have access to -/// it(i.e., be an overlay over RealFileSystem). RealFileSystem will be used -/// if \p VFS is nullptr. -/// -// FIXME: Move OnlyLocalDecls, UseBumpAllocator to setters on the ASTUnit, we -// shouldn't need to specify them at construction time. -std::unique_ptr CreateASTUnitFromCommandLine( - const char **ArgBegin, const char **ArgEnd, - std::shared_ptr PCHContainerOps, - std::shared_ptr DiagOpts, - IntrusiveRefCntPtr Diags, StringRef ResourceFilesPath, - bool StorePreamblesInMemory = false, - StringRef PreambleStoragePath = StringRef(), bool OnlyLocalDecls = false, - CaptureDiagsKind CaptureDiagnostics = CaptureDiagsKind::None, - ArrayRef RemappedFiles = {}, - bool RemappedFilesKeepOriginalName = true, - unsigned PrecompilePreambleAfterNParses = 0, - TranslationUnitKind TUKind = TU_Complete, - bool CacheCodeCompletionResults = false, - bool IncludeBriefCommentsInCodeCompletion = false, - bool AllowPCHWithCompilerErrors = false, - SkipFunctionBodiesScope SkipFunctionBodies = SkipFunctionBodiesScope::None, - bool SingleFileParse = false, bool UserFilesAreVolatile = false, - bool ForSerialization = false, bool RetainExcludedConditionalBlocks = false, - std::optional ModuleFormat = std::nullopt, - std::unique_ptr *ErrAST = nullptr, - IntrusiveRefCntPtr VFS = nullptr); - -} // namespace clang - -#endif // LLVM_CLANG_DRIVER_CREATEASTUNITFROMARGS_H diff --git a/clang/include/clang/Driver/CreateInvocationFromArgs.h b/clang/include/clang/Driver/CreateInvocationFromArgs.h deleted file mode 100644 index 0e0f67373ce87..0000000000000 --- a/clang/include/clang/Driver/CreateInvocationFromArgs.h +++ /dev/null @@ -1,76 +0,0 @@ -//===--- CreateInvocationFromArgs.h - CompilerInvocation from Args --------===// -// -// 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 -// -//===----------------------------------------------------------------------===// -// -// Utility for creating a CompilerInvocation from command-line arguments, for -// tools to use in preparation to parse a file. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_DRIVER_CREATEINVOCATIONFROMARGS_H -#define LLVM_CLANG_DRIVER_CREATEINVOCATIONFROMARGS_H - -#include "clang/Basic/Diagnostic.h" -#include "clang/Basic/LLVM.h" -#include "llvm/Support/VirtualFileSystem.h" -#include -#include -#include - -namespace clang { - -class CompilerInvocation; -class DiagnosticsEngine; - -/// Optional inputs to createInvocation. -struct CreateInvocationOptions { - /// Receives diagnostics encountered while parsing command-line flags. - /// If not provided, these are printed to stderr. - IntrusiveRefCntPtr Diags = nullptr; - /// Used e.g. to probe for system headers locations. - /// If not provided, the real filesystem is used. - /// FIXME: the driver does perform some non-virtualized IO. - IntrusiveRefCntPtr VFS = nullptr; - /// Whether to attempt to produce a non-null (possibly incorrect) invocation - /// if any errors were encountered. - /// By default, always return null on errors. - bool RecoverOnError = false; - /// Allow the driver to probe the filesystem for PCH files. - /// This is used to replace -include with -include-pch in the cc1 args. - /// FIXME: ProbePrecompiled=true is a poor, historical default. - /// It misbehaves if the PCH file is from GCC, has the wrong version, etc. - bool ProbePrecompiled = false; - /// If set, the target is populated with the cc1 args produced by the driver. - /// This may be populated even if createInvocation returns nullptr. - std::vector *CC1Args = nullptr; -}; - -/// Interpret clang arguments in preparation to parse a file. -/// -/// This simulates a number of steps Clang takes when its driver is invoked: -/// - choosing actions (e.g compile + link) to run -/// - probing the system for settings like standard library locations -/// - spawning a cc1 subprocess to compile code, with more explicit arguments -/// - in the cc1 process, assembling those arguments into a CompilerInvocation -/// which is used to configure the parser -/// -/// This simulation is lossy, e.g. in some situations one driver run would -/// result in multiple parses. (Multi-arch, CUDA, ...). -/// This function tries to select a reasonable invocation that tools should use. -/// -/// Args[0] should be the driver name, such as "clang" or "/usr/bin/g++". -/// Absolute path is preferred - this affects searching for system headers. -/// -/// May return nullptr if an invocation could not be determined. -/// See CreateInvocationOptions::RecoverOnError to try harder! -std::unique_ptr -createInvocation(ArrayRef Args, - CreateInvocationOptions Opts = {}); - -} // namespace clang - -#endif // LLVM_CLANG_DRIVER_CREATEINVOCATIONFROMARGS_H diff --git a/clang/include/clang/Driver/Driver.h b/clang/include/clang/Driver/Driver.h index 76a6c5a128efb..83bcb7cab550f 100644 --- a/clang/include/clang/Driver/Driver.h +++ b/clang/include/clang/Driver/Driver.h @@ -406,6 +406,10 @@ class Driver { SmallString<128> &CrashDiagDir); public: + /// Takes the path to a binary that's either in bin/ or lib/ and returns + /// the path to clang's resource directory. + static std::string GetResourcesPath(StringRef BinaryPath); + Driver(StringRef ClangExecutable, StringRef TargetTriple, DiagnosticsEngine &Diags, std::string Title = "clang LLVM compiler", IntrusiveRefCntPtr VFS = nullptr); diff --git a/clang/include/clang/Frontend/ASTUnit.h b/clang/include/clang/Frontend/ASTUnit.h index 341460e1962cb..e585933a5c8be 100644 --- a/clang/include/clang/Frontend/ASTUnit.h +++ b/clang/include/clang/Frontend/ASTUnit.h @@ -23,13 +23,11 @@ #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetOptions.h" #include "clang/Frontend/PrecompiledPreamble.h" -#include "clang/Frontend/StandaloneDiagnostic.h" #include "clang/Lex/HeaderSearchOptions.h" #include "clang/Lex/ModuleLoader.h" #include "clang/Lex/PreprocessingRecord.h" #include "clang/Sema/CodeCompleteConsumer.h" #include "clang/Serialization/ASTBitCodes.h" -#include "clang/Serialization/ASTWriter.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/IntrusiveRefCntPtr.h" @@ -38,7 +36,6 @@ #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/iterator_range.h" -#include "llvm/Bitstream/BitstreamWriter.h" #include #include #include @@ -91,6 +88,25 @@ enum class CaptureDiagsKind { None, All, AllWithoutNonErrorsFromIncludes }; /// Utility class for loading a ASTContext from an AST file. class ASTUnit { +public: + struct StandaloneFixIt { + std::pair RemoveRange; + std::pair InsertFromRange; + std::string CodeToInsert; + bool BeforePreviousInsertions; + }; + + struct StandaloneDiagnostic { + unsigned ID; + DiagnosticsEngine::Level Level; + std::string Message; + std::string Filename; + unsigned LocOffset; + std::vector> Ranges; + std::vector FixIts; + }; + +private: std::unique_ptr LangOpts; std::unique_ptr CodeGenOpts; // FIXME: The documentation on \c LoadFrom* member functions states that the @@ -113,15 +129,7 @@ class ASTUnit { bool HadModuleLoaderFatalFailure = false; bool StorePreamblesInMemory = false; - /// Utility struct for managing ASTWriter and its associated data streams. - struct ASTWriterData { - SmallString<128> Buffer; - llvm::BitstreamWriter Stream; - ASTWriter Writer; - - ASTWriterData(ModuleCache &ModCache, const CodeGenOptions &CGOpts) - : Stream(Buffer), Writer(Stream, Buffer, ModCache, CGOpts, {}) {} - }; + struct ASTWriterData; std::unique_ptr WriterData; FileSystemOptions FileSystemOpts; @@ -263,6 +271,11 @@ class ASTUnit { static void ConfigureDiags(IntrusiveRefCntPtr Diags, ASTUnit &AST, CaptureDiagsKind CaptureDiagnostics); + void + TranslateStoredDiagnostics(FileManager &FileMgr, SourceManager &SrcMan, + const SmallVectorImpl &Diags, + SmallVectorImpl &Out); + void clearFileLevelDecls(); public: @@ -821,24 +834,65 @@ class ASTUnit { bool IncludeBriefCommentsInCodeCompletion = false, bool UserFilesAreVolatile = false); - friend std::unique_ptr CreateASTUnitFromCommandLine( + /// LoadFromCommandLine - Create an ASTUnit from a vector of command line + /// arguments, which must specify exactly one source file. + /// + /// \param ArgBegin - The beginning of the argument vector. + /// + /// \param ArgEnd - The end of the argument vector. + /// + /// \param PCHContainerOps - The PCHContainerOperations to use for loading and + /// creating modules. + /// + /// \param Diags - The diagnostics engine to use for reporting errors; its + /// lifetime is expected to extend past that of the returned ASTUnit. + /// + /// \param ResourceFilesPath - The path to the compiler resource files. + /// + /// \param StorePreamblesInMemory - Whether to store PCH in memory. If false, + /// PCH are stored in temporary files. + /// + /// \param PreambleStoragePath - The path to a directory, in which to create + /// temporary PCH files. If empty, the default system temporary directory is + /// used. This parameter is ignored if \p StorePreamblesInMemory is true. + /// + /// \param ModuleFormat - If provided, uses the specific module format. + /// + /// \param ErrAST - If non-null and parsing failed without any AST to return + /// (e.g. because the PCH could not be loaded), this accepts the ASTUnit + /// mainly to allow the caller to see the diagnostics. + /// + /// \param VFS - A llvm::vfs::FileSystem to be used for all file accesses. + /// Note that preamble is saved to a temporary directory on a RealFileSystem, + /// so in order for it to be loaded correctly, VFS should have access to + /// it(i.e., be an overlay over RealFileSystem). RealFileSystem will be used + /// if \p VFS is nullptr. + /// + // FIXME: Move OnlyLocalDecls, UseBumpAllocator to setters on the ASTUnit, we + // shouldn't need to specify them at construction time. + static std::unique_ptr LoadFromCommandLine( const char **ArgBegin, const char **ArgEnd, std::shared_ptr PCHContainerOps, std::shared_ptr DiagOpts, IntrusiveRefCntPtr Diags, StringRef ResourceFilesPath, - bool StorePreamblesInMemory, StringRef PreambleStoragePath, - bool OnlyLocalDecls, CaptureDiagsKind CaptureDiagnostics, - ArrayRef RemappedFiles, - bool RemappedFilesKeepOriginalName, - unsigned PrecompilePreambleAfterNParses, TranslationUnitKind TUKind, - bool CacheCodeCompletionResults, - bool IncludeBriefCommentsInCodeCompletion, - bool AllowPCHWithCompilerErrors, - SkipFunctionBodiesScope SkipFunctionBodies, bool SingleFileParse, - bool UserFilesAreVolatile, bool ForSerialization, - bool RetainExcludedConditionalBlocks, - std::optional ModuleFormat, std::unique_ptr *ErrAST, - IntrusiveRefCntPtr VFS); + bool StorePreamblesInMemory = false, + StringRef PreambleStoragePath = StringRef(), bool OnlyLocalDecls = false, + CaptureDiagsKind CaptureDiagnostics = CaptureDiagsKind::None, + ArrayRef RemappedFiles = {}, + bool RemappedFilesKeepOriginalName = true, + unsigned PrecompilePreambleAfterNParses = 0, + TranslationUnitKind TUKind = TU_Complete, + bool CacheCodeCompletionResults = false, + bool IncludeBriefCommentsInCodeCompletion = false, + bool AllowPCHWithCompilerErrors = false, + SkipFunctionBodiesScope SkipFunctionBodies = + SkipFunctionBodiesScope::None, + bool SingleFileParse = false, bool UserFilesAreVolatile = false, + bool ForSerialization = false, + bool RetainExcludedConditionalBlocks = false, + std::optional ModuleFormat = std::nullopt, + std::unique_ptr *ErrAST = nullptr, + IntrusiveRefCntPtr VFS = nullptr); /// Reparse the source files using the same command-line options that /// were originally used to produce this translation unit. @@ -909,44 +963,6 @@ class ASTUnit { bool serialize(raw_ostream &OS); }; -/// Diagnostic consumer that saves each diagnostic it is given. -class FilterAndStoreDiagnosticConsumer : public DiagnosticConsumer { - SmallVectorImpl *StoredDiags; - SmallVectorImpl *StandaloneDiags; - bool CaptureNonErrorsFromIncludes = true; - const LangOptions *LangOpts = nullptr; - SourceManager *SourceMgr = nullptr; - -public: - FilterAndStoreDiagnosticConsumer( - SmallVectorImpl *StoredDiags, - SmallVectorImpl *StandaloneDiags, - bool CaptureNonErrorsFromIncludes); - - void BeginSourceFile(const LangOptions &LangOpts, - const Preprocessor *PP = nullptr) override; - - void HandleDiagnostic(DiagnosticsEngine::Level Level, - const Diagnostic &Info) override; -}; - -/// RAII object that optionally captures and filters diagnostics, if -/// there is no diagnostic client to capture them already. -class CaptureDroppedDiagnostics { - DiagnosticsEngine &Diags; - FilterAndStoreDiagnosticConsumer Client; - DiagnosticConsumer *PreviousClient = nullptr; - std::unique_ptr OwningPreviousClient; - -public: - CaptureDroppedDiagnostics( - CaptureDiagsKind CaptureDiagnostics, DiagnosticsEngine &Diags, - SmallVectorImpl *StoredDiags, - SmallVectorImpl *StandaloneDiags); - - ~CaptureDroppedDiagnostics(); -}; - } // namespace clang #endif // LLVM_CLANG_FRONTEND_ASTUNIT_H diff --git a/clang/include/clang/Frontend/CompilerInvocation.h b/clang/include/clang/Frontend/CompilerInvocation.h index 4977ddb307d21..b19a6e1a8acc3 100644 --- a/clang/include/clang/Frontend/CompilerInvocation.h +++ b/clang/include/clang/Frontend/CompilerInvocation.h @@ -299,6 +299,16 @@ class CompilerInvocation : public CompilerInvocationBase { DiagnosticsEngine &Diags, const char *Argv0 = nullptr); + /// Get the directory where the compiler headers + /// reside, relative to the compiler binary (found by the passed in + /// arguments). + /// + /// \param Argv0 - The program path (from argv[0]), for finding the builtin + /// compiler path. + /// \param MainAddr - The address of main (or some other function in the main + /// executable), for finding the builtin compiler path. + static std::string GetResourcesPath(const char *Argv0, void *MainAddr); + /// Populate \p Opts with the default set of pointer authentication-related /// options given \p LangOpts and \p Triple. /// diff --git a/clang/include/clang/Frontend/StandaloneDiagnostic.h b/clang/include/clang/Frontend/StandaloneDiagnostic.h deleted file mode 100644 index c23d5f95e0c2f..0000000000000 --- a/clang/include/clang/Frontend/StandaloneDiagnostic.h +++ /dev/null @@ -1,82 +0,0 @@ -//===--- StandaloneDiagnostic.h - Serializable Diagnostic -------*- 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 -// -//===----------------------------------------------------------------------===// -// -// A serializable diagnostic representation to retain diagnostics after their -// SourceManager has been destroyed. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_FRONTEND_STANDALONEDIAGNOSTICS_H -#define LLVM_CLANG_FRONTEND_STANDALONEDIAGNOSTICS_H - -#include "clang/Basic/DiagnosticIDs.h" -#include "clang/Basic/DiagnosticOptions.h" -#include "clang/Basic/SourceLocation.h" -#include "clang/Basic/SourceManager.h" -#include "clang/Basic/Specifiers.h" -#include "llvm/ADT/StringExtras.h" -#include -#include -#include - -namespace clang { - -/// Represents a StoredDiagnostic in a form that can be retained until after its -/// SourceManager has been destroyed. -/// -/// Source locations are stored as a combination of filename and offsets into -/// that file. -/// To report the diagnostic, it must first be translated back into a -/// StoredDiagnostic with a new associated SourceManager. -struct StandaloneDiagnostic { - /// Represents a CharSourceRange within a StandaloneDiagnostic. - struct SourceOffsetRange { - SourceOffsetRange(CharSourceRange Range, const SourceManager &SrcMgr, - const LangOptions &LangOpts); - - unsigned Begin = 0; - unsigned End = 0; - }; - - /// Represents a FixItHint within a StandaloneDiagnostic. - struct StandaloneFixIt { - StandaloneFixIt(const SourceManager &SrcMgr, const LangOptions &LangOpts, - const FixItHint &FixIt); - - SourceOffsetRange RemoveRange; - SourceOffsetRange InsertFromRange; - std::string CodeToInsert; - bool BeforePreviousInsertions; - }; - - StandaloneDiagnostic(const LangOptions &LangOpts, - const StoredDiagnostic &InDiag); - - DiagnosticsEngine::Level Level; - SrcMgr::CharacteristicKind FileKind; - unsigned ID = 0; - unsigned FileOffset = 0; - std::string Message; - std::string Filename; - std::vector Ranges; - std::vector FixIts; -}; - -/// Translates \c StandaloneDiag into a StoredDiagnostic, associating it with -/// the provided FileManager and SourceManager. -/// -/// This allows the diagnostic to be emitted using the diagnostics engine, since -/// StandaloneDiagnostics themselfs cannot be emitted directly. -StoredDiagnostic -translateStandaloneDiag(FileManager &FileMgr, SourceManager &SrcMgr, - const StandaloneDiagnostic &StandaloneDiag, - llvm::StringMap &SrcLocCache); - -} // namespace clang - -#endif // STANDALONEDIAGNOSTICS diff --git a/clang/include/clang/Frontend/Utils.h b/clang/include/clang/Frontend/Utils.h index 1c561b47b5c47..ed2703c76f18d 100644 --- a/clang/include/clang/Frontend/Utils.h +++ b/clang/include/clang/Frontend/Utils.h @@ -192,6 +192,51 @@ IntrusiveRefCntPtr createChainedIncludesSource(CompilerInstance &CI, IntrusiveRefCntPtr &OutReader); +/// Optional inputs to createInvocation. +struct CreateInvocationOptions { + /// Receives diagnostics encountered while parsing command-line flags. + /// If not provided, these are printed to stderr. + IntrusiveRefCntPtr Diags = nullptr; + /// Used e.g. to probe for system headers locations. + /// If not provided, the real filesystem is used. + /// FIXME: the driver does perform some non-virtualized IO. + IntrusiveRefCntPtr VFS = nullptr; + /// Whether to attempt to produce a non-null (possibly incorrect) invocation + /// if any errors were encountered. + /// By default, always return null on errors. + bool RecoverOnError = false; + /// Allow the driver to probe the filesystem for PCH files. + /// This is used to replace -include with -include-pch in the cc1 args. + /// FIXME: ProbePrecompiled=true is a poor, historical default. + /// It misbehaves if the PCH file is from GCC, has the wrong version, etc. + bool ProbePrecompiled = false; + /// If set, the target is populated with the cc1 args produced by the driver. + /// This may be populated even if createInvocation returns nullptr. + std::vector *CC1Args = nullptr; +}; + +/// Interpret clang arguments in preparation to parse a file. +/// +/// This simulates a number of steps Clang takes when its driver is invoked: +/// - choosing actions (e.g compile + link) to run +/// - probing the system for settings like standard library locations +/// - spawning a cc1 subprocess to compile code, with more explicit arguments +/// - in the cc1 process, assembling those arguments into a CompilerInvocation +/// which is used to configure the parser +/// +/// This simulation is lossy, e.g. in some situations one driver run would +/// result in multiple parses. (Multi-arch, CUDA, ...). +/// This function tries to select a reasonable invocation that tools should use. +/// +/// Args[0] should be the driver name, such as "clang" or "/usr/bin/g++". +/// Absolute path is preferred - this affects searching for system headers. +/// +/// May return nullptr if an invocation could not be determined. +/// See CreateInvocationOptions::ShouldRecoverOnErrors to try harder! +std::unique_ptr +createInvocation(ArrayRef Args, + CreateInvocationOptions Opts = {}); + } // namespace clang #endif // LLVM_CLANG_FRONTEND_UTILS_H diff --git a/clang/include/clang/Options/OptionUtils.h b/clang/include/clang/Options/OptionUtils.h index 02c9c27554db1..83c48bd7d6843 100644 --- a/clang/include/clang/Options/OptionUtils.h +++ b/clang/include/clang/Options/OptionUtils.h @@ -28,7 +28,6 @@ class ArgList; } // namespace llvm namespace clang { - /// Return the value of the last argument as an integer, or a default. If Diags /// is non-null, emits an error if the argument is given, but non-integral. int getLastArgIntValue(const llvm::opt::ArgList &Args, @@ -54,29 +53,6 @@ inline uint64_t getLastArgUInt64Value(const llvm::opt::ArgList &Args, return getLastArgUInt64Value(Args, Id, Default, &Diags, Base); } -// Parse -mprefer-vector-width=. Return the Value string if well-formed. -// Otherwise, return an empty string and issue a diagnosic message if needed. -StringRef parseMPreferVectorWidthOption(clang::DiagnosticsEngine &Diags, - const llvm::opt::ArgList &Args); - -// Parse -mrecip. Return the Value string if well-formed. -// Otherwise, return an empty string and issue a diagnosic message if needed. -StringRef parseMRecipOption(clang::DiagnosticsEngine &Diags, - const llvm::opt::ArgList &Args); - -/// Get the directory where the compiler headers reside, relative to the -/// compiler binary path \p BinaryPath. -std::string GetResourcesPath(StringRef BinaryPath); - -/// Get the directory where the compiler headers reside, relative to the -/// compiler binary path (found by the passed in arguments). -/// -/// \param Argv0 The program path (from argv[0]), for finding the builtin -/// compiler path. -/// \param MainAddr The address of main (or some other function in the main -/// executable), for finding the builtin compiler path. -std::string GetResourcesPath(const char *Argv0, void *MainAddr); - } // namespace clang #endif // LLVM_CLANG_OPTIONS_OPTIONUTILS_H diff --git a/clang/lib/CrossTU/CMakeLists.txt b/clang/lib/CrossTU/CMakeLists.txt index eef7a892701fb..3349fc283925d 100644 --- a/clang/lib/CrossTU/CMakeLists.txt +++ b/clang/lib/CrossTU/CMakeLists.txt @@ -9,7 +9,6 @@ add_clang_library(clangCrossTU LINK_LIBS clangAST clangBasic - clangDriver clangFrontend clangIndex ) diff --git a/clang/lib/CrossTU/CrossTranslationUnit.cpp b/clang/lib/CrossTU/CrossTranslationUnit.cpp index a3fc2cf6bfb3c..0287845a741ed 100644 --- a/clang/lib/CrossTU/CrossTranslationUnit.cpp +++ b/clang/lib/CrossTU/CrossTranslationUnit.cpp @@ -16,7 +16,6 @@ #include "clang/Basic/DiagnosticDriver.h" #include "clang/Basic/TargetInfo.h" #include "clang/CrossTU/CrossTUDiagnostic.h" -#include "clang/Driver/CreateASTUnitFromArgs.h" #include "clang/Frontend/ASTUnit.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/TextDiagnosticPrinter.h" @@ -620,7 +619,7 @@ CrossTranslationUnitContext::ASTLoader::loadFromSource( auto Diags = llvm::makeIntrusiveRefCnt(DiagID, *DiagOpts, DiagClient); - return CreateASTUnitFromCommandLine( + return ASTUnit::LoadFromCommandLine( CommandLineArgs.begin(), (CommandLineArgs.end()), CI.getPCHContainerOperations(), DiagOpts, Diags, CI.getHeaderSearchOpts().ResourceDir); diff --git a/clang/lib/Driver/CMakeLists.txt b/clang/lib/Driver/CMakeLists.txt index d987111827597..8052659e9836b 100644 --- a/clang/lib/Driver/CMakeLists.txt +++ b/clang/lib/Driver/CMakeLists.txt @@ -17,8 +17,6 @@ endif() add_clang_library(clangDriver Action.cpp Compilation.cpp - CreateASTUnitFromArgs.cpp - CreateInvocationFromArgs.cpp Distro.cpp Driver.cpp Job.cpp @@ -98,8 +96,6 @@ add_clang_library(clangDriver LINK_LIBS clangBasic - clangFrontend - clangSerialization clangLex clangOptions ${system_libs} diff --git a/clang/lib/Driver/CreateASTUnitFromArgs.cpp b/clang/lib/Driver/CreateASTUnitFromArgs.cpp deleted file mode 100644 index ea31a8ed07c5f..0000000000000 --- a/clang/lib/Driver/CreateASTUnitFromArgs.cpp +++ /dev/null @@ -1,166 +0,0 @@ -//===--- CreateASTUnitFromArgs.h - Create an ASTUnit from Args ------------===// -// -// 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 -// -//===----------------------------------------------------------------------===// -// -// Utility for creating an ASTUnit from a vector of command line arguments. -// -//===----------------------------------------------------------------------===// - -#include "clang/Driver/CreateASTUnitFromArgs.h" -#include "clang/Driver/CreateInvocationFromArgs.h" -#include "clang/Frontend/CompilerInvocation.h" -#include "clang/Lex/PreprocessorOptions.h" -#include "clang/Serialization/ModuleCache.h" -#include "llvm/Support/CrashRecoveryContext.h" - -using namespace clang; - -/// Create an ASTUnit from a vector of command line arguments, which must -/// specify exactly one source file. -/// -/// \param ArgBegin - The beginning of the argument vector. -/// -/// \param ArgEnd - The end of the argument vector. -/// -/// \param PCHContainerOps - The PCHContainerOperations to use for loading and -/// creating modules. -/// -/// \param Diags - The diagnostics engine to use for reporting errors; its -/// lifetime is expected to extend past that of the returned ASTUnit. -/// -/// \param ResourceFilesPath - The path to the compiler resource files. -/// -/// \param StorePreamblesInMemory - Whether to store PCH in memory. If false, -/// PCH are stored in temporary files. -/// -/// \param PreambleStoragePath - The path to a directory, in which to create -/// temporary PCH files. If empty, the default system temporary directory is -/// used. This parameter is ignored if \p StorePreamblesInMemory is true. -/// -/// \param ModuleFormat - If provided, uses the specific module format. -/// -/// \param ErrAST - If non-null and parsing failed without any AST to return -/// (e.g. because the PCH could not be loaded), this accepts the ASTUnit -/// mainly to allow the caller to see the diagnostics. -/// -/// \param VFS - A llvm::vfs::FileSystem to be used for all file accesses. -/// Note that preamble is saved to a temporary directory on a RealFileSystem, -/// so in order for it to be loaded correctly, VFS should have access to -/// it(i.e., be an overlay over RealFileSystem). RealFileSystem will be used -/// if \p VFS is nullptr. -/// -// FIXME: Move OnlyLocalDecls, UseBumpAllocator to setters on the ASTUnit, we -// shouldn't need to specify them at construction time. -std::unique_ptr clang::CreateASTUnitFromCommandLine( - const char **ArgBegin, const char **ArgEnd, - std::shared_ptr PCHContainerOps, - std::shared_ptr DiagOpts, - IntrusiveRefCntPtr Diags, StringRef ResourceFilesPath, - bool StorePreamblesInMemory, StringRef PreambleStoragePath, - bool OnlyLocalDecls, CaptureDiagsKind CaptureDiagnostics, - ArrayRef RemappedFiles, - bool RemappedFilesKeepOriginalName, unsigned PrecompilePreambleAfterNParses, - TranslationUnitKind TUKind, bool CacheCodeCompletionResults, - bool IncludeBriefCommentsInCodeCompletion, bool AllowPCHWithCompilerErrors, - SkipFunctionBodiesScope SkipFunctionBodies, bool SingleFileParse, - bool UserFilesAreVolatile, bool ForSerialization, - bool RetainExcludedConditionalBlocks, std::optional ModuleFormat, - std::unique_ptr *ErrAST, - IntrusiveRefCntPtr VFS) { - assert(Diags.get() && "no DiagnosticsEngine was provided"); - - // If no VFS was provided, create one that tracks the physical file system. - // If '-working-directory' was passed as an argument, 'createInvocation' will - // set this as the current working directory of the VFS. - if (!VFS) - VFS = llvm::vfs::createPhysicalFileSystem(); - - SmallVector StoredDiagnostics; - - std::shared_ptr CI; - - { - CaptureDroppedDiagnostics Capture(CaptureDiagnostics, *Diags, - &StoredDiagnostics, nullptr); - - CreateInvocationOptions CIOpts; - CIOpts.VFS = VFS; - CIOpts.Diags = Diags; - CIOpts.ProbePrecompiled = true; // FIXME: historical default. Needed? - CI = createInvocation(llvm::ArrayRef(ArgBegin, ArgEnd), std::move(CIOpts)); - if (!CI) - return nullptr; - } - - // Override any files that need remapping - for (const auto &RemappedFile : RemappedFiles) { - CI->getPreprocessorOpts().addRemappedFile(RemappedFile.first, - RemappedFile.second); - } - PreprocessorOptions &PPOpts = CI->getPreprocessorOpts(); - PPOpts.RemappedFilesKeepOriginalName = RemappedFilesKeepOriginalName; - PPOpts.AllowPCHWithCompilerErrors = AllowPCHWithCompilerErrors; - PPOpts.SingleFileParseMode = SingleFileParse; - PPOpts.RetainExcludedConditionalBlocks = RetainExcludedConditionalBlocks; - - // Override the resources path. - CI->getHeaderSearchOpts().ResourceDir = std::string(ResourceFilesPath); - - CI->getFrontendOpts().SkipFunctionBodies = - SkipFunctionBodies == SkipFunctionBodiesScope::PreambleAndMainFile; - - if (ModuleFormat) - CI->getHeaderSearchOpts().ModuleFormat = std::string(*ModuleFormat); - - // Create the AST unit. - std::unique_ptr AST; - AST.reset(new ASTUnit(false)); - AST->NumStoredDiagnosticsFromDriver = StoredDiagnostics.size(); - AST->StoredDiagnostics.swap(StoredDiagnostics); - ASTUnit::ConfigureDiags(Diags, *AST, CaptureDiagnostics); - AST->DiagOpts = DiagOpts; - AST->Diagnostics = Diags; - AST->FileSystemOpts = CI->getFileSystemOpts(); - AST->CodeGenOpts = std::make_unique(CI->getCodeGenOpts()); - VFS = createVFSFromCompilerInvocation(*CI, *Diags, VFS); - AST->FileMgr = - llvm::makeIntrusiveRefCnt(AST->FileSystemOpts, VFS); - AST->StorePreamblesInMemory = StorePreamblesInMemory; - AST->PreambleStoragePath = PreambleStoragePath; - AST->ModCache = createCrossProcessModuleCache(); - AST->OnlyLocalDecls = OnlyLocalDecls; - AST->CaptureDiagnostics = CaptureDiagnostics; - AST->TUKind = TUKind; - AST->ShouldCacheCodeCompletionResults = CacheCodeCompletionResults; - AST->IncludeBriefCommentsInCodeCompletion = - IncludeBriefCommentsInCodeCompletion; - AST->UserFilesAreVolatile = UserFilesAreVolatile; - AST->Invocation = CI; - AST->SkipFunctionBodies = SkipFunctionBodies; - if (ForSerialization) - AST->WriterData.reset( - new ASTUnit::ASTWriterData(*AST->ModCache, *AST->CodeGenOpts)); - // Zero out now to ease cleanup during crash recovery. - CI = nullptr; - Diags = nullptr; - - // Recover resources if we crash before exiting this method. - llvm::CrashRecoveryContextCleanupRegistrar ASTUnitCleanup(AST.get()); - - if (AST->LoadFromCompilerInvocation(std::move(PCHContainerOps), - PrecompilePreambleAfterNParses, VFS)) { - // Some error occurred, if caller wants to examine diagnostics, pass it the - // ASTUnit. - if (ErrAST) { - AST->StoredDiagnostics.swap(AST->FailedParseDiagnostics); - ErrAST->swap(AST); - } - return nullptr; - } - - return AST; -} diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index c6dd66d9efef3..de8d4601210ae 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -66,7 +66,6 @@ #include "clang/Driver/ToolChain.h" #include "clang/Driver/Types.h" #include "clang/Lex/DependencyDirectivesScanner.h" -#include "clang/Options/OptionUtils.h" #include "clang/Options/Options.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/STLExtras.h" @@ -126,6 +125,40 @@ template static bool usesInput(const ArgList &Args, F &&Fn) { }); } +// static +std::string Driver::GetResourcesPath(StringRef BinaryPath) { + // Since the resource directory is embedded in the module hash, it's important + // that all places that need it call this function, so that they get the + // exact same string ("a/../b/" and "b/" get different hashes, for example). + + // Dir is bin/ or lib/, depending on where BinaryPath is. + StringRef Dir = llvm::sys::path::parent_path(BinaryPath); + SmallString<128> P(Dir); + + StringRef ConfiguredResourceDir(CLANG_RESOURCE_DIR); + if (!ConfiguredResourceDir.empty()) { + // FIXME: We should fix the behavior of llvm::sys::path::append so we don't + // need to check for absolute paths here. + if (llvm::sys::path::is_absolute(ConfiguredResourceDir)) + P = ConfiguredResourceDir; + else + llvm::sys::path::append(P, ConfiguredResourceDir); + } else { + // On Windows, libclang.dll is in bin/. + // On non-Windows, libclang.so/.dylib is in lib/. + // With a static-library build of libclang, LibClangPath will contain the + // path of the embedding binary, which for LLVM binaries will be in bin/. + // ../lib gets us to lib/ in both cases. + P = llvm::sys::path::parent_path(Dir); + // This search path is also created in the COFF driver of lld, so any + // changes here also needs to happen in lld/COFF/Driver.cpp + llvm::sys::path::append(P, CLANG_INSTALL_LIBDIR_BASENAME, "clang", + CLANG_VERSION_MAJOR_STRING); + } + + return std::string(P); +} + CUIDOptions::CUIDOptions(llvm::opt::DerivedArgList &Args, const Driver &D) : UseCUID(Kind::Hash) { if (Arg *A = Args.getLastArg(options::OPT_fuse_cuid_EQ)) { diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 2f0aec3ec3c37..c5d40c9825fab 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -32,7 +32,6 @@ #include "clang/Driver/SanitizerArgs.h" #include "clang/Driver/Types.h" #include "clang/Driver/XRayArgs.h" -#include "clang/Options/OptionUtils.h" #include "clang/Options/Options.h" #include "llvm/ADT/ScopeExit.h" #include "llvm/ADT/SmallSet.h" diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp index d3539a594df11..4c036f0f8dee3 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -3398,6 +3398,169 @@ void tools::handleInterchangeLoopsArgs(const ArgList &Args, CmdArgs.push_back("-floop-interchange"); } +// Parse -mprefer-vector-width=. Return the Value string if well-formed. +// Otherwise, return an empty string and issue a diagnosic message if needed. +StringRef tools::parseMPreferVectorWidthOption(clang::DiagnosticsEngine &Diags, + const llvm::opt::ArgList &Args) { + Arg *A = Args.getLastArg(options::OPT_mprefer_vector_width_EQ); + if (!A) + return ""; + + StringRef Value = A->getValue(); + unsigned Width LLVM_ATTRIBUTE_UNINITIALIZED; + + // Only "none" and Integer values are accepted by + // -mprefer-vector-width=. + if (Value != "none" && Value.getAsInteger(10, Width)) { + Diags.Report(clang::diag::err_drv_invalid_value) + << A->getOption().getName() << Value; + return ""; + } + + return Value; +} + +// This is a helper function for validating the optional refinement step +// parameter in reciprocal argument strings. Return false if there is an error +// parsing the refinement step. Otherwise, return true and set the Position +// of the refinement step in the input string. +static bool getRefinementStep(StringRef In, clang::DiagnosticsEngine &Diags, + const Arg &A, size_t &Position) { + const char RefinementStepToken = ':'; + Position = In.find(RefinementStepToken); + if (Position != StringRef::npos) { + StringRef Option = A.getOption().getName(); + StringRef RefStep = In.substr(Position + 1); + // Allow exactly one numeric character for the additional refinement + // step parameter. This is reasonable for all currently-supported + // operations and architectures because we would expect that a larger value + // of refinement steps would cause the estimate "optimization" to + // under-perform the native operation. Also, if the estimate does not + // converge quickly, it probably will not ever converge, so further + // refinement steps will not produce a better answer. + if (RefStep.size() != 1) { + Diags.Report(diag::err_drv_invalid_value) << Option << RefStep; + return false; + } + char RefStepChar = RefStep[0]; + if (RefStepChar < '0' || RefStepChar > '9') { + Diags.Report(diag::err_drv_invalid_value) << Option << RefStep; + return false; + } + } + return true; +} + +// Parse -mrecip. Return the Value string if well-formed. +// Otherwise, return an empty string and issue a diagnosic message if needed. +StringRef tools::parseMRecipOption(clang::DiagnosticsEngine &Diags, + const ArgList &Args) { + StringRef DisabledPrefixIn = "!"; + StringRef DisabledPrefixOut = "!"; + StringRef EnabledPrefixOut = ""; + StringRef Out = ""; + + Arg *A = Args.getLastArg(options::OPT_mrecip, options::OPT_mrecip_EQ); + if (!A) + return ""; + + unsigned NumOptions = A->getNumValues(); + if (NumOptions == 0) { + // No option is the same as "all". + return "all"; + } + + // Pass through "all", "none", or "default" with an optional refinement step. + if (NumOptions == 1) { + StringRef Val = A->getValue(0); + size_t RefStepLoc; + if (!getRefinementStep(Val, Diags, *A, RefStepLoc)) + return ""; + StringRef ValBase = Val.slice(0, RefStepLoc); + if (ValBase == "all" || ValBase == "none" || ValBase == "default") { + return Val; + } + } + + // Each reciprocal type may be enabled or disabled individually. + // Check each input value for validity, concatenate them all back together, + // and pass through. + + llvm::StringMap OptionStrings; + OptionStrings.insert(std::make_pair("divd", false)); + OptionStrings.insert(std::make_pair("divf", false)); + OptionStrings.insert(std::make_pair("divh", false)); + OptionStrings.insert(std::make_pair("vec-divd", false)); + OptionStrings.insert(std::make_pair("vec-divf", false)); + OptionStrings.insert(std::make_pair("vec-divh", false)); + OptionStrings.insert(std::make_pair("sqrtd", false)); + OptionStrings.insert(std::make_pair("sqrtf", false)); + OptionStrings.insert(std::make_pair("sqrth", false)); + OptionStrings.insert(std::make_pair("vec-sqrtd", false)); + OptionStrings.insert(std::make_pair("vec-sqrtf", false)); + OptionStrings.insert(std::make_pair("vec-sqrth", false)); + + for (unsigned i = 0; i != NumOptions; ++i) { + StringRef Val = A->getValue(i); + + bool IsDisabled = Val.starts_with(DisabledPrefixIn); + // Ignore the disablement token for string matching. + if (IsDisabled) + Val = Val.substr(1); + + size_t RefStep; + if (!getRefinementStep(Val, Diags, *A, RefStep)) + return ""; + + StringRef ValBase = Val.slice(0, RefStep); + llvm::StringMap::iterator OptionIter = OptionStrings.find(ValBase); + if (OptionIter == OptionStrings.end()) { + // Try again specifying float suffix. + OptionIter = OptionStrings.find(ValBase.str() + 'f'); + if (OptionIter == OptionStrings.end()) { + // The input name did not match any known option string. + Diags.Report(diag::err_drv_unknown_argument) << Val; + return ""; + } + // The option was specified without a half or float or double suffix. + // Make sure that the double or half entry was not already specified. + // The float entry will be checked below. + if (OptionStrings[ValBase.str() + 'd'] || + OptionStrings[ValBase.str() + 'h']) { + Diags.Report(diag::err_drv_invalid_value) + << A->getOption().getName() << Val; + return ""; + } + } + + if (OptionIter->second == true) { + // Duplicate option specified. + Diags.Report(diag::err_drv_invalid_value) + << A->getOption().getName() << Val; + return ""; + } + + // Mark the matched option as found. Do not allow duplicate specifiers. + OptionIter->second = true; + + // If the precision was not specified, also mark the double and half entry + // as found. + if (ValBase.back() != 'f' && ValBase.back() != 'd' && + ValBase.back() != 'h') { + OptionStrings[ValBase.str() + 'd'] = true; + OptionStrings[ValBase.str() + 'h'] = true; + } + + // Build the output string. + StringRef Prefix = IsDisabled ? DisabledPrefixOut : EnabledPrefixOut; + Out = Args.MakeArgString(Out + Prefix + Val); + if (i != NumOptions - 1) + Out = Args.MakeArgString(Out + ","); + } + + return Out; +} + std::string tools::complexRangeKindToStr(LangOptions::ComplexRangeKind Range) { switch (Range) { case LangOptions::ComplexRangeKind::CX_Full: diff --git a/clang/lib/Driver/ToolChains/Flang.cpp b/clang/lib/Driver/ToolChains/Flang.cpp index 438de23be0103..cc4755cd6a9b0 100644 --- a/clang/lib/Driver/ToolChains/Flang.cpp +++ b/clang/lib/Driver/ToolChains/Flang.cpp @@ -11,7 +11,6 @@ #include "clang/Basic/CodeGenOptions.h" #include "clang/Driver/CommonArgs.h" -#include "clang/Options/OptionUtils.h" #include "clang/Options/Options.h" #include "llvm/Frontend/Debug/Options.h" #include "llvm/Support/Path.h" diff --git a/clang/lib/Frontend/ASTUnit.cpp b/clang/lib/Frontend/ASTUnit.cpp index e72317da64596..1de779ccbf141 100644 --- a/clang/lib/Frontend/ASTUnit.cpp +++ b/clang/lib/Frontend/ASTUnit.cpp @@ -44,7 +44,6 @@ #include "clang/Frontend/FrontendOptions.h" #include "clang/Frontend/MultiplexConsumer.h" #include "clang/Frontend/PrecompiledPreamble.h" -#include "clang/Frontend/StandaloneDiagnostic.h" #include "clang/Frontend/Utils.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/HeaderSearchOptions.h" @@ -211,6 +210,15 @@ getBufferForFileHandlingRemapping(const CompilerInvocation &Invocation, return llvm::MemoryBuffer::getMemBufferCopy(Buffer->getBuffer(), FilePath); } +struct ASTUnit::ASTWriterData { + SmallString<128> Buffer; + llvm::BitstreamWriter Stream; + ASTWriter Writer; + + ASTWriterData(ModuleCache &ModCache, const CodeGenOptions &CGOpts) + : Stream(Buffer), Writer(Stream, Buffer, ModCache, CGOpts, {}) {} +}; + void ASTUnit::clearFileLevelDecls() { FileDecls.clear(); } @@ -573,24 +581,73 @@ class ASTInfoCollector : public ASTReaderListener { Counter = NewCounter; } }; -} // anonymous namespace -FilterAndStoreDiagnosticConsumer::FilterAndStoreDiagnosticConsumer( - SmallVectorImpl *StoredDiags, - SmallVectorImpl *StandaloneDiags, - bool CaptureNonErrorsFromIncludes) - : StoredDiags(StoredDiags), StandaloneDiags(StandaloneDiags), - CaptureNonErrorsFromIncludes(CaptureNonErrorsFromIncludes) { - assert((StoredDiags || StandaloneDiags) && - "No output collections were passed to StoredDiagnosticConsumer."); -} +/// Diagnostic consumer that saves each diagnostic it is given. +class FilterAndStoreDiagnosticConsumer : public DiagnosticConsumer { + SmallVectorImpl *StoredDiags; + SmallVectorImpl *StandaloneDiags; + bool CaptureNonErrorsFromIncludes = true; + const LangOptions *LangOpts = nullptr; + SourceManager *SourceMgr = nullptr; -void FilterAndStoreDiagnosticConsumer::BeginSourceFile( - const LangOptions &LangOpts, const Preprocessor *PP) { - this->LangOpts = &LangOpts; - if (PP) - SourceMgr = &PP->getSourceManager(); -} +public: + FilterAndStoreDiagnosticConsumer( + SmallVectorImpl *StoredDiags, + SmallVectorImpl *StandaloneDiags, + bool CaptureNonErrorsFromIncludes) + : StoredDiags(StoredDiags), StandaloneDiags(StandaloneDiags), + CaptureNonErrorsFromIncludes(CaptureNonErrorsFromIncludes) { + assert((StoredDiags || StandaloneDiags) && + "No output collections were passed to StoredDiagnosticConsumer."); + } + + void BeginSourceFile(const LangOptions &LangOpts, + const Preprocessor *PP = nullptr) override { + this->LangOpts = &LangOpts; + if (PP) + SourceMgr = &PP->getSourceManager(); + } + + void HandleDiagnostic(DiagnosticsEngine::Level Level, + const Diagnostic &Info) override; +}; + +/// RAII object that optionally captures and filters diagnostics, if +/// there is no diagnostic client to capture them already. +class CaptureDroppedDiagnostics { + DiagnosticsEngine &Diags; + FilterAndStoreDiagnosticConsumer Client; + DiagnosticConsumer *PreviousClient = nullptr; + std::unique_ptr OwningPreviousClient; + +public: + CaptureDroppedDiagnostics( + CaptureDiagsKind CaptureDiagnostics, DiagnosticsEngine &Diags, + SmallVectorImpl *StoredDiags, + SmallVectorImpl *StandaloneDiags) + : Diags(Diags), + Client(StoredDiags, StandaloneDiags, + CaptureDiagnostics != + CaptureDiagsKind::AllWithoutNonErrorsFromIncludes) { + if (CaptureDiagnostics != CaptureDiagsKind::None || + Diags.getClient() == nullptr) { + OwningPreviousClient = Diags.takeClient(); + PreviousClient = Diags.getClient(); + Diags.setClient(&Client, false); + } + } + + ~CaptureDroppedDiagnostics() { + if (Diags.getClient() == &Client) + Diags.setClient(PreviousClient, !!OwningPreviousClient.release()); + } +}; + +} // namespace + +static ASTUnit::StandaloneDiagnostic +makeStandaloneDiagnostic(const LangOptions &LangOpts, + const StoredDiagnostic &InDiag); static bool isInMainFile(const clang::Diagnostic &D) { if (!D.hasSourceManager() || !D.getLocation().isValid()) @@ -626,32 +683,12 @@ void FilterAndStoreDiagnosticConsumer::HandleDiagnostic( StoredDiag.emplace(Level, Info); ResultDiag = &*StoredDiag; } - StandaloneDiags->emplace_back(*LangOpts, *ResultDiag); + StandaloneDiags->push_back( + makeStandaloneDiagnostic(*LangOpts, *ResultDiag)); } } } -CaptureDroppedDiagnostics::CaptureDroppedDiagnostics( - CaptureDiagsKind CaptureDiagnostics, DiagnosticsEngine &Diags, - SmallVectorImpl *StoredDiags, - SmallVectorImpl *StandaloneDiags) - : Diags(Diags), - Client(StoredDiags, StandaloneDiags, - CaptureDiagnostics != - CaptureDiagsKind::AllWithoutNonErrorsFromIncludes) { - if (CaptureDiagnostics != CaptureDiagsKind::None || - Diags.getClient() == nullptr) { - OwningPreviousClient = Diags.takeClient(); - PreviousClient = Diags.getClient(); - Diags.setClient(&Client, false); - } -} - -CaptureDroppedDiagnostics::~CaptureDroppedDiagnostics() { - if (Diags.getClient() == &Client) - Diags.setClient(PreviousClient, !!OwningPreviousClient.release()); -} - IntrusiveRefCntPtr ASTUnit::getASTReader() const { return Reader; } @@ -1073,7 +1110,7 @@ class ASTUnitPreambleCallbacks : public PreambleCallbacks { unsigned Hash = 0; std::vector TopLevelDecls; std::vector TopLevelDeclIDs; - llvm::SmallVector PreambleDiags; + llvm::SmallVector PreambleDiags; }; } // namespace @@ -1222,17 +1259,10 @@ bool ASTUnit::Parse(std::shared_ptr PCHContainerOps, if (!Act->BeginSourceFile(*Clang, Clang->getFrontendOpts().Inputs[0])) return true; - if (SavedMainFileBuffer) { - StoredDiagnostics.clear(); - StoredDiagnostics.reserve(PreambleDiagnostics.size()); - llvm::transform(std::move(PreambleDiagnostics), - std::back_inserter(StoredDiagnostics), - [&](auto &&StandaloneDiag) { - return translateStandaloneDiag( - getFileManager(), getSourceManager(), - std::move(StandaloneDiag), PreambleSrcLocCache); - }); - } else + if (SavedMainFileBuffer) + TranslateStoredDiagnostics(getFileManager(), getSourceManager(), + PreambleDiagnostics, StoredDiagnostics); + else PreambleSrcLocCache.clear(); if (llvm::Error Err = Act->Execute()) { @@ -1251,6 +1281,51 @@ bool ASTUnit::Parse(std::shared_ptr PCHContainerOps, return false; } +static std::pair +makeStandaloneRange(CharSourceRange Range, const SourceManager &SM, + const LangOptions &LangOpts) { + CharSourceRange FileRange = Lexer::makeFileCharRange(Range, SM, LangOpts); + unsigned Offset = SM.getFileOffset(FileRange.getBegin()); + unsigned EndOffset = SM.getFileOffset(FileRange.getEnd()); + return std::make_pair(Offset, EndOffset); +} + +static ASTUnit::StandaloneFixIt makeStandaloneFixIt(const SourceManager &SM, + const LangOptions &LangOpts, + const FixItHint &InFix) { + ASTUnit::StandaloneFixIt OutFix; + OutFix.RemoveRange = makeStandaloneRange(InFix.RemoveRange, SM, LangOpts); + OutFix.InsertFromRange = + makeStandaloneRange(InFix.InsertFromRange, SM, LangOpts); + OutFix.CodeToInsert = InFix.CodeToInsert; + OutFix.BeforePreviousInsertions = InFix.BeforePreviousInsertions; + return OutFix; +} + +static ASTUnit::StandaloneDiagnostic +makeStandaloneDiagnostic(const LangOptions &LangOpts, + const StoredDiagnostic &InDiag) { + ASTUnit::StandaloneDiagnostic OutDiag; + OutDiag.ID = InDiag.getID(); + OutDiag.Level = InDiag.getLevel(); + OutDiag.Message = std::string(InDiag.getMessage()); + OutDiag.LocOffset = 0; + if (InDiag.getLocation().isInvalid()) + return OutDiag; + const SourceManager &SM = InDiag.getLocation().getManager(); + SourceLocation FileLoc = SM.getFileLoc(InDiag.getLocation()); + OutDiag.Filename = std::string(SM.getFilename(FileLoc)); + if (OutDiag.Filename.empty()) + return OutDiag; + OutDiag.LocOffset = SM.getFileOffset(FileLoc); + for (const auto &Range : InDiag.getRanges()) + OutDiag.Ranges.push_back(makeStandaloneRange(Range, SM, LangOpts)); + for (const auto &FixIt : InDiag.getFixIts()) + OutDiag.FixIts.push_back(makeStandaloneFixIt(SM, LangOpts, FixIt)); + + return OutDiag; +} + /// Attempt to build or re-use a precompiled preamble when (re-)parsing /// the source file. /// @@ -1705,6 +1780,114 @@ std::unique_ptr ASTUnit::LoadFromCompilerInvocation( return AST; } +std::unique_ptr ASTUnit::LoadFromCommandLine( + const char **ArgBegin, const char **ArgEnd, + std::shared_ptr PCHContainerOps, + std::shared_ptr DiagOpts, + IntrusiveRefCntPtr Diags, StringRef ResourceFilesPath, + bool StorePreamblesInMemory, StringRef PreambleStoragePath, + bool OnlyLocalDecls, CaptureDiagsKind CaptureDiagnostics, + ArrayRef RemappedFiles, bool RemappedFilesKeepOriginalName, + unsigned PrecompilePreambleAfterNParses, TranslationUnitKind TUKind, + bool CacheCodeCompletionResults, bool IncludeBriefCommentsInCodeCompletion, + bool AllowPCHWithCompilerErrors, SkipFunctionBodiesScope SkipFunctionBodies, + bool SingleFileParse, bool UserFilesAreVolatile, bool ForSerialization, + bool RetainExcludedConditionalBlocks, std::optional ModuleFormat, + std::unique_ptr *ErrAST, + IntrusiveRefCntPtr VFS) { + assert(Diags.get() && "no DiagnosticsEngine was provided"); + + // If no VFS was provided, create one that tracks the physical file system. + // If '-working-directory' was passed as an argument, 'createInvocation' will + // set this as the current working directory of the VFS. + if (!VFS) + VFS = llvm::vfs::createPhysicalFileSystem(); + + SmallVector StoredDiagnostics; + + std::shared_ptr CI; + + { + CaptureDroppedDiagnostics Capture(CaptureDiagnostics, *Diags, + &StoredDiagnostics, nullptr); + + CreateInvocationOptions CIOpts; + CIOpts.VFS = VFS; + CIOpts.Diags = Diags; + CIOpts.ProbePrecompiled = true; // FIXME: historical default. Needed? + CI = createInvocation(llvm::ArrayRef(ArgBegin, ArgEnd), std::move(CIOpts)); + if (!CI) + return nullptr; + } + + // Override any files that need remapping + for (const auto &RemappedFile : RemappedFiles) { + CI->getPreprocessorOpts().addRemappedFile(RemappedFile.first, + RemappedFile.second); + } + PreprocessorOptions &PPOpts = CI->getPreprocessorOpts(); + PPOpts.RemappedFilesKeepOriginalName = RemappedFilesKeepOriginalName; + PPOpts.AllowPCHWithCompilerErrors = AllowPCHWithCompilerErrors; + PPOpts.SingleFileParseMode = SingleFileParse; + PPOpts.RetainExcludedConditionalBlocks = RetainExcludedConditionalBlocks; + + // Override the resources path. + CI->getHeaderSearchOpts().ResourceDir = std::string(ResourceFilesPath); + + CI->getFrontendOpts().SkipFunctionBodies = + SkipFunctionBodies == SkipFunctionBodiesScope::PreambleAndMainFile; + + if (ModuleFormat) + CI->getHeaderSearchOpts().ModuleFormat = std::string(*ModuleFormat); + + // Create the AST unit. + std::unique_ptr AST; + AST.reset(new ASTUnit(false)); + AST->NumStoredDiagnosticsFromDriver = StoredDiagnostics.size(); + AST->StoredDiagnostics.swap(StoredDiagnostics); + ConfigureDiags(Diags, *AST, CaptureDiagnostics); + AST->DiagOpts = DiagOpts; + AST->Diagnostics = Diags; + AST->FileSystemOpts = CI->getFileSystemOpts(); + AST->CodeGenOpts = std::make_unique(CI->getCodeGenOpts()); + VFS = createVFSFromCompilerInvocation(*CI, *Diags, VFS); + AST->FileMgr = + llvm::makeIntrusiveRefCnt(AST->FileSystemOpts, VFS); + AST->StorePreamblesInMemory = StorePreamblesInMemory; + AST->PreambleStoragePath = PreambleStoragePath; + AST->ModCache = createCrossProcessModuleCache(); + AST->OnlyLocalDecls = OnlyLocalDecls; + AST->CaptureDiagnostics = CaptureDiagnostics; + AST->TUKind = TUKind; + AST->ShouldCacheCodeCompletionResults = CacheCodeCompletionResults; + AST->IncludeBriefCommentsInCodeCompletion = + IncludeBriefCommentsInCodeCompletion; + AST->UserFilesAreVolatile = UserFilesAreVolatile; + AST->Invocation = CI; + AST->SkipFunctionBodies = SkipFunctionBodies; + if (ForSerialization) + AST->WriterData.reset(new ASTWriterData(*AST->ModCache, *AST->CodeGenOpts)); + // Zero out now to ease cleanup during crash recovery. + CI = nullptr; + Diags = nullptr; + + // Recover resources if we crash before exiting this method. + llvm::CrashRecoveryContextCleanupRegistrar ASTUnitCleanup(AST.get()); + + if (AST->LoadFromCompilerInvocation(std::move(PCHContainerOps), + PrecompilePreambleAfterNParses, VFS)) { + // Some error occurred, if caller wants to examine diagnostics, pass it the + // ASTUnit. + if (ErrAST) { + AST->StoredDiagnostics.swap(AST->FailedParseDiagnostics); + ErrAST->swap(AST); + } + return nullptr; + } + + return AST; +} + bool ASTUnit::Reparse(std::shared_ptr PCHContainerOps, ArrayRef RemappedFiles, IntrusiveRefCntPtr VFS) { @@ -2223,6 +2406,64 @@ bool ASTUnit::serialize(raw_ostream &OS) { return serializeUnit(Writer, Buffer, getSema(), OS); } +void ASTUnit::TranslateStoredDiagnostics( + FileManager &FileMgr, SourceManager &SrcMgr, + const SmallVectorImpl &Diags, + SmallVectorImpl &Out) { + // Map the standalone diagnostic into the new source manager. We also need to + // remap all the locations to the new view. This includes the diag location, + // any associated source ranges, and the source ranges of associated fix-its. + // FIXME: There should be a cleaner way to do this. + SmallVector Result; + Result.reserve(Diags.size()); + + for (const auto &SD : Diags) { + // Rebuild the StoredDiagnostic. + if (SD.Filename.empty()) + continue; + auto FE = FileMgr.getOptionalFileRef(SD.Filename); + if (!FE) + continue; + SourceLocation FileLoc; + auto ItFileID = PreambleSrcLocCache.find(SD.Filename); + if (ItFileID == PreambleSrcLocCache.end()) { + FileID FID = SrcMgr.translateFile(*FE); + FileLoc = SrcMgr.getLocForStartOfFile(FID); + PreambleSrcLocCache[SD.Filename] = FileLoc; + } else { + FileLoc = ItFileID->getValue(); + } + + if (FileLoc.isInvalid()) + continue; + SourceLocation L = FileLoc.getLocWithOffset(SD.LocOffset); + FullSourceLoc Loc(L, SrcMgr); + + SmallVector Ranges; + Ranges.reserve(SD.Ranges.size()); + for (const auto &Range : SD.Ranges) { + SourceLocation BL = FileLoc.getLocWithOffset(Range.first); + SourceLocation EL = FileLoc.getLocWithOffset(Range.second); + Ranges.push_back(CharSourceRange::getCharRange(BL, EL)); + } + + SmallVector FixIts; + FixIts.reserve(SD.FixIts.size()); + for (const auto &FixIt : SD.FixIts) { + FixIts.push_back(FixItHint()); + FixItHint &FH = FixIts.back(); + FH.CodeToInsert = FixIt.CodeToInsert; + SourceLocation BL = FileLoc.getLocWithOffset(FixIt.RemoveRange.first); + SourceLocation EL = FileLoc.getLocWithOffset(FixIt.RemoveRange.second); + FH.RemoveRange = CharSourceRange::getCharRange(BL, EL); + } + + Result.push_back( + StoredDiagnostic(SD.Level, SD.ID, SD.Message, Loc, Ranges, FixIts)); + } + Result.swap(Out); +} + void ASTUnit::addFileLevelDecl(Decl *D) { assert(D); diff --git a/clang/lib/Frontend/CMakeLists.txt b/clang/lib/Frontend/CMakeLists.txt index 634f239933605..dac9e0d26f393 100644 --- a/clang/lib/Frontend/CMakeLists.txt +++ b/clang/lib/Frontend/CMakeLists.txt @@ -17,6 +17,7 @@ add_clang_library(clangFrontend ChainedIncludesSource.cpp CompilerInstance.cpp CompilerInvocation.cpp + CreateInvocationFromCommandLine.cpp DependencyFile.cpp DependencyGraph.cpp DiagnosticRenderer.cpp @@ -35,7 +36,6 @@ add_clang_library(clangFrontend SARIFDiagnosticPrinter.cpp SerializedDiagnosticPrinter.cpp SerializedDiagnosticReader.cpp - StandaloneDiagnostic.cpp TestModuleFileExtension.cpp TextDiagnostic.cpp TextDiagnosticBuffer.cpp @@ -51,6 +51,7 @@ add_clang_library(clangFrontend clangAPINotes clangAST clangBasic + clangDriver clangOptions clangEdit clangLex diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 5f1c7afdc80a3..c7c29a91721c0 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -27,6 +27,7 @@ #include "clang/Basic/Version.h" #include "clang/Basic/XRayInstr.h" #include "clang/Config/config.h" +#include "clang/Driver/Driver.h" #include "clang/Frontend/CommandLineSourceLoc.h" #include "clang/Frontend/DependencyOutputOptions.h" #include "clang/Frontend/FrontendOptions.h" @@ -3272,6 +3273,13 @@ static bool ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, return Diags.getNumErrors() == NumErrorsBefore; } +std::string CompilerInvocation::GetResourcesPath(const char *Argv0, + void *MainAddr) { + std::string ClangExecutable = + llvm::sys::fs::getMainExecutable(Argv0, MainAddr); + return driver::Driver::GetResourcesPath(ClangExecutable); +} + static void GenerateHeaderSearchArgs(const HeaderSearchOptions &Opts, ArgumentConsumer Consumer) { const HeaderSearchOptions *HeaderSearchOpts = &Opts; diff --git a/clang/lib/Driver/CreateInvocationFromArgs.cpp b/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp similarity index 93% rename from clang/lib/Driver/CreateInvocationFromArgs.cpp rename to clang/lib/Frontend/CreateInvocationFromCommandLine.cpp index 516d61f1a1159..e54e83151ad1e 100644 --- a/clang/lib/Driver/CreateInvocationFromArgs.cpp +++ b/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp @@ -1,4 +1,4 @@ -//===--- CreateInvocationFromArgs.h - CompilerInvocation from Args --------===// +//===--- CreateInvocationFromCommandLine.cpp - CompilerInvocation from Args ==// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -10,9 +10,9 @@ // //===----------------------------------------------------------------------===// -#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Basic/DiagnosticFrontend.h" #include "clang/Basic/DiagnosticOptions.h" +#include "clang/Driver/Action.h" #include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" #include "clang/Driver/Tool.h" @@ -24,13 +24,12 @@ #include "llvm/Option/ArgList.h" #include "llvm/Support/VirtualFileSystem.h" #include "llvm/TargetParser/Host.h" - +using namespace clang; using namespace llvm::opt; -namespace clang { - std::unique_ptr -createInvocation(ArrayRef ArgList, CreateInvocationOptions Opts) { +clang::createInvocation(ArrayRef ArgList, + CreateInvocationOptions Opts) { assert(!ArgList.empty()); std::optional LocalDiagOpts; IntrusiveRefCntPtr Diags; @@ -115,5 +114,3 @@ createInvocation(ArrayRef ArgList, CreateInvocationOptions Opts) { return nullptr; return CI; } - -} // namespace clang diff --git a/clang/lib/Frontend/StandaloneDiagnostic.cpp b/clang/lib/Frontend/StandaloneDiagnostic.cpp deleted file mode 100644 index 4f19c91b7d266..0000000000000 --- a/clang/lib/Frontend/StandaloneDiagnostic.cpp +++ /dev/null @@ -1,117 +0,0 @@ -//===--- StandaloneDiagnostic.h - Serializable Diagnostic ------------- ---===// -// -// 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/Frontend/StandaloneDiagnostic.h" -#include "clang/Lex/Lexer.h" - -namespace clang { - -StandaloneDiagnostic::SourceOffsetRange::SourceOffsetRange( - CharSourceRange Range, const SourceManager &SrcMgr, - const LangOptions &LangOpts) { - const auto FileRange = Lexer::makeFileCharRange(Range, SrcMgr, LangOpts); - Begin = SrcMgr.getFileOffset(FileRange.getBegin()); - End = SrcMgr.getFileOffset(FileRange.getEnd()); -} - -StandaloneDiagnostic::StandaloneFixIt::StandaloneFixIt( - const SourceManager &SrcMgr, const LangOptions &LangOpts, - const FixItHint &FixIt) - : RemoveRange(FixIt.RemoveRange, SrcMgr, LangOpts), - InsertFromRange(FixIt.InsertFromRange, SrcMgr, LangOpts), - CodeToInsert(FixIt.CodeToInsert), - BeforePreviousInsertions(FixIt.BeforePreviousInsertions) {} - -StandaloneDiagnostic::StandaloneDiagnostic(const LangOptions &LangOpts, - const StoredDiagnostic &InDiag) - : Level(InDiag.getLevel()), ID(InDiag.getID()), - Message(InDiag.getMessage()) { - const FullSourceLoc &FullLoc = InDiag.getLocation(); - // This is not an invalid diagnostic; invalid SourceLocations are used to - // represent diagnostics without a specific SourceLocation. - if (FullLoc.isInvalid()) - return; - - const auto &SrcMgr = FullLoc.getManager(); - FileKind = SrcMgr.getFileCharacteristic(static_cast(FullLoc)); - const auto FileLoc = SrcMgr.getFileLoc(static_cast(FullLoc)); - FileOffset = SrcMgr.getFileOffset(FileLoc); - Filename = SrcMgr.getFilename(FileLoc); - assert(!Filename.empty() && "diagnostic with location has no source file?"); - - Ranges.reserve(InDiag.getRanges().size()); - for (const auto &Range : InDiag.getRanges()) - Ranges.emplace_back(Range, SrcMgr, LangOpts); - - FixIts.reserve(InDiag.getFixIts().size()); - for (const auto &FixIt : InDiag.getFixIts()) - FixIts.emplace_back(SrcMgr, LangOpts, FixIt); -} - -StoredDiagnostic -translateStandaloneDiag(FileManager &FileMgr, SourceManager &SrcMgr, - const StandaloneDiagnostic &StandaloneDiag, - llvm::StringMap &SrcLocCache) { - const auto FileRef = FileMgr.getOptionalFileRef(StandaloneDiag.Filename); - if (!FileRef) - return StoredDiagnostic(StandaloneDiag.Level, StandaloneDiag.ID, - StandaloneDiag.Message); - - // Try to get FileLoc from cache first - SourceLocation FileLoc; - auto It = SrcLocCache.find(StandaloneDiag.Filename); - if (It != SrcLocCache.end()) { - FileLoc = It->getValue(); - } - - // Cache miss - compute and cache the location - if (FileLoc.isInvalid()) { - const auto FileID = - SrcMgr.getOrCreateFileID(*FileRef, StandaloneDiag.FileKind); - FileLoc = SrcMgr.getLocForStartOfFile(FileID); - - if (FileLoc.isInvalid()) - return StoredDiagnostic(StandaloneDiag.Level, StandaloneDiag.ID, - StandaloneDiag.Message); - - SrcLocCache[StandaloneDiag.Filename] = FileLoc; - } - - const auto DiagLoc = FileLoc.getLocWithOffset(StandaloneDiag.FileOffset); - const FullSourceLoc Loc(DiagLoc, SrcMgr); - - auto ConvertOffsetRange = - [&](const StandaloneDiagnostic::SourceOffsetRange &Range) { - return CharSourceRange( - SourceRange(FileLoc.getLocWithOffset(Range.Begin), - FileLoc.getLocWithOffset(Range.End)), - /*IsTokenRange*/ false); - }; - - SmallVector TranslatedRanges; - TranslatedRanges.reserve(StandaloneDiag.Ranges.size()); - transform(StandaloneDiag.Ranges, std::back_inserter(TranslatedRanges), - ConvertOffsetRange); - - SmallVector TranslatedFixIts; - TranslatedFixIts.reserve(StandaloneDiag.FixIts.size()); - for (const auto &FixIt : StandaloneDiag.FixIts) { - FixItHint TranslatedFixIt; - TranslatedFixIt.CodeToInsert = FixIt.CodeToInsert; - TranslatedFixIt.RemoveRange = ConvertOffsetRange(FixIt.RemoveRange); - TranslatedFixIt.InsertFromRange = ConvertOffsetRange(FixIt.InsertFromRange); - TranslatedFixIt.BeforePreviousInsertions = FixIt.BeforePreviousInsertions; - TranslatedFixIts.push_back(std::move(TranslatedFixIt)); - } - - return StoredDiagnostic(StandaloneDiag.Level, StandaloneDiag.ID, - StandaloneDiag.Message, Loc, TranslatedRanges, - TranslatedFixIts); -} - -} // namespace clang diff --git a/clang/lib/Interpreter/CMakeLists.txt b/clang/lib/Interpreter/CMakeLists.txt index 9a597146b2fc4..37faa0302caaa 100644 --- a/clang/lib/Interpreter/CMakeLists.txt +++ b/clang/lib/Interpreter/CMakeLists.txt @@ -46,7 +46,6 @@ add_clang_library(clangInterpreter clangFrontend clangFrontendTool clangLex - clangOptions clangParse clangSema clangSerialization diff --git a/clang/lib/Interpreter/Interpreter.cpp b/clang/lib/Interpreter/Interpreter.cpp index 6cbc5e9910bcc..7764fa7dc92b9 100644 --- a/clang/lib/Interpreter/Interpreter.cpp +++ b/clang/lib/Interpreter/Interpreter.cpp @@ -42,7 +42,6 @@ #include "clang/Interpreter/Interpreter.h" #include "clang/Interpreter/Value.h" #include "clang/Lex/PreprocessorOptions.h" -#include "clang/Options/OptionUtils.h" #include "clang/Options/Options.h" #include "clang/Sema/Lookup.h" #include "clang/Serialization/ObjectFilePCHContainerReader.h" @@ -106,7 +105,7 @@ CreateCI(const llvm::opt::ArgStringList &Argv) { if (Clang->getHeaderSearchOpts().UseBuiltinIncludes && Clang->getHeaderSearchOpts().ResourceDir.empty()) Clang->getHeaderSearchOpts().ResourceDir = - GetResourcesPath(Argv[0], nullptr); + CompilerInvocation::GetResourcesPath(Argv[0], nullptr); Clang->createVirtualFileSystem(); diff --git a/clang/lib/Options/OptionUtils.cpp b/clang/lib/Options/OptionUtils.cpp index e5aefa012f679..fcafd3c83c6b3 100644 --- a/clang/lib/Options/OptionUtils.cpp +++ b/clang/lib/Options/OptionUtils.cpp @@ -9,12 +9,7 @@ #include "clang/Options/OptionUtils.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/DiagnosticDriver.h" -#include "clang/Basic/Version.h" -#include "clang/Config/config.h" -#include "clang/Options/Options.h" #include "llvm/Option/ArgList.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/Path.h" using namespace clang; using namespace llvm::opt; @@ -36,211 +31,17 @@ IntTy getLastArgIntValueImpl(const ArgList &Args, OptSpecifier Id, } } // namespace -int clang::getLastArgIntValue(const ArgList &Args, OptSpecifier Id, int Default, - DiagnosticsEngine *Diags, unsigned Base) { +namespace clang { + +int getLastArgIntValue(const ArgList &Args, OptSpecifier Id, int Default, + DiagnosticsEngine *Diags, unsigned Base) { return getLastArgIntValueImpl(Args, Id, Default, Diags, Base); } -uint64_t clang::getLastArgUInt64Value(const ArgList &Args, OptSpecifier Id, - uint64_t Default, - DiagnosticsEngine *Diags, unsigned Base) { +uint64_t getLastArgUInt64Value(const ArgList &Args, OptSpecifier Id, + uint64_t Default, DiagnosticsEngine *Diags, + unsigned Base) { return getLastArgIntValueImpl(Args, Id, Default, Diags, Base); } -StringRef clang::parseMPreferVectorWidthOption(clang::DiagnosticsEngine &Diags, - const llvm::opt::ArgList &Args) { - const Arg *A = Args.getLastArg(options::OPT_mprefer_vector_width_EQ); - if (!A) - return ""; - - StringRef Value = A->getValue(); - unsigned Width LLVM_ATTRIBUTE_UNINITIALIZED; - - // Only "none" and Integer values are accepted by - // -mprefer-vector-width=. - if (Value != "none" && Value.getAsInteger(10, Width)) { - Diags.Report(clang::diag::err_drv_invalid_value) - << A->getOption().getName() << Value; - return ""; - } - - return Value; -} - -// This is a helper function for validating the optional refinement step -// parameter in reciprocal argument strings. Return false if there is an error -// parsing the refinement step. Otherwise, return true and set the Position -// of the refinement step in the input string. -static bool getRefinementStep(StringRef In, clang::DiagnosticsEngine &Diags, - const Arg &A, size_t &Position) { - const char RefinementStepToken = ':'; - Position = In.find(RefinementStepToken); - if (Position != StringRef::npos) { - StringRef Option = A.getOption().getName(); - StringRef RefStep = In.substr(Position + 1); - // Allow exactly one numeric character for the additional refinement - // step parameter. This is reasonable for all currently-supported - // operations and architectures because we would expect that a larger value - // of refinement steps would cause the estimate "optimization" to - // under-perform the native operation. Also, if the estimate does not - // converge quickly, it probably will not ever converge, so further - // refinement steps will not produce a better answer. - if (RefStep.size() != 1) { - Diags.Report(diag::err_drv_invalid_value) << Option << RefStep; - return false; - } - char RefStepChar = RefStep[0]; - if (RefStepChar < '0' || RefStepChar > '9') { - Diags.Report(diag::err_drv_invalid_value) << Option << RefStep; - return false; - } - } - return true; -} - -StringRef clang::parseMRecipOption(clang::DiagnosticsEngine &Diags, - const ArgList &Args) { - StringRef DisabledPrefixIn = "!"; - StringRef DisabledPrefixOut = "!"; - StringRef EnabledPrefixOut = ""; - StringRef Out = ""; - - const Arg *A = Args.getLastArg(options::OPT_mrecip, options::OPT_mrecip_EQ); - if (!A) - return ""; - - const unsigned NumOptions = A->getNumValues(); - if (NumOptions == 0) { - // No option is the same as "all". - return "all"; - } - - // Pass through "all", "none", or "default" with an optional refinement step. - if (NumOptions == 1) { - StringRef Val = A->getValue(0); - size_t RefStepLoc; - if (!getRefinementStep(Val, Diags, *A, RefStepLoc)) - return ""; - StringRef ValBase = Val.slice(0, RefStepLoc); - if (ValBase == "all" || ValBase == "none" || ValBase == "default") { - return Val; - } - } - - // Each reciprocal type may be enabled or disabled individually. - // Check each input value for validity, concatenate them all back together, - // and pass through. - - llvm::StringMap OptionStrings; - OptionStrings.insert(std::make_pair("divd", false)); - OptionStrings.insert(std::make_pair("divf", false)); - OptionStrings.insert(std::make_pair("divh", false)); - OptionStrings.insert(std::make_pair("vec-divd", false)); - OptionStrings.insert(std::make_pair("vec-divf", false)); - OptionStrings.insert(std::make_pair("vec-divh", false)); - OptionStrings.insert(std::make_pair("sqrtd", false)); - OptionStrings.insert(std::make_pair("sqrtf", false)); - OptionStrings.insert(std::make_pair("sqrth", false)); - OptionStrings.insert(std::make_pair("vec-sqrtd", false)); - OptionStrings.insert(std::make_pair("vec-sqrtf", false)); - OptionStrings.insert(std::make_pair("vec-sqrth", false)); - - for (unsigned i = 0; i != NumOptions; ++i) { - StringRef Val = A->getValue(i); - - bool IsDisabled = Val.starts_with(DisabledPrefixIn); - // Ignore the disablement token for string matching. - if (IsDisabled) - Val = Val.substr(1); - - size_t RefStep; - if (!getRefinementStep(Val, Diags, *A, RefStep)) - return ""; - - StringRef ValBase = Val.slice(0, RefStep); - llvm::StringMap::iterator OptionIter = OptionStrings.find(ValBase); - if (OptionIter == OptionStrings.end()) { - // Try again specifying float suffix. - OptionIter = OptionStrings.find(ValBase.str() + 'f'); - if (OptionIter == OptionStrings.end()) { - // The input name did not match any known option string. - Diags.Report(diag::err_drv_unknown_argument) << Val; - return ""; - } - // The option was specified without a half or float or double suffix. - // Make sure that the double or half entry was not already specified. - // The float entry will be checked below. - if (OptionStrings[ValBase.str() + 'd'] || - OptionStrings[ValBase.str() + 'h']) { - Diags.Report(diag::err_drv_invalid_value) - << A->getOption().getName() << Val; - return ""; - } - } - - if (OptionIter->second == true) { - // Duplicate option specified. - Diags.Report(diag::err_drv_invalid_value) - << A->getOption().getName() << Val; - return ""; - } - - // Mark the matched option as found. Do not allow duplicate specifiers. - OptionIter->second = true; - - // If the precision was not specified, also mark the double and half entry - // as found. - if (ValBase.back() != 'f' && ValBase.back() != 'd' && - ValBase.back() != 'h') { - OptionStrings[ValBase.str() + 'd'] = true; - OptionStrings[ValBase.str() + 'h'] = true; - } - - // Build the output string. - StringRef Prefix = IsDisabled ? DisabledPrefixOut : EnabledPrefixOut; - Out = Args.MakeArgString(Out + Prefix + Val); - if (i != NumOptions - 1) - Out = Args.MakeArgString(Out + ","); - } - - return Out; -} - -std::string clang::GetResourcesPath(StringRef BinaryPath) { - // Since the resource directory is embedded in the module hash, it's important - // that all places that need it call this function, so that they get the - // exact same string ("a/../b/" and "b/" get different hashes, for example). - - // Dir is bin/ or lib/, depending on where BinaryPath is. - StringRef Dir = llvm::sys::path::parent_path(BinaryPath); - SmallString<128> P(Dir); - - StringRef ConfiguredResourceDir(CLANG_RESOURCE_DIR); - if (!ConfiguredResourceDir.empty()) { - // FIXME: We should fix the behavior of llvm::sys::path::append so we don't - // need to check for absolute paths here. - if (llvm::sys::path::is_absolute(ConfiguredResourceDir)) - P = ConfiguredResourceDir; - else - llvm::sys::path::append(P, ConfiguredResourceDir); - } else { - // On Windows, libclang.dll is in bin/. - // On non-Windows, libclang.so/.dylib is in lib/. - // With a static-library build of libclang, LibClangPath will contain the - // path of the embedding binary, which for LLVM binaries will be in bin/. - // ../lib gets us to lib/ in both cases. - P = llvm::sys::path::parent_path(Dir); - // This search path is also created in the COFF driver of lld, so any - // changes here also needs to happen in lld/COFF/Driver.cpp - llvm::sys::path::append(P, CLANG_INSTALL_LIBDIR_BASENAME, "clang", - CLANG_VERSION_MAJOR_STRING); - } - - return std::string(P); -} - -std::string clang::GetResourcesPath(const char *Argv0, void *MainAddr) { - const std::string ClangExecutable = - llvm::sys::fs::getMainExecutable(Argv0, MainAddr); - return GetResourcesPath(ClangExecutable); -} +} // namespace clang diff --git a/clang/lib/Tooling/Tooling.cpp b/clang/lib/Tooling/Tooling.cpp index 1d55f615de8a9..9bae12454d2dc 100644 --- a/clang/lib/Tooling/Tooling.cpp +++ b/clang/lib/Tooling/Tooling.cpp @@ -31,7 +31,6 @@ #include "clang/Frontend/TextDiagnosticPrinter.h" #include "clang/Lex/HeaderSearchOptions.h" #include "clang/Lex/PreprocessorOptions.h" -#include "clang/Options/OptionUtils.h" #include "clang/Options/Options.h" #include "clang/Tooling/ArgumentsAdjusters.h" #include "clang/Tooling/CompilationDatabase.h" @@ -511,7 +510,8 @@ static void injectResourceDir(CommandLineArguments &Args, const char *Argv0, // If there's no override in place add our resource dir. Args = getInsertArgumentAdjuster( - ("-resource-dir=" + GetResourcesPath(Argv0, MainAddr)).c_str())(Args, ""); + ("-resource-dir=" + CompilerInvocation::GetResourcesPath(Argv0, MainAddr)) + .c_str())(Args, ""); } int ClangTool::run(ToolAction *Action) { diff --git a/clang/tools/c-index-test/CMakeLists.txt b/clang/tools/c-index-test/CMakeLists.txt index 41e80e66ffa7a..24e7c9692ca56 100644 --- a/clang/tools/c-index-test/CMakeLists.txt +++ b/clang/tools/c-index-test/CMakeLists.txt @@ -27,7 +27,6 @@ else() libclang clangAST clangBasic - clangDriver clangFrontend clangIndex clangSerialization diff --git a/clang/tools/c-index-test/core_main.cpp b/clang/tools/c-index-test/core_main.cpp index c67479fd130ca..5a3086a7fc08f 100644 --- a/clang/tools/c-index-test/core_main.cpp +++ b/clang/tools/c-index-test/core_main.cpp @@ -8,7 +8,6 @@ #include "clang/AST/Mangle.h" #include "clang/Basic/LangOptions.h" -#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/ASTUnit.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/CompilerInvocation.h" diff --git a/clang/tools/diagtool/CMakeLists.txt b/clang/tools/diagtool/CMakeLists.txt index 09b2a81790f87..b49619c075c73 100644 --- a/clang/tools/diagtool/CMakeLists.txt +++ b/clang/tools/diagtool/CMakeLists.txt @@ -15,6 +15,5 @@ add_clang_tool(diagtool clang_target_link_libraries(diagtool PRIVATE clangBasic - clangDriver clangFrontend ) diff --git a/clang/tools/diagtool/ShowEnabledWarnings.cpp b/clang/tools/diagtool/ShowEnabledWarnings.cpp index 5b25e656dafa4..bea0288c09358 100644 --- a/clang/tools/diagtool/ShowEnabledWarnings.cpp +++ b/clang/tools/diagtool/ShowEnabledWarnings.cpp @@ -9,7 +9,6 @@ #include "DiagTool.h" #include "DiagnosticNames.h" #include "clang/Basic/LLVM.h" -#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/TextDiagnosticBuffer.h" #include "clang/Frontend/TextDiagnosticPrinter.h" diff --git a/clang/tools/driver/cc1_main.cpp b/clang/tools/driver/cc1_main.cpp index cc757039cafd0..300d59df1bf7b 100644 --- a/clang/tools/driver/cc1_main.cpp +++ b/clang/tools/driver/cc1_main.cpp @@ -17,7 +17,6 @@ #include "clang/Basic/TargetOptions.h" #include "clang/CodeGen/ObjectFilePCHContainerWriter.h" #include "clang/Config/config.h" -#include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/CompilerInvocation.h" @@ -270,7 +269,7 @@ int cc1_main(ArrayRef Argv, const char *Argv0, void *MainAddr) { if (Clang->getHeaderSearchOpts().UseBuiltinIncludes && Clang->getHeaderSearchOpts().ResourceDir.empty()) Clang->getHeaderSearchOpts().ResourceDir = - GetResourcesPath(Argv0, MainAddr); + CompilerInvocation::GetResourcesPath(Argv0, MainAddr); /// Create the actual file system. Clang->createVirtualFileSystem(llvm::vfs::getRealFileSystem(), DiagsBuffer); diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp index 32e84248c1b27..f4d6fa72a1dfe 100644 --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -38,7 +38,6 @@ #include "clang/Basic/Stack.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/Version.h" -#include "clang/Driver/CreateASTUnitFromArgs.h" #include "clang/Frontend/ASTUnit.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Index/CommentToXML.h" @@ -4362,7 +4361,7 @@ clang_parseTranslationUnit_Impl(CXIndex CIdx, const char *source_filename, LibclangInvocationReporter InvocationReporter( *CXXIdx, LibclangInvocationReporter::OperationKind::ParseOperation, options, llvm::ArrayRef(*Args), /*InvocationArgs=*/{}, unsaved_files); - std::unique_ptr Unit = CreateASTUnitFromCommandLine( + std::unique_ptr Unit = ASTUnit::LoadFromCommandLine( Args->data(), Args->data() + Args->size(), CXXIdx->getPCHContainerOperations(), DiagOpts, Diags, CXXIdx->getClangResourcesPath(), CXXIdx->getStorePreamblesInMemory(), diff --git a/clang/tools/libclang/CIndexer.cpp b/clang/tools/libclang/CIndexer.cpp index 853a936b43e37..11d9312b64849 100644 --- a/clang/tools/libclang/CIndexer.cpp +++ b/clang/tools/libclang/CIndexer.cpp @@ -16,7 +16,6 @@ #include "clang/Basic/Version.h" #include "clang/Config/config.h" #include "clang/Driver/Driver.h" -#include "clang/Options/OptionUtils.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/FileSystem.h" @@ -138,7 +137,7 @@ const std::string &CIndexer::getClangResourcesPath() { #endif // Cache our result. - ResourcesPath = GetResourcesPath(LibClangPath); + ResourcesPath = driver::Driver::GetResourcesPath(LibClangPath); return ResourcesPath; } diff --git a/clang/tools/libclang/CMakeLists.txt b/clang/tools/libclang/CMakeLists.txt index b0105f5a5f79f..e0ff7605b68b8 100644 --- a/clang/tools/libclang/CMakeLists.txt +++ b/clang/tools/libclang/CMakeLists.txt @@ -65,7 +65,6 @@ set(LIBS clangFrontend clangIndex clangLex - clangOptions clangRewrite clangSema clangSerialization diff --git a/clang/tools/libclang/Indexing.cpp b/clang/tools/libclang/Indexing.cpp index 75323d70afcfe..c142f142d5071 100644 --- a/clang/tools/libclang/Indexing.cpp +++ b/clang/tools/libclang/Indexing.cpp @@ -15,7 +15,6 @@ #include "CXString.h" #include "CXTranslationUnit.h" #include "clang/AST/ASTConsumer.h" -#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/ASTUnit.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/CompilerInvocation.h" diff --git a/clang/unittests/Driver/DXCModeTest.cpp b/clang/unittests/Driver/DXCModeTest.cpp index 130da620b40b5..e0454f190b35a 100644 --- a/clang/unittests/Driver/DXCModeTest.cpp +++ b/clang/unittests/Driver/DXCModeTest.cpp @@ -15,7 +15,6 @@ #include "clang/Basic/LLVM.h" #include "clang/Basic/TargetOptions.h" #include "clang/Driver/Compilation.h" -#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Driver/Driver.h" #include "clang/Driver/ToolChain.h" #include "clang/Frontend/CompilerInstance.h" diff --git a/clang/unittests/Driver/ToolChainTest.cpp b/clang/unittests/Driver/ToolChainTest.cpp index 8f533790ec501..afa17ff219be2 100644 --- a/clang/unittests/Driver/ToolChainTest.cpp +++ b/clang/unittests/Driver/ToolChainTest.cpp @@ -17,7 +17,6 @@ #include "clang/Basic/TargetInfo.h" #include "clang/Basic/TargetOptions.h" #include "clang/Driver/Compilation.h" -#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Driver/Driver.h" #include "clang/Frontend/CompilerInstance.h" #include "llvm/ADT/ArrayRef.h" diff --git a/clang/unittests/Frontend/ASTUnitTest.cpp b/clang/unittests/Frontend/ASTUnitTest.cpp index bf9e4e184b5db..dfdbe90e72f1f 100644 --- a/clang/unittests/Frontend/ASTUnitTest.cpp +++ b/clang/unittests/Frontend/ASTUnitTest.cpp @@ -9,8 +9,6 @@ #include #include "clang/Basic/FileManager.h" -#include "clang/Driver/CreateASTUnitFromArgs.h" -#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/ASTUnit.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/CompilerInvocation.h" @@ -175,7 +173,7 @@ TEST_F(ASTUnitTest, LoadFromCommandLineEarlyError) { auto PCHContainerOps = std::make_shared(); std::unique_ptr ErrUnit; - std::unique_ptr AST = CreateASTUnitFromCommandLine( + std::unique_ptr AST = ASTUnit::LoadFromCommandLine( &Args[0], &Args[4], PCHContainerOps, DiagOpts, Diags, "", false, "", false, CaptureDiagsKind::All, {}, true, 0, TU_Complete, false, false, false, SkipFunctionBodiesScope::None, false, true, false, false, @@ -203,7 +201,7 @@ TEST_F(ASTUnitTest, LoadFromCommandLineWorkingDirectory) { auto PCHContainerOps = std::make_shared(); std::unique_ptr ErrUnit; - std::unique_ptr AST = CreateASTUnitFromCommandLine( + std::unique_ptr AST = ASTUnit::LoadFromCommandLine( &Args[0], &Args[4], PCHContainerOps, DiagOpts, Diags, "", false, "", false, CaptureDiagsKind::All, {}, true, 0, TU_Complete, false, false, false, SkipFunctionBodiesScope::None, false, true, false, false, diff --git a/clang/unittests/Frontend/CompilerInstanceTest.cpp b/clang/unittests/Frontend/CompilerInstanceTest.cpp index 39d35b48f394a..cd3fefa1ea994 100644 --- a/clang/unittests/Frontend/CompilerInstanceTest.cpp +++ b/clang/unittests/Frontend/CompilerInstanceTest.cpp @@ -8,7 +8,6 @@ #include "clang/Frontend/CompilerInstance.h" #include "clang/Basic/FileManager.h" -#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/CompilerInvocation.h" #include "clang/Frontend/FrontendActions.h" #include "clang/Frontend/TextDiagnosticPrinter.h" diff --git a/clang/unittests/Frontend/UtilsTest.cpp b/clang/unittests/Frontend/UtilsTest.cpp index a82733d57714a..fc411e4af705f 100644 --- a/clang/unittests/Frontend/UtilsTest.cpp +++ b/clang/unittests/Frontend/UtilsTest.cpp @@ -9,7 +9,6 @@ #include "clang/Frontend/Utils.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/TargetOptions.h" -#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/CompilerInvocation.h" #include "clang/Lex/PreprocessorOptions.h" diff --git a/clang/unittests/Sema/CMakeLists.txt b/clang/unittests/Sema/CMakeLists.txt index 188f6135a60ac..b61ed8c457635 100644 --- a/clang/unittests/Sema/CMakeLists.txt +++ b/clang/unittests/Sema/CMakeLists.txt @@ -13,7 +13,6 @@ add_distinct_clang_unittest(SemaTests clangAST clangASTMatchers clangBasic - clangDriver clangFrontend clangParse clangSema diff --git a/clang/unittests/Sema/SemaNoloadLookupTest.cpp b/clang/unittests/Sema/SemaNoloadLookupTest.cpp index 3944269eff502..e565372698e5e 100644 --- a/clang/unittests/Sema/SemaNoloadLookupTest.cpp +++ b/clang/unittests/Sema/SemaNoloadLookupTest.cpp @@ -10,7 +10,6 @@ #include "clang/AST/DeclarationName.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/ASTMatchers/ASTMatchers.h" -#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendAction.h" #include "clang/Frontend/FrontendActions.h" diff --git a/clang/unittests/Serialization/ForceCheckFileInputTest.cpp b/clang/unittests/Serialization/ForceCheckFileInputTest.cpp index b76dcfec96063..edf33ae04230b 100644 --- a/clang/unittests/Serialization/ForceCheckFileInputTest.cpp +++ b/clang/unittests/Serialization/ForceCheckFileInputTest.cpp @@ -9,7 +9,6 @@ #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/ASTMatchers/ASTMatchers.h" #include "clang/Basic/FileManager.h" -#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/CompilerInvocation.h" #include "clang/Frontend/FrontendActions.h" diff --git a/clang/unittests/Serialization/LoadSpecLazilyTest.cpp b/clang/unittests/Serialization/LoadSpecLazilyTest.cpp index f55925aeae1f2..d7b55491fddac 100644 --- a/clang/unittests/Serialization/LoadSpecLazilyTest.cpp +++ b/clang/unittests/Serialization/LoadSpecLazilyTest.cpp @@ -6,7 +6,6 @@ // //===----------------------------------------------------------------------===// -#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendAction.h" #include "clang/Frontend/FrontendActions.h" diff --git a/clang/unittests/Serialization/ModuleCacheTest.cpp b/clang/unittests/Serialization/ModuleCacheTest.cpp index df26e54588b9e..e9b8da3dba6af 100644 --- a/clang/unittests/Serialization/ModuleCacheTest.cpp +++ b/clang/unittests/Serialization/ModuleCacheTest.cpp @@ -7,7 +7,6 @@ //===----------------------------------------------------------------------===// #include "clang/Basic/FileManager.h" -#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/CompilerInvocation.h" #include "clang/Frontend/FrontendActions.h" diff --git a/clang/unittests/Serialization/NoCommentsTest.cpp b/clang/unittests/Serialization/NoCommentsTest.cpp index 444a082bba907..01bb6999a7c90 100644 --- a/clang/unittests/Serialization/NoCommentsTest.cpp +++ b/clang/unittests/Serialization/NoCommentsTest.cpp @@ -9,7 +9,6 @@ #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/ASTMatchers/ASTMatchers.h" #include "clang/Basic/FileManager.h" -#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/CompilerInvocation.h" #include "clang/Frontend/FrontendActions.h" diff --git a/clang/unittests/Serialization/PreambleInNamedModulesTest.cpp b/clang/unittests/Serialization/PreambleInNamedModulesTest.cpp index b826f20ce4d70..55ee72875ead2 100644 --- a/clang/unittests/Serialization/PreambleInNamedModulesTest.cpp +++ b/clang/unittests/Serialization/PreambleInNamedModulesTest.cpp @@ -6,7 +6,6 @@ // //===----------------------------------------------------------------------===// -#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/CompilerInvocation.h" #include "clang/Frontend/FrontendActions.h" diff --git a/clang/unittests/Serialization/VarDeclConstantInitTest.cpp b/clang/unittests/Serialization/VarDeclConstantInitTest.cpp index 2be01def49809..743f851fc5fe1 100644 --- a/clang/unittests/Serialization/VarDeclConstantInitTest.cpp +++ b/clang/unittests/Serialization/VarDeclConstantInitTest.cpp @@ -9,7 +9,6 @@ #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/ASTMatchers/ASTMatchers.h" #include "clang/Basic/FileManager.h" -#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/CompilerInvocation.h" #include "clang/Frontend/FrontendActions.h" diff --git a/clang/unittests/Tooling/Syntax/TokensTest.cpp b/clang/unittests/Tooling/Syntax/TokensTest.cpp index 468ca5ddd2c75..47184cbf5d768 100644 --- a/clang/unittests/Tooling/Syntax/TokensTest.cpp +++ b/clang/unittests/Tooling/Syntax/TokensTest.cpp @@ -20,7 +20,6 @@ #include "clang/Basic/SourceManager.h" #include "clang/Basic/TokenKinds.def" #include "clang/Basic/TokenKinds.h" -#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendAction.h" #include "clang/Frontend/Utils.h" diff --git a/clang/unittests/Tooling/Syntax/TreeTestBase.cpp b/clang/unittests/Tooling/Syntax/TreeTestBase.cpp index dad75854240ef..b2be64fc08f3d 100644 --- a/clang/unittests/Tooling/Syntax/TreeTestBase.cpp +++ b/clang/unittests/Tooling/Syntax/TreeTestBase.cpp @@ -13,7 +13,6 @@ #include "TreeTestBase.h" #include "clang/AST/ASTConsumer.h" #include "clang/Basic/LLVM.h" -#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/CompilerInvocation.h" #include "clang/Frontend/FrontendAction.h" diff --git a/flang/lib/Frontend/CMakeLists.txt b/flang/lib/Frontend/CMakeLists.txt index fb74b3dcb280e..bb0b4a39cec9b 100644 --- a/flang/lib/Frontend/CMakeLists.txt +++ b/flang/lib/Frontend/CMakeLists.txt @@ -75,6 +75,7 @@ add_flang_library(flangFrontend CLANG_LIBS clangBasic + clangDriver clangOptions ) diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp index b6c4e6303cdac..0c32f3914e04b 100644 --- a/flang/lib/Frontend/CompilerInvocation.cpp +++ b/flang/lib/Frontend/CompilerInvocation.cpp @@ -325,9 +325,10 @@ static void parseCodeGenArgs(Fortran::frontend::CodeGenOptions &opts, for (auto *a : args.filtered(clang::options::OPT_fpass_plugin_EQ)) opts.LLVMPassPlugins.push_back(a->getValue()); - opts.Reciprocals = clang::parseMRecipOption(diags, args); + opts.Reciprocals = clang::driver::tools::parseMRecipOption(diags, args); - opts.PreferVectorWidth = clang::parseMPreferVectorWidthOption(diags, args); + opts.PreferVectorWidth = + clang::driver::tools::parseMPreferVectorWidthOption(diags, args); // -fembed-offload-object option for (auto *a : args.filtered(clang::options::OPT_fembed_offload_object_EQ)) diff --git a/lldb/source/Commands/CommandObjectTarget.cpp b/lldb/source/Commands/CommandObjectTarget.cpp index 7f880d223d6c3..30bca639060e6 100644 --- a/lldb/source/Commands/CommandObjectTarget.cpp +++ b/lldb/source/Commands/CommandObjectTarget.cpp @@ -60,7 +60,6 @@ #include "lldb/lldb-forward.h" #include "lldb/lldb-private-enumerations.h" -#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/CompilerInvocation.h" #include "clang/Frontend/FrontendActions.h" diff --git a/lldb/source/Plugins/ExpressionParser/Clang/CMakeLists.txt b/lldb/source/Plugins/ExpressionParser/Clang/CMakeLists.txt index 759a7c4dd14fb..01d588ff6a78b 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/CMakeLists.txt +++ b/lldb/source/Plugins/ExpressionParser/Clang/CMakeLists.txt @@ -51,10 +51,10 @@ add_lldb_library(lldbPluginExpressionParserClang CLANG_LIBS clangAST clangCodeGen + clangDriver clangEdit clangFrontend clangLex - clangOptions clangParse clangRewrite clangRewriteFrontend diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangHost.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangHost.cpp index 660a21e3c6a8d..6de851081598f 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangHost.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangHost.cpp @@ -10,7 +10,7 @@ #include "clang/Basic/Version.h" #include "clang/Config/config.h" -#include "clang/Options/OptionUtils.h" +#include "clang/Driver/Driver.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" @@ -53,7 +53,7 @@ static bool DefaultComputeClangResourceDirectory(FileSpec &lldb_shlib_spec, std::string raw_path = lldb_shlib_spec.GetPath(); llvm::StringRef parent_dir = llvm::sys::path::parent_path(raw_path); static const std::string clang_resource_path = - clang::GetResourcesPath("bin/lldb"); + clang::driver::Driver::GetResourcesPath("bin/lldb"); static const llvm::StringRef kResourceDirSuffixes[] = { // LLVM.org's build of LLDB uses the clang resource directory placed diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp index ce8dc50b84a31..e37c84efefdc9 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp @@ -10,7 +10,6 @@ #include "clang/Basic/DiagnosticFrontend.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/TargetInfo.h" -#include "clang/Driver/CreateInvocationFromArgs.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendActions.h" #include "clang/Frontend/TextDiagnosticPrinter.h" diff --git a/lldb/unittests/Expression/ClangParserTest.cpp b/lldb/unittests/Expression/ClangParserTest.cpp index c949026e87cd8..fab4487c73719 100644 --- a/lldb/unittests/Expression/ClangParserTest.cpp +++ b/lldb/unittests/Expression/ClangParserTest.cpp @@ -8,7 +8,7 @@ #include "clang/Basic/Version.h" #include "clang/Config/config.h" -#include "clang/Options/OptionUtils.h" +#include "clang/Driver/Driver.h" #include "Plugins/ExpressionParser/Clang/ClangHost.h" #include "TestingSupport/SubsystemRAII.h" @@ -43,7 +43,7 @@ TEST_F(ClangHostTest, ComputeClangResourceDirectory) { std::string path_to_liblldb = "C:\\foo\\bar\\lib\\"; #endif std::string path_to_clang_dir = - clang::GetResourcesPath(path_to_liblldb + "liblldb"); + clang::driver::Driver::GetResourcesPath(path_to_liblldb + "liblldb"); llvm::SmallString<256> path_to_clang_lib_dir_real; llvm::sys::fs::real_path(path_to_clang_dir, path_to_clang_lib_dir_real); From 72dd4f75d6c6f7964a6612599ff09895ffd8d7e6 Mon Sep 17 00:00:00 2001 From: LLVM GN Syncbot Date: Mon, 24 Nov 2025 20:10:02 +0000 Subject: [PATCH 07/50] [gn build] Port dea330b38d9c --- llvm/utils/gn/secondary/clang/lib/Driver/BUILD.gn | 2 -- llvm/utils/gn/secondary/clang/lib/Frontend/BUILD.gn | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/llvm/utils/gn/secondary/clang/lib/Driver/BUILD.gn b/llvm/utils/gn/secondary/clang/lib/Driver/BUILD.gn index 9b524e2ef7cd5..66dbf6152472a 100644 --- a/llvm/utils/gn/secondary/clang/lib/Driver/BUILD.gn +++ b/llvm/utils/gn/secondary/clang/lib/Driver/BUILD.gn @@ -29,8 +29,6 @@ static_library("Driver") { sources = [ "Action.cpp", "Compilation.cpp", - "CreateASTUnitFromArgs.cpp", - "CreateInvocationFromArgs.cpp", "Distro.cpp", "Driver.cpp", "Job.cpp", diff --git a/llvm/utils/gn/secondary/clang/lib/Frontend/BUILD.gn b/llvm/utils/gn/secondary/clang/lib/Frontend/BUILD.gn index cdf39d645bc52..4009cfc609f4a 100644 --- a/llvm/utils/gn/secondary/clang/lib/Frontend/BUILD.gn +++ b/llvm/utils/gn/secondary/clang/lib/Frontend/BUILD.gn @@ -28,6 +28,7 @@ static_library("Frontend") { "ChainedIncludesSource.cpp", "CompilerInstance.cpp", "CompilerInvocation.cpp", + "CreateInvocationFromCommandLine.cpp", "DependencyFile.cpp", "DependencyGraph.cpp", "DiagnosticRenderer.cpp", @@ -47,7 +48,6 @@ static_library("Frontend") { "SARIFDiagnosticPrinter.cpp", "SerializedDiagnosticPrinter.cpp", "SerializedDiagnosticReader.cpp", - "StandaloneDiagnostic.cpp", "TestModuleFileExtension.cpp", "TextDiagnostic.cpp", "TextDiagnosticBuffer.cpp", From 20929abb85633e4f17e5df21c9ac2fd80650f9d4 Mon Sep 17 00:00:00 2001 From: agozillon Date: Mon, 24 Nov 2025 21:20:29 +0100 Subject: [PATCH 08/50] [MLIR][OpenMP] Introduce overlapped record type map support (#119588) This PR introduces a new additional type of map lowering for record types that Clang currently supports, in which a user can map a top-level record type and then individual members with different mapping, effectively creating a sort of "overlapping" mapping that we attempt to cut around. This is currently most predominantly used in Fortran, when mapping descriptors and there data, we map the descriptor and its data with separate map modifiers and "cut around" the pointer data, so that wedo not overwrite it unless the runtime deems it a neccesary action based on its reference counting mechanism. However, it is a mechanism that will come in handy/trigger when a user explitily maps a record type (derived type or structure) and then explicitly maps a member with a different map type. These additions were predominantly in the OpenMPToLLVMIRTranslation.cpp file and phase, however, one Flang test that checks end-to-end IR compilation (as far as we care for now at least) was altered. 2/3 required PRs to enable declare target to mapping, should look at PR 3/3 to check for full green passes (this one will fail a number due to some dependencies). Co-authored-by: Raghu Maddhipatla raghu.maddhipatla@amd.com --- .../OpenMP/map-types-and-sizes.f90 | 143 +++++---- .../OpenMP/OpenMPToLLVMIRTranslation.cpp | 298 +++++++++++++----- .../omptarget-data-use-dev-ordering.mlir | 20 +- .../omptarget-declare-target-to-host.mlir | 34 ++ mlir/test/Target/LLVMIR/omptarget-nowait.mlir | 27 +- ...ptarget-overlapping-record-member-map.mlir | 65 ++++ ...rget-record-type-with-ptr-member-host.mlir | 105 +++--- .../fortran/dtype-member-overlap-map.f90 | 56 ++++ 8 files changed, 551 insertions(+), 197 deletions(-) create mode 100644 mlir/test/Target/LLVMIR/omptarget-declare-target-to-host.mlir create mode 100644 mlir/test/Target/LLVMIR/omptarget-overlapping-record-member-map.mlir create mode 100644 offload/test/offloading/fortran/dtype-member-overlap-map.f90 diff --git a/flang/test/Integration/OpenMP/map-types-and-sizes.f90 b/flang/test/Integration/OpenMP/map-types-and-sizes.f90 index 44a049f5ac510..8eb40c089e05c 100644 --- a/flang/test/Integration/OpenMP/map-types-and-sizes.f90 +++ b/flang/test/Integration/OpenMP/map-types-and-sizes.f90 @@ -33,8 +33,8 @@ subroutine mapType_array !$omp end target end subroutine mapType_array -!CHECK: @.offload_sizes{{.*}} = private unnamed_addr constant [4 x i64] [i64 0, i64 24, i64 8, i64 0] -!CHECK: @.offload_maptypes{{.*}} = private unnamed_addr constant [4 x i64] [i64 32, i64 281474976711169, i64 281474976711171, i64 281474976711187] +!CHECK: @.offload_sizes{{.*}} = private unnamed_addr constant [5 x i64] [i64 0, i64 0, i64 0, i64 8, i64 0] +!CHECK: @.offload_maptypes{{.*}} = private unnamed_addr constant [5 x i64] [i64 32, i64 281474976711173, i64 281474976711173, i64 281474976711171, i64 281474976711187] subroutine mapType_ptr integer, pointer :: a !$omp target @@ -73,8 +73,8 @@ subroutine map_ompx_hold !$omp end target data end subroutine -!CHECK: @.offload_sizes{{.*}} = private unnamed_addr constant [4 x i64] [i64 0, i64 24, i64 8, i64 0] -!CHECK: @.offload_maptypes{{.*}} = private unnamed_addr constant [4 x i64] [i64 32, i64 281474976711169, i64 281474976711171, i64 281474976711187] +!CHECK: @.offload_sizes{{.*}} = private unnamed_addr constant [5 x i64] [i64 0, i64 0, i64 0, i64 8, i64 0] +!CHECK: @.offload_maptypes{{.*}} = private unnamed_addr constant [5 x i64] [i64 32, i64 281474976711173, i64 281474976711173, i64 281474976711171, i64 281474976711187] subroutine mapType_allocatable integer, allocatable :: a allocate(a) @@ -84,8 +84,8 @@ subroutine mapType_allocatable deallocate(a) end subroutine mapType_allocatable -!CHECK: @.offload_sizes{{.*}} = private unnamed_addr constant [4 x i64] [i64 0, i64 24, i64 8, i64 0] -!CHECK: @.offload_maptypes{{.*}} = private unnamed_addr constant [4 x i64] [i64 32, i64 281474976710657, i64 281474976710659, i64 281474976710675] +!CHECK: @.offload_sizes{{.*}} = private unnamed_addr constant [5 x i64] [i64 0, i64 0, i64 0, i64 8, i64 0] +!CHECK: @.offload_maptypes{{.*}} = private unnamed_addr constant [5 x i64] [i64 32, i64 281474976710661, i64 281474976710661, i64 281474976710659, i64 281474976710675] subroutine mapType_ptr_explicit integer, pointer :: a !$omp target map(tofrom: a) @@ -93,8 +93,8 @@ subroutine mapType_ptr_explicit !$omp end target end subroutine mapType_ptr_explicit -!CHECK: @.offload_sizes{{.*}} = private unnamed_addr constant [4 x i64] [i64 0, i64 24, i64 8, i64 0] -!CHECK: @.offload_maptypes{{.*}} = private unnamed_addr constant [4 x i64] [i64 32, i64 281474976710657, i64 281474976710659, i64 281474976710675] +!CHECK: @.offload_sizes{{.*}} = private unnamed_addr constant [5 x i64] [i64 0, i64 0, i64 0, i64 8, i64 0] +!CHECK: @.offload_maptypes{{.*}} = private unnamed_addr constant [5 x i64] [i64 32, i64 281474976710661, i64 281474976710661, i64 281474976710659, i64 281474976710675] subroutine mapType_allocatable_explicit integer, allocatable :: a allocate(a) @@ -246,7 +246,7 @@ subroutine mapType_derived_explicit_nested_member_with_bounds end subroutine mapType_derived_explicit_nested_member_with_bounds !CHECK: @.offload_sizes{{.*}} = private unnamed_addr constant [4 x i64] [i64 0, i64 48, i64 8, i64 0] -!CHECK: @.offload_maptypes{{.*}} = private unnamed_addr constant [4 x i64] [i64 32, i64 281474976710657, i64 281474976710659, i64 281474976710675] +!CHECK: @.offload_maptypes{{.*}} = private unnamed_addr constant [4 x i64] [i64 32, i64 281474976710661, i64 281474976710659, i64 281474976710675] subroutine mapType_derived_type_alloca() type :: one_layer real(4) :: i @@ -266,8 +266,8 @@ subroutine mapType_derived_type_alloca() !$omp end target end subroutine -!CHECK: @.offload_sizes{{.*}} = private unnamed_addr constant [8 x i64] [i64 0, i64 40, i64 8, i64 0, i64 48, i64 8, i64 0, i64 4] -!CHECK: @.offload_maptypes{{.*}} = private unnamed_addr constant [8 x i64] [i64 32, i64 281474976710657, i64 281474976710659, i64 281474976710675, i64 281474976710657, i64 281474976710659, i64 281474976710675, i64 281474976710659] +!CHECK: @.offload_sizes{{.*}} = private unnamed_addr constant [9 x i64] [i64 0, i64 0, i64 0, i64 8, i64 0, i64 48, i64 8, i64 0, i64 4] +!CHECK: @.offload_maptypes{{.*}} = private unnamed_addr constant [9 x i64] [i64 32, i64 281474976710661, i64 281474976710661, i64 281474976710659, i64 281474976710675, i64 281474976710661, i64 281474976710659, i64 281474976710675, i64 281474976710659] subroutine mapType_alloca_derived_type() type :: one_layer real(4) :: i @@ -289,8 +289,8 @@ subroutine mapType_alloca_derived_type() !$omp end target end subroutine -!CHECK: @.offload_sizes{{.*}} = private unnamed_addr constant [8 x i64] [i64 0, i64 40, i64 8, i64 0, i64 48, i64 8, i64 0, i64 4] -!CHECK: @.offload_maptypes{{.*}} = private unnamed_addr constant [8 x i64] [i64 32, i64 281474976710657, i64 281474976710659, i64 281474976710675, i64 281474976710657, i64 281474976710659, i64 281474976710675, i64 281474976710659] +!CHECK: @.offload_sizes{{.*}} = private unnamed_addr constant [9 x i64] [i64 0, i64 0, i64 0, i64 8, i64 0, i64 48, i64 8, i64 0, i64 4] +!CHECK: @.offload_maptypes{{.*}} = private unnamed_addr constant [9 x i64] [i64 32, i64 281474976710661, i64 281474976710661, i64 281474976710659, i64 281474976710675, i64 281474976710661, i64 281474976710659, i64 281474976710675, i64 281474976710659] subroutine mapType_alloca_nested_derived_type() type :: middle_layer real(4) :: i @@ -321,7 +321,7 @@ subroutine mapType_alloca_nested_derived_type() end subroutine !CHECK: @.offload_sizes{{.*}} = private unnamed_addr constant [4 x i64] [i64 0, i64 48, i64 8, i64 0] -!CHECK: @.offload_maptypes{{.*}} = private unnamed_addr constant [4 x i64] [i64 32, i64 281474976710657, i64 281474976710659, i64 281474976710675] +!CHECK: @.offload_maptypes{{.*}} = private unnamed_addr constant [4 x i64] [i64 32, i64 281474976710661, i64 281474976710659, i64 281474976710675] subroutine mapType_nested_derived_type_alloca() type :: middle_layer real(4) :: i @@ -350,7 +350,7 @@ subroutine mapType_nested_derived_type_alloca() end subroutine !CHECK: @.offload_sizes{{.*}} = private unnamed_addr constant [7 x i64] [i64 0, i64 64, i64 8, i64 0, i64 48, i64 8, i64 0] -!CHECK: @.offload_maptypes{{.*}} = private unnamed_addr constant [7 x i64] [i64 32, i64 281474976710657, i64 281474976710656, i64 281474976710672, i64 281474976710657, i64 281474976710659, i64 281474976710675] +!CHECK: @.offload_maptypes{{.*}} = private unnamed_addr constant [7 x i64] [i64 32, i64 281474976710661, i64 281474976710656, i64 281474976710672, i64 281474976710661, i64 281474976710659, i64 281474976710675] subroutine mapType_nested_derived_type_member_idx() type :: vertexes integer :: test @@ -428,7 +428,7 @@ end subroutine mapType_common_block_members !CHECK: %[[ALLOCA_INT:.*]] = ptrtoint ptr %[[ALLOCA]] to i64 !CHECK: %[[SIZE_DIFF:.*]] = sub i64 %[[ALLOCA_GEP_INT]], %[[ALLOCA_INT]] !CHECK: %[[DIV:.*]] = sdiv exact i64 %[[SIZE_DIFF]], ptrtoint (ptr getelementptr (i8, ptr null, i32 1) to i64) -!CHECK: %[[OFFLOAD_SIZE_ARR:.*]] = getelementptr inbounds [4 x i64], ptr %.offload_sizes, i32 0, i32 0 +!CHECK: %[[OFFLOAD_SIZE_ARR:.*]] = getelementptr inbounds [5 x i64], ptr %.offload_sizes, i32 0, i32 0 !CHECK: store i64 %[[DIV]], ptr %[[OFFLOAD_SIZE_ARR]], align 8 !CHECK-LABEL: define {{.*}} @{{.*}}maptype_allocatable_explicit_{{.*}} @@ -438,7 +438,7 @@ end subroutine mapType_common_block_members !CHECK: %[[ALLOCA_INT:.*]] = ptrtoint ptr %[[ALLOCA]] to i64 !CHECK: %[[SIZE_DIFF:.*]] = sub i64 %[[ALLOCA_GEP_INT]], %[[ALLOCA_INT]] !CHECK: %[[DIV:.*]] = sdiv exact i64 %[[SIZE_DIFF]], ptrtoint (ptr getelementptr (i8, ptr null, i32 1) to i64) -!CHECK: %[[OFFLOAD_SIZE_ARR:.*]] = getelementptr inbounds [4 x i64], ptr %.offload_sizes, i32 0, i32 0 +!CHECK: %[[OFFLOAD_SIZE_ARR:.*]] = getelementptr inbounds [5 x i64], ptr %.offload_sizes, i32 0, i32 0 !CHECK: store i64 %[[DIV]], ptr %[[OFFLOAD_SIZE_ARR]], align 8 !CHECK-LABEL: define {{.*}} @{{.*}}maptype_derived_implicit_{{.*}} @@ -620,43 +620,56 @@ end subroutine mapType_common_block_members !CHECK: %[[DTYPE_BEGIN:.*]] = ptrtoint ptr %[[DTYPE_DESC_ALLOCA_3]] to i64 !CHECK: %[[DTYPE_DESC_SZ_CALC:.*]] = sub i64 %[[DTYPE_END]], %[[DTYPE_BEGIN]] !CHECK: %[[DTYPE_DESC_SZ:.*]] = sdiv exact i64 %[[DTYPE_DESC_SZ_CALC]], ptrtoint (ptr getelementptr (i8, ptr null, i32 1) to i64) -!CHECK: %[[SIZE_CMP:.*]] = icmp eq ptr %[[MEMBER_ARRAY_OFFSET]], null -!CHECK: %[[SIZE_SEL:.*]] = select i1 %[[SIZE_CMP]], i64 0, i64 %[[MEMBER_SIZE_CALC_4]] -!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_baseptrs, i32 0, i32 0 +!CHECK: %[[DTYPE_BASE_ADDR_ACCESS_4:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, ptr %[[DTYPE_DESC_ALLOCA_3]], i32 1 +!CHECK: %[[DTYPE_BASE_ADDR_ACCESS_3_OFF:.*]] = getelementptr ptr, ptr %[[DTYPE_BASE_ADDR_ACCESS_3]], i32 1 +!CHECK: %[[SIZE_2_CALC_1:.*]] = ptrtoint ptr %[[DTYPE_BASE_ADDR_ACCESS_4]] to i64 +!CHECK: %[[SIZE_2_CALC_2:.*]] = ptrtoint ptr %[[DTYPE_BASE_ADDR_ACCESS_3_OFF]] to i64 +!CHECK: %[[SIZE_2_CALC_3:.*]] = sub i64 %[[SIZE_2_CALC_1]], %[[SIZE_2_CALC_2]] +!CHECK: %[[SIZE_2_CALC_4:.*]] = sdiv exact i64 %[[SIZE_2_CALC_3]], ptrtoint (ptr getelementptr (i8, ptr null, i32 1) to i64) +!CHECK: %[[CMP_NULL:.*]] = icmp eq ptr %[[MEMBER_ARRAY_OFFSET]], null +!CHECK: %[[NULL_SEL:.*]] = select i1 %[[CMP_NULL]], i64 0, i64 %[[MEMBER_SIZE_CALC_4]] + +!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_baseptrs, i32 0, i32 0 !CHECK: store ptr %[[DTYPE_DESC_ALLOCA_3]], ptr %[[BASE_PTR_ARR]], align 8 -!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_ptrs, i32 0, i32 0 +!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_ptrs, i32 0, i32 0 !CHECK: store ptr %[[DTYPE_DESC_ALLOCA_3]], ptr %[[OFFLOAD_PTR_ARR]], align 8 -!CHECK: %[[OFFLOAD_SIZE_ARR:.*]] = getelementptr inbounds [8 x i64], ptr %.offload_sizes, i32 0, i32 0 +!CHECK: %[[OFFLOAD_SIZE_ARR:.*]] = getelementptr inbounds [9 x i64], ptr %.offload_sizes, i32 0, i32 0 !CHECK: store i64 %[[DTYPE_DESC_SZ]], ptr %[[OFFLOAD_SIZE_ARR]], align 8 -!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_baseptrs, i32 0, i32 1 +!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_baseptrs, i32 0, i32 1 !CHECK: store ptr %[[DTYPE_DESC_ALLOCA_3]], ptr %[[BASE_PTR_ARR]], align 8 -!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_ptrs, i32 0, i32 1 +!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_ptrs, i32 0, i32 1 !CHECK: store ptr %[[DTYPE_DESC_ALLOCA_3]], ptr %[[OFFLOAD_PTR_ARR]], align 8 -!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_baseptrs, i32 0, i32 2 +!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_baseptrs, i32 0, i32 2 !CHECK: store ptr %[[DTYPE_DESC_ALLOCA_3]], ptr %[[BASE_PTR_ARR]], align 8 -!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_ptrs, i32 0, i32 2 +!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_ptrs, i32 0, i32 2 +!CHECK: store ptr %[[DTYPE_BASE_ADDR_ACCESS_3_OFF]], ptr %[[OFFLOAD_PTR_ARR]], align 8 +!CHECK: %[[OFFLOAD_SIZE_ARR:.*]] = getelementptr inbounds [9 x i64], ptr %.offload_sizes, i32 0, i32 2 +!CHECK: store i64 %[[SIZE_2_CALC_4]], ptr %[[OFFLOAD_SIZE_ARR]], align 8 +!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_baseptrs, i32 0, i32 3 +!CHECK: store ptr %[[DTYPE_DESC_ALLOCA_3]], ptr %[[BASE_PTR_ARR]], align 8 +!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_ptrs, i32 0, i32 3 !CHECK: store ptr %[[DTYPE_BASE_ADDR_ACCESS_3]], ptr %[[OFFLOAD_PTR_ARR]], align 8 -!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_baseptrs, i32 0, i32 3 +!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_baseptrs, i32 0, i32 4 !CHECK: store ptr %[[DTYPE_BASE_ADDR_ACCESS_3]], ptr %[[BASE_PTR_ARR]], align 8 -!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_ptrs, i32 0, i32 3 +!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_ptrs, i32 0, i32 4 !CHECK: store ptr %[[DTYPE_BASE_ADDR_LOAD_3]], ptr %[[OFFLOAD_PTR_ARR]], align 8 -!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_baseptrs, i32 0, i32 4 +!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_baseptrs, i32 0, i32 5 !CHECK: store ptr %[[DTYPE_DESC_ALLOCA_3]], ptr %[[BASE_PTR_ARR]], align 8 -!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_ptrs, i32 0, i32 4 +!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_ptrs, i32 0, i32 5 !CHECK: store ptr %[[DTYPE_ALLOCA_MEMBER_ACCESS]], ptr %[[OFFLOAD_PTR_ARR]], align 8 -!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_baseptrs, i32 0, i32 5 +!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_baseptrs, i32 0, i32 6 !CHECK: store ptr %[[DTYPE_DESC_ALLOCA_3]], ptr %[[BASE_PTR_ARR]], align 8 -!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_ptrs, i32 0, i32 5 +!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_ptrs, i32 0, i32 6 !CHECK: store ptr %[[DTYPE_ALLOCA_MEMBER_BASE_ADDR_ACCESS]], ptr %[[OFFLOAD_PTR_ARR]], align 8 -!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_baseptrs, i32 0, i32 6 +!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_baseptrs, i32 0, i32 7 !CHECK: store ptr %[[DTYPE_ALLOCA_MEMBER_BASE_ADDR_ACCESS]], ptr %[[BASE_PTR_ARR]], align 8 -!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_ptrs, i32 0, i32 6 +!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_ptrs, i32 0, i32 7 !CHECK: store ptr %[[MEMBER_ARRAY_OFFSET]], ptr %[[OFFLOAD_PTR_ARR]], align 8 -!CHECK: %[[OFFLOAD_SIZE_ARR:.*]] = getelementptr inbounds [8 x i64], ptr %.offload_sizes, i32 0, i32 6 -!CHECK: store i64 %[[SIZE_SEL]], ptr %[[OFFLOAD_SIZE_ARR]], align 8 -!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_baseptrs, i32 0, i32 7 +!CHECK: %[[OFFLOAD_SIZE_ARR:.*]] = getelementptr inbounds [9 x i64], ptr %.offload_sizes, i32 0, i32 7 +!CHECK: store i64 %[[NULL_SEL]], ptr %[[OFFLOAD_SIZE_ARR]], align 8 +!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_baseptrs, i32 0, i32 8 !CHECK: store ptr %[[DTYPE_DESC_ALLOCA_3]], ptr %[[BASE_PTR_ARR]], align 8 -!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_ptrs, i32 0, i32 7 +!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_ptrs, i32 0, i32 8 !CHECK: store ptr %[[DTYPE_NONALLOCA_MEMBER_ACCESS]], ptr %[[OFFLOAD_PTR_ARR]], align 8 !CHECK-LABEL: define {{.*}} @{{.*}}maptype_alloca_nested_derived_type{{.*}} @@ -690,43 +703,55 @@ end subroutine mapType_common_block_members !CHECK: %[[DTYPE_DESC_SIZE_CALC_3:.*]] = ptrtoint ptr %[[DTYPE_DESC_ALLOCA_3]] to i64 !CHECK: %[[DTYPE_DESC_SIZE_CALC_4:.*]] = sub i64 %[[DTYPE_DESC_SIZE_CALC_2]], %[[DTYPE_DESC_SIZE_CALC_3]] !CHECK: %[[DTYPE_DESC_SIZE_CALC_5:.*]] = sdiv exact i64 %[[DTYPE_DESC_SIZE_CALC_4]], ptrtoint (ptr getelementptr (i8, ptr null, i32 1) to i64) -!CHECK: %[[DATA_CMP:.*]] = icmp eq ptr %[[ARRAY_OFFSET]], null -!CHECK: %[[DATA_SEL:.*]] = select i1 %[[DATA_CMP]], i64 0, i64 %[[ALLOCATABLE_MEMBER_SIZE_CALC_5]] -!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_baseptrs, i32 0, i32 0 +!CHECK: %[[DTYPE_BASE_ADDR_ACCESS_3:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, ptr %[[DTYPE_DESC_ALLOCA_3]], i32 1 +!CHECK: %[[DTYPE_BASE_ADDR_ACCESS_3_OFF:.*]] = getelementptr ptr, ptr %[[DTYPE_DESC_BASE_ADDR]], i32 1 +!CHECK: %[[SIZE_2_CALC_1:.*]] = ptrtoint ptr %[[DTYPE_BASE_ADDR_ACCESS_3]] to i64 +!CHECK: %[[SIZE_2_CALC_2:.*]] = ptrtoint ptr %[[DTYPE_BASE_ADDR_ACCESS_3_OFF]] to i64 +!CHECK: %[[SIZE_2_CALC_3:.*]] = sub i64 %[[SIZE_2_CALC_1]], %[[SIZE_2_CALC_2]] +!CHECK: %[[SIZE_2_CALC_4:.*]] = sdiv exact i64 %[[SIZE_2_CALC_3]], ptrtoint (ptr getelementptr (i8, ptr null, i32 1) to i64) +!CHECK: %[[NULL_CMP:.*]] = icmp eq ptr %[[ARRAY_OFFSET]], null +!CHECK: %[[NULL_SEL:.*]] = select i1 %[[NULL_CMP]], i64 0, i64 %[[ALLOCATABLE_MEMBER_SIZE_CALC_5]] +!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_baseptrs, i32 0, i32 0 !CHECK: store ptr %[[DTYPE_DESC_ALLOCA_3]], ptr %[[BASE_PTR_ARR]], align 8 -!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_ptrs, i32 0, i32 0 +!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_ptrs, i32 0, i32 0 !CHECK: store ptr %[[DTYPE_DESC_ALLOCA_3]], ptr %[[OFFLOAD_PTR_ARR]], align 8 -!CHECK: %[[OFFLOAD_SIZE_ARR:.*]] = getelementptr inbounds [8 x i64], ptr %.offload_sizes, i32 0, i32 0 +!CHECK: %[[OFFLOAD_SIZE_ARR:.*]] = getelementptr inbounds [9 x i64], ptr %.offload_sizes, i32 0, i32 0 !CHECK: store i64 %[[DTYPE_DESC_SIZE_CALC_5]], ptr %[[OFFLOAD_SIZE_ARR]], align 8 -!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_baseptrs, i32 0, i32 1 +!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_baseptrs, i32 0, i32 1 !CHECK: store ptr %[[DTYPE_DESC_ALLOCA_3]], ptr %[[BASE_PTR_ARR]], align 8 -!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_ptrs, i32 0, i32 1 +!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_ptrs, i32 0, i32 1 !CHECK: store ptr %[[DTYPE_DESC_ALLOCA_3]], ptr %[[OFFLOAD_PTR_ARR]], align 8 -!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_baseptrs, i32 0, i32 2 +!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_baseptrs, i32 0, i32 2 +!CHECK: store ptr %[[DTYPE_DESC_ALLOCA_3]], ptr %[[BASE_PTR_ARR]], align 8 +!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_ptrs, i32 0, i32 2 +!CHECK: store ptr %[[DTYPE_BASE_ADDR_ACCESS_3_OFF]], ptr %[[OFFLOAD_PTR_ARR]], align 8 +!CHECK: %[[OFFLOAD_SIZE_ARR:.*]] = getelementptr inbounds [9 x i64], ptr %.offload_sizes, i32 0, i32 2 +!CHECK: store i64 %[[SIZE_2_CALC_4]], ptr %[[OFFLOAD_SIZE_ARR]], align 8 +!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_baseptrs, i32 0, i32 3 !CHECK: store ptr %[[DTYPE_DESC_ALLOCA_3]], ptr %[[BASE_PTR_ARR]], align 8 -!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_ptrs, i32 0, i32 2 +!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_ptrs, i32 0, i32 3 !CHECK: store ptr %[[DTYPE_DESC_BASE_ADDR]], ptr %[[OFFLOAD_PTR_ARR]], align 8 -!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_baseptrs, i32 0, i32 3 +!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_baseptrs, i32 0, i32 4 !CHECK: store ptr %[[DTYPE_DESC_BASE_ADDR]], ptr %[[BASE_PTR_ARR]], align 8 -!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_ptrs, i32 0, i32 3 +!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_ptrs, i32 0, i32 4 !CHECK: store ptr %[[LOAD_BASE_ADDR]], ptr %[[OFFLOAD_PTR_ARR]], align 8 -!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_baseptrs, i32 0, i32 4 +!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_baseptrs, i32 0, i32 5 !CHECK: store ptr %[[DTYPE_DESC_ALLOCA_3]], ptr %[[BASE_PTR_ARR]], align 8 -!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_ptrs, i32 0, i32 4 +!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_ptrs, i32 0, i32 5 !CHECK: store ptr %[[MAPPED_MEMBER_ACCESS]], ptr %[[OFFLOAD_PTR_ARR]], align 8 -!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_baseptrs, i32 0, i32 5 +!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_baseptrs, i32 0, i32 6 !CHECK: store ptr %[[DTYPE_DESC_ALLOCA_3]], ptr %[[BASE_PTR_ARR]], align 8 -!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_ptrs, i32 0, i32 5 +!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_ptrs, i32 0, i32 6 !CHECK: store ptr %[[MAPPED_MEMBER_BASE_ADDR_ACCESS]], ptr %[[OFFLOAD_PTR_ARR]], align 8 -!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_baseptrs, i32 0, i32 6 +!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_baseptrs, i32 0, i32 7 !CHECK: store ptr %[[MAPPED_MEMBER_BASE_ADDR_ACCESS]], ptr %[[BASE_PTR_ARR]], align 8 -!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_ptrs, i32 0, i32 6 +!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_ptrs, i32 0, i32 7 !CHECK: store ptr %[[ARRAY_OFFSET]], ptr %[[OFFLOAD_PTR_ARR]], align 8 -!CHECK: %[[OFFLOAD_SIZE_ARR:.*]] = getelementptr inbounds [8 x i64], ptr %.offload_sizes, i32 0, i32 6 -!CHECK: store i64 %[[DATA_SEL]], ptr %[[OFFLOAD_SIZE_ARR]], align 8 -!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_baseptrs, i32 0, i32 7 +!CHECK: %[[OFFLOAD_SIZE_ARR:.*]] = getelementptr inbounds [9 x i64], ptr %.offload_sizes, i32 0, i32 7 +!CHECK: store i64 %[[NULL_SEL]], ptr %[[OFFLOAD_SIZE_ARR]], align 8 +!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_baseptrs, i32 0, i32 8 !CHECK: store ptr %[[DTYPE_DESC_ALLOCA_3]], ptr %[[BASE_PTR_ARR]], align 8 -!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_ptrs, i32 0, i32 7 +!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_ptrs, i32 0, i32 8 !CHECK: store ptr %[[NESTED_NONALLOCA_MEMBER_ACCESS]], ptr %[[OFFLOAD_PTR_ARR]], align 8 !CHECK-LABEL: define {{.*}} @{{.*}}maptype_nested_derived_type_alloca{{.*}} diff --git a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp index 8edec990eaaba..eb36e68d5ff58 100644 --- a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp +++ b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp @@ -4042,41 +4042,60 @@ static int getMapDataMemberIdx(MapInfoData &mapData, omp::MapInfoOp memberOp) { return std::distance(mapData.MapClause.begin(), res); } -static omp::MapInfoOp getFirstOrLastMappedMemberPtr(omp::MapInfoOp mapInfo, - bool first) { +static void sortMapIndices(llvm::SmallVectorImpl &indices, + omp::MapInfoOp mapInfo) { ArrayAttr indexAttr = mapInfo.getMembersIndexAttr(); - // Only 1 member has been mapped, we can return it. - if (indexAttr.size() == 1) - return cast(mapInfo.getMembers()[0].getDefiningOp()); + llvm::SmallVector occludedChildren; + llvm::sort( + indices.begin(), indices.end(), [&](const size_t a, const size_t b) { + auto memberIndicesA = cast(indexAttr[a]); + auto memberIndicesB = cast(indexAttr[b]); - llvm::SmallVector indices(indexAttr.size()); - std::iota(indices.begin(), indices.end(), 0); + for (auto it : llvm::zip(memberIndicesA, memberIndicesB)) { + int64_t aIndex = mlir::cast(std::get<0>(it)).getInt(); + int64_t bIndex = mlir::cast(std::get<1>(it)).getInt(); - llvm::sort(indices, [&](const size_t a, const size_t b) { - auto memberIndicesA = cast(indexAttr[a]); - auto memberIndicesB = cast(indexAttr[b]); - for (const auto it : llvm::zip(memberIndicesA, memberIndicesB)) { - int64_t aIndex = cast(std::get<0>(it)).getInt(); - int64_t bIndex = cast(std::get<1>(it)).getInt(); + if (aIndex == bIndex) + continue; - if (aIndex == bIndex) - continue; + if (aIndex < bIndex) + return true; - if (aIndex < bIndex) - return first; + if (aIndex > bIndex) + return false; + } - if (aIndex > bIndex) - return !first; - } + // Iterated up until the end of the smallest member and + // they were found to be equal up to that point, so select + // the member with the lowest index count, so the "parent" + bool memberAParent = memberIndicesA.size() < memberIndicesB.size(); + if (memberAParent) + occludedChildren.push_back(b); + else + occludedChildren.push_back(a); + return memberAParent; + }); - // Iterated the up until the end of the smallest member and - // they were found to be equal up to that point, so select - // the member with the lowest index count, so the "parent" - return memberIndicesA.size() < memberIndicesB.size(); - }); + // We remove children from the index list that are overshadowed by + // a parent, this prevents us retrieving these as the first or last + // element when the parent is the correct element in these cases. + for (auto v : occludedChildren) + indices.erase(std::remove(indices.begin(), indices.end(), v), + indices.end()); +} +static omp::MapInfoOp getFirstOrLastMappedMemberPtr(omp::MapInfoOp mapInfo, + bool first) { + ArrayAttr indexAttr = mapInfo.getMembersIndexAttr(); + // Only 1 member has been mapped, we can return it. + if (indexAttr.size() == 1) + return cast(mapInfo.getMembers()[0].getDefiningOp()); + llvm::SmallVector indices(indexAttr.size()); + std::iota(indices.begin(), indices.end(), 0); + sortMapIndices(indices, mapInfo); return llvm::cast( - mapInfo.getMembers()[indices.front()].getDefiningOp()); + mapInfo.getMembers()[first ? indices.front() : indices.back()] + .getDefiningOp()); } /// This function calculates the array/pointer offset for map data provided @@ -4155,6 +4174,86 @@ calculateBoundsOffset(LLVM::ModuleTranslation &moduleTranslation, return idx; } +static void getAsIntegers(ArrayAttr values, llvm::SmallVector &ints) { + llvm::transform(values, std::back_inserter(ints), [](Attribute value) { + return cast(value).getInt(); + }); +} + +// Gathers members that are overlapping in the parent, excluding members that +// themselves overlap, keeping the top-most (closest to parents level) map. +static void +getOverlappedMembers(llvm::SmallVectorImpl &overlapMapDataIdxs, + omp::MapInfoOp parentOp) { + // No members mapped, no overlaps. + if (parentOp.getMembers().empty()) + return; + + // Single member, we can insert and return early. + if (parentOp.getMembers().size() == 1) { + overlapMapDataIdxs.push_back(0); + return; + } + + // 1) collect list of top-level overlapping members from MemberOp + llvm::SmallVector> memberByIndex; + ArrayAttr indexAttr = parentOp.getMembersIndexAttr(); + for (auto [memIndex, indicesAttr] : llvm::enumerate(indexAttr)) + memberByIndex.push_back( + std::make_pair(memIndex, cast(indicesAttr))); + + // Sort the smallest first (higher up the parent -> member chain), so that + // when we remove members, we remove as much as we can in the initial + // iterations, shortening the number of passes required. + llvm::sort(memberByIndex.begin(), memberByIndex.end(), + [&](auto a, auto b) { return a.second.size() < b.second.size(); }); + + // Remove elements from the vector if there is a parent element that + // supersedes it. i.e. if member [0] is mapped, we can remove members [0,1], + // [0,2].. etc. + llvm::SmallVector> skipList; + for (auto v : memberByIndex) { + llvm::SmallVector vArr(v.second.size()); + getAsIntegers(v.second, vArr); + skipList.push_back( + *std::find_if(memberByIndex.begin(), memberByIndex.end(), [&](auto x) { + if (v == x) + return false; + llvm::SmallVector xArr(x.second.size()); + getAsIntegers(x.second, xArr); + return std::equal(vArr.begin(), vArr.end(), xArr.begin()) && + xArr.size() >= vArr.size(); + })); + } + + // Collect the indices, as we need the base pointer etc. from the MapData + // structure which is primarily accessible via index at the moment. + for (auto v : memberByIndex) + if (find(skipList.begin(), skipList.end(), v) == skipList.end()) + overlapMapDataIdxs.push_back(v.first); +} + +// The intent is to verify if the mapped data being passed is a +// pointer -> pointee that requires special handling in certain cases, +// e.g. applying the OMP_MAP_PTR_AND_OBJ map type. +// +// There may be a better way to verify this, but unfortunately with +// opaque pointers we lose the ability to easily check if something is +// a pointer whilst maintaining access to the underlying type. +static bool checkIfPointerMap(omp::MapInfoOp mapOp) { + // If we have a varPtrPtr field assigned then the underlying type is a pointer + if (mapOp.getVarPtrPtr()) + return true; + + // If the map data is declare target with a link clause, then it's represented + // as a pointer when we lower it to LLVM-IR even if at the MLIR level it has + // no relation to pointers. + if (isDeclareTargetLink(mapOp.getVarPtr())) + return true; + + return false; +} + // This creates two insertions into the MapInfosTy data structure for the // "parent" of a set of members, (usually a container e.g. // class/structure/derived type) when subsequent members have also been @@ -4170,10 +4269,12 @@ calculateBoundsOffset(LLVM::ModuleTranslation &moduleTranslation, // // This function borrows a lot from Clang's emitCombinedEntry function // inside of CGOpenMPRuntime.cpp -static llvm::omp::OpenMPOffloadMappingFlags mapParentWithMembers( - LLVM::ModuleTranslation &moduleTranslation, llvm::IRBuilderBase &builder, - llvm::OpenMPIRBuilder &ompBuilder, DataLayout &dl, MapInfosTy &combinedInfo, - MapInfoData &mapData, uint64_t mapDataIndex, bool isTargetParams) { +static llvm::omp::OpenMPOffloadMappingFlags +mapParentWithMembers(LLVM::ModuleTranslation &moduleTranslation, + llvm::IRBuilderBase &builder, + llvm::OpenMPIRBuilder &ompBuilder, DataLayout &dl, + MapInfosTy &combinedInfo, MapInfoData &mapData, + uint64_t mapDataIndex, TargetDirective targetDirective) { assert(!ompBuilder.Config.isTargetDevice() && "function only supported for host device codegen"); @@ -4217,7 +4318,6 @@ static llvm::omp::OpenMPOffloadMappingFlags mapParentWithMembers( // runtime information on the dynamically allocated data). auto parentClause = llvm::cast(mapData.MapClause[mapDataIndex]); - llvm::Value *lowAddr, *highAddr; if (!parentClause.getPartialMap()) { lowAddr = builder.CreatePointerCast(mapData.Pointers[mapDataIndex], @@ -4263,39 +4363,85 @@ static llvm::omp::OpenMPOffloadMappingFlags mapParentWithMembers( // further case specific flag modifications). For the moment, it handles // what we support as expected. llvm::omp::OpenMPOffloadMappingFlags mapFlag = mapData.Types[mapDataIndex]; + bool hasMapClose = (llvm::omp::OpenMPOffloadMappingFlags(mapFlag) & + llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_CLOSE) == + llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_CLOSE; ompBuilder.setCorrectMemberOfFlag(mapFlag, memberOfFlag); - combinedInfo.Types.emplace_back(mapFlag); - combinedInfo.DevicePointers.emplace_back( - llvm::OpenMPIRBuilder::DeviceInfoTy::None); - combinedInfo.Mappers.emplace_back(nullptr); - combinedInfo.Names.emplace_back(LLVM::createMappingInformation( - mapData.MapClause[mapDataIndex]->getLoc(), ompBuilder)); - combinedInfo.BasePointers.emplace_back(mapData.BasePointers[mapDataIndex]); - combinedInfo.Pointers.emplace_back(mapData.Pointers[mapDataIndex]); - combinedInfo.Sizes.emplace_back(mapData.Sizes[mapDataIndex]); - } - return memberOfFlag; -} - -// The intent is to verify if the mapped data being passed is a -// pointer -> pointee that requires special handling in certain cases, -// e.g. applying the OMP_MAP_PTR_AND_OBJ map type. -// -// There may be a better way to verify this, but unfortunately with -// opaque pointers we lose the ability to easily check if something is -// a pointer whilst maintaining access to the underlying type. -static bool checkIfPointerMap(omp::MapInfoOp mapOp) { - // If we have a varPtrPtr field assigned then the underlying type is a pointer - if (mapOp.getVarPtrPtr()) - return true; - // If the map data is declare target with a link clause, then it's represented - // as a pointer when we lower it to LLVM-IR even if at the MLIR level it has - // no relation to pointers. - if (isDeclareTargetLink(mapOp.getVarPtr())) - return true; + if (targetDirective == TargetDirective::TargetUpdate || hasMapClose) { + combinedInfo.Types.emplace_back(mapFlag); + combinedInfo.DevicePointers.emplace_back( + mapData.DevicePointers[mapDataIndex]); + combinedInfo.Names.emplace_back(LLVM::createMappingInformation( + mapData.MapClause[mapDataIndex]->getLoc(), ompBuilder)); + combinedInfo.BasePointers.emplace_back( + mapData.BasePointers[mapDataIndex]); + combinedInfo.Pointers.emplace_back(mapData.Pointers[mapDataIndex]); + combinedInfo.Sizes.emplace_back(mapData.Sizes[mapDataIndex]); + combinedInfo.Mappers.emplace_back(mapData.Mappers[mapDataIndex]); + } else { + llvm::SmallVector overlapIdxs; + // Find all of the members that "overlap", i.e. occlude other members that + // were mapped alongside the parent, e.g. member [0], occludes [0,1] and + // [0,2], but not [1,0]. + getOverlappedMembers(overlapIdxs, parentClause); + // We need to make sure the overlapped members are sorted in order of + // lowest address to highest address. + sortMapIndices(overlapIdxs, parentClause); + + lowAddr = builder.CreatePointerCast(mapData.Pointers[mapDataIndex], + builder.getPtrTy()); + highAddr = builder.CreatePointerCast( + builder.CreateConstGEP1_32(mapData.BaseType[mapDataIndex], + mapData.Pointers[mapDataIndex], 1), + builder.getPtrTy()); + + // TODO: We may want to skip arrays/array sections in this as Clang does. + // It appears to be an optimisation rather than a necessity though, + // but this requires further investigation. However, we would have to make + // sure to not exclude maps with bounds that ARE pointers, as these are + // processed as separate components, i.e. pointer + data. + for (auto v : overlapIdxs) { + auto mapDataOverlapIdx = getMapDataMemberIdx( + mapData, + cast(parentClause.getMembers()[v].getDefiningOp())); + combinedInfo.Types.emplace_back(mapFlag); + combinedInfo.DevicePointers.emplace_back( + mapData.DevicePointers[mapDataOverlapIdx]); + combinedInfo.Names.emplace_back(LLVM::createMappingInformation( + mapData.MapClause[mapDataIndex]->getLoc(), ompBuilder)); + combinedInfo.BasePointers.emplace_back( + mapData.BasePointers[mapDataIndex]); + combinedInfo.Mappers.emplace_back(mapData.Mappers[mapDataIndex]); + combinedInfo.Pointers.emplace_back(lowAddr); + combinedInfo.Sizes.emplace_back(builder.CreateIntCast( + builder.CreatePtrDiff(builder.getInt8Ty(), + mapData.OriginalValue[mapDataOverlapIdx], + lowAddr), + builder.getInt64Ty(), /*isSigned=*/true)); + lowAddr = builder.CreateConstGEP1_32( + checkIfPointerMap(llvm::cast( + mapData.MapClause[mapDataOverlapIdx])) + ? builder.getPtrTy() + : mapData.BaseType[mapDataOverlapIdx], + mapData.BasePointers[mapDataOverlapIdx], 1); + } - return false; + combinedInfo.Types.emplace_back(mapFlag); + combinedInfo.DevicePointers.emplace_back( + mapData.DevicePointers[mapDataIndex]); + combinedInfo.Names.emplace_back(LLVM::createMappingInformation( + mapData.MapClause[mapDataIndex]->getLoc(), ompBuilder)); + combinedInfo.BasePointers.emplace_back( + mapData.BasePointers[mapDataIndex]); + combinedInfo.Mappers.emplace_back(mapData.Mappers[mapDataIndex]); + combinedInfo.Pointers.emplace_back(lowAddr); + combinedInfo.Sizes.emplace_back(builder.CreateIntCast( + builder.CreatePtrDiff(builder.getInt8Ty(), highAddr, lowAddr), + builder.getInt64Ty(), true)); + } + } + return memberOfFlag; } // This function is intended to add explicit mappings of members @@ -4303,7 +4449,8 @@ static void processMapMembersWithParent( LLVM::ModuleTranslation &moduleTranslation, llvm::IRBuilderBase &builder, llvm::OpenMPIRBuilder &ompBuilder, DataLayout &dl, MapInfosTy &combinedInfo, MapInfoData &mapData, uint64_t mapDataIndex, - llvm::omp::OpenMPOffloadMappingFlags memberOfFlag) { + llvm::omp::OpenMPOffloadMappingFlags memberOfFlag, + TargetDirective targetDirective) { assert(!ompBuilder.Config.isTargetDevice() && "function only supported for host device codegen"); @@ -4375,7 +4522,8 @@ static void processMapMembersWithParent( } static void processIndividualMap(MapInfoData &mapData, size_t mapDataIdx, - MapInfosTy &combinedInfo, bool isTargetParams, + MapInfosTy &combinedInfo, + TargetDirective targetDirective, int mapDataParentIdx = -1) { // Declare Target Mappings are excluded from being marked as // OMP_MAP_TARGET_PARAM as they are not passed as parameters, they're @@ -4416,7 +4564,7 @@ static void processMapWithMembersOf(LLVM::ModuleTranslation &moduleTranslation, llvm::OpenMPIRBuilder &ompBuilder, DataLayout &dl, MapInfosTy &combinedInfo, MapInfoData &mapData, uint64_t mapDataIndex, - bool isTargetParams) { + TargetDirective targetDirective) { assert(!ompBuilder.Config.isTargetDevice() && "function only supported for host device codegen"); @@ -4528,7 +4676,7 @@ createAlteredByCaptureMap(MapInfoData &mapData, static void genMapInfos(llvm::IRBuilderBase &builder, LLVM::ModuleTranslation &moduleTranslation, DataLayout &dl, MapInfosTy &combinedInfo, - MapInfoData &mapData, bool isTargetParams = false) { + MapInfoData &mapData, TargetDirective targetDirective) { assert(!moduleTranslation.getOpenMPBuilder()->Config.isTargetDevice() && "function only supported for host device codegen"); @@ -4572,11 +4720,13 @@ static void genMapInfos(llvm::IRBuilderBase &builder, static llvm::Expected emitUserDefinedMapper(Operation *declMapperOp, llvm::IRBuilderBase &builder, LLVM::ModuleTranslation &moduleTranslation, - llvm::StringRef mapperFuncName); + llvm::StringRef mapperFuncName, + TargetDirective targetDirective); static llvm::Expected getOrCreateUserDefinedMapperFunc(Operation *op, llvm::IRBuilderBase &builder, - LLVM::ModuleTranslation &moduleTranslation) { + LLVM::ModuleTranslation &moduleTranslation, + TargetDirective targetDirective) { assert(!moduleTranslation.getOpenMPBuilder()->Config.isTargetDevice() && "function only supported for host device codegen"); auto declMapperOp = cast(op); @@ -4588,13 +4738,14 @@ getOrCreateUserDefinedMapperFunc(Operation *op, llvm::IRBuilderBase &builder, return lookupFunc; return emitUserDefinedMapper(declMapperOp, builder, moduleTranslation, - mapperFuncName); + mapperFuncName, targetDirective); } static llvm::Expected emitUserDefinedMapper(Operation *op, llvm::IRBuilderBase &builder, LLVM::ModuleTranslation &moduleTranslation, - llvm::StringRef mapperFuncName) { + llvm::StringRef mapperFuncName, + TargetDirective targetDirective) { assert(!moduleTranslation.getOpenMPBuilder()->Config.isTargetDevice() && "function only supported for host device codegen"); auto declMapperOp = cast(op); @@ -4622,7 +4773,8 @@ emitUserDefinedMapper(Operation *op, llvm::IRBuilderBase &builder, MapInfoData mapData; collectMapDataFromMapOperands(mapData, mapVars, moduleTranslation, dl, builder); - genMapInfos(builder, moduleTranslation, dl, combinedInfo, mapData); + genMapInfos(builder, moduleTranslation, dl, combinedInfo, mapData, + targetDirective); // Drop the mapping that is no longer necessary so that the same region can // be processed multiple times. @@ -4634,7 +4786,7 @@ emitUserDefinedMapper(Operation *op, llvm::IRBuilderBase &builder, if (!combinedInfo.Mappers[i]) return nullptr; return getOrCreateUserDefinedMapperFunc(combinedInfo.Mappers[i], builder, - moduleTranslation); + moduleTranslation, targetDirective); }; llvm::Expected newFn = ompBuilder->emitUserDefinedMapper( @@ -4873,7 +5025,7 @@ convertOmpTargetData(Operation *op, llvm::IRBuilderBase &builder, return nullptr; info.HasMapper = true; return getOrCreateUserDefinedMapperFunc(combinedInfo.Mappers[i], builder, - moduleTranslation); + moduleTranslation, targetDirective); }; llvm::OpenMPIRBuilder::LocationDescription ompLoc(builder); @@ -5882,7 +6034,7 @@ convertOmpTarget(Operation &opInst, llvm::IRBuilderBase &builder, return nullptr; info.HasMapper = true; return getOrCreateUserDefinedMapperFunc(combinedInfos.Mappers[i], builder, - moduleTranslation); + moduleTranslation, targetDirective); }; llvm::Value *ifCond = nullptr; diff --git a/mlir/test/Target/LLVMIR/omptarget-data-use-dev-ordering.mlir b/mlir/test/Target/LLVMIR/omptarget-data-use-dev-ordering.mlir index f6860e5fcce63..d9be6d1c174f6 100644 --- a/mlir/test/Target/LLVMIR/omptarget-data-use-dev-ordering.mlir +++ b/mlir/test/Target/LLVMIR/omptarget-data-use-dev-ordering.mlir @@ -67,18 +67,18 @@ module attributes {omp.is_target_device = false, omp.target_triples = ["amdgcn-a // CHECK: define void @mix_use_device_ptr_and_addr_and_map_(ptr %[[ARG_0:.*]], ptr %[[ARG_1:.*]], ptr %[[ARG_2:.*]], ptr %[[ARG_3:.*]], ptr %[[ARG_4:.*]], ptr %[[ARG_5:.*]], ptr %[[ARG_6:.*]], ptr %[[ARG_7:.*]]) { // CHECK: %[[ALLOCA:.*]] = alloca ptr, align 8 -// CHECK: %[[BASEPTR_0_GEP:.*]] = getelementptr inbounds [10 x ptr], ptr %.offload_baseptrs, i32 0, i32 0 +// CHECK: %[[BASEPTR_0_GEP:.*]] = getelementptr inbounds [12 x ptr], ptr %.offload_baseptrs, i32 0, i32 0 // CHECK: store ptr %[[ARG_0]], ptr %[[BASEPTR_0_GEP]], align 8 -// CHECK: %[[BASEPTR_2_GEP:.*]] = getelementptr inbounds [10 x ptr], ptr %.offload_baseptrs, i32 0, i32 2 +// CHECK: %[[BASEPTR_2_GEP:.*]] = getelementptr inbounds [12 x ptr], ptr %.offload_baseptrs, i32 0, i32 4 // CHECK: store ptr %[[ARG_2]], ptr %[[BASEPTR_2_GEP]], align 8 -// CHECK: %[[BASEPTR_6_GEP:.*]] = getelementptr inbounds [10 x ptr], ptr %.offload_baseptrs, i32 0, i32 6 -// CHECK: store ptr %[[ARG_4]], ptr %[[BASEPTR_6_GEP]], align 8 +// CHECK: %[[BASEPTR_3_GEP:.*]] = getelementptr inbounds [12 x ptr], ptr %.offload_baseptrs, i32 0, i32 9 +// CHECK: store ptr %[[ARG_4]], ptr %[[BASEPTR_3_GEP]], align 8 // CHECK: call void @__tgt_target_data_begin_mapper({{.*}}) // CHECK: %[[LOAD_BASEPTR_0:.*]] = load ptr, ptr %[[BASEPTR_0_GEP]], align 8 // store ptr %[[LOAD_BASEPTR_0]], ptr %[[ALLOCA]], align 8 // CHECK: %[[LOAD_BASEPTR_2:.*]] = load ptr, ptr %[[BASEPTR_2_GEP]], align 8 -// CHECK: %[[LOAD_BASEPTR_6:.*]] = load ptr, ptr %[[BASEPTR_6_GEP]], align 8 +// CHECK: %[[LOAD_BASEPTR_3:.*]] = load ptr, ptr %[[BASEPTR_3_GEP]], align 8 // CHECK: %[[GEP_A4:.*]] = getelementptr { i64 }, ptr %[[ARG_4]], i32 0, i32 0 // CHECK: %[[GEP_A7:.*]] = getelementptr { i64 }, ptr %[[ARG_7]], i32 0, i32 0 // CHECK: %[[LOAD_A4:.*]] = load i64, ptr %[[GEP_A4]], align 4 @@ -93,17 +93,17 @@ module attributes {omp.is_target_device = false, omp.target_triples = ["amdgcn-a // CHECK: define void @mix_use_device_ptr_and_addr_and_map_2(ptr %[[ARG_0:.*]], ptr %[[ARG_1:.*]], ptr %[[ARG_2:.*]], ptr %[[ARG_3:.*]], ptr %[[ARG_4:.*]], ptr %[[ARG_5:.*]], ptr %[[ARG_6:.*]], ptr %[[ARG_7:.*]]) { // CHECK: %[[ALLOCA:.*]] = alloca ptr, align 8 -// CHECK: %[[BASEPTR_1_GEP:.*]] = getelementptr inbounds [10 x ptr], ptr %.offload_baseptrs, i32 0, i32 1 +// CHECK: %[[BASEPTR_1_GEP:.*]] = getelementptr inbounds [12 x ptr], ptr %.offload_baseptrs, i32 0, i32 1 // CHECK: store ptr %[[ARG_0]], ptr %[[BASEPTR_1_GEP]], align 8 -// CHECK: %[[BASEPTR_2_GEP:.*]] = getelementptr inbounds [10 x ptr], ptr %.offload_baseptrs, i32 0, i32 2 +// CHECK: %[[BASEPTR_2_GEP:.*]] = getelementptr inbounds [12 x ptr], ptr %.offload_baseptrs, i32 0, i32 4 // CHECK: store ptr %[[ARG_2]], ptr %[[BASEPTR_2_GEP]], align 8 -// CHECK: %[[BASEPTR_6_GEP:.*]] = getelementptr inbounds [10 x ptr], ptr %.offload_baseptrs, i32 0, i32 6 -// CHECK: store ptr %[[ARG_4]], ptr %[[BASEPTR_6_GEP]], align 8 +// CHECK: %[[BASEPTR_3_GEP:.*]] = getelementptr inbounds [12 x ptr], ptr %.offload_baseptrs, i32 0, i32 9 +// CHECK: store ptr %[[ARG_4]], ptr %[[BASEPTR_3_GEP]], align 8 // CHECK: call void @__tgt_target_data_begin_mapper({{.*}}) // CHECK: %[[LOAD_BASEPTR_1:.*]] = load ptr, ptr %[[BASEPTR_1_GEP]], align 8 // store ptr %[[LOAD_BASEPTR_1]], ptr %[[ALLOCA]], align 8 // CHECK: %[[LOAD_BASEPTR_2:.*]] = load ptr, ptr %[[BASEPTR_2_GEP]], align 8 -// CHECK: %[[LOAD_BASEPTR_6:.*]] = load ptr, ptr %[[BASEPTR_6_GEP]], align 8 +// CHECK: %[[LOAD_BASEPTR_3:.*]] = load ptr, ptr %[[BASEPTR_3_GEP]], align 8 // CHECK: %[[GEP_A4:.*]] = getelementptr { i64 }, ptr %[[ARG_4]], i32 0, i32 0 // CHECK: %[[GEP_A7:.*]] = getelementptr { i64 }, ptr %[[ARG_7]], i32 0, i32 0 // CHECK: %[[LOAD_A4:.*]] = load i64, ptr %[[GEP_A4]], align 4 diff --git a/mlir/test/Target/LLVMIR/omptarget-declare-target-to-host.mlir b/mlir/test/Target/LLVMIR/omptarget-declare-target-to-host.mlir new file mode 100644 index 0000000000000..4202421aed5ac --- /dev/null +++ b/mlir/test/Target/LLVMIR/omptarget-declare-target-to-host.mlir @@ -0,0 +1,34 @@ +// RUN: mlir-translate -mlir-to-llvmir %s | FileCheck %s + +module attributes {llvm.target_triple = "x86_64-unknown-linux-gnu", omp.is_gpu = false, omp.is_target_device = false, omp.target_triples = ["amdgcn-amd-amdhsa"]} { + // CHECK-DAG: @_QMtest_0Ezii = global [11 x float] zeroinitializer + // CHECK-DAG: @.offload_sizes = private unnamed_addr constant [1 x i64] [i64 48] + // CHECK-DAG: @.offload_maptypes = private unnamed_addr constant [1 x i64] [i64 3] + // CHECK-DAG: @.offloading.entry._QMtest_0Ezii = weak constant %struct.__tgt_offload_entry {{.*}} ptr @_QMtest_0Ezii, {{.*}}, i64 44,{{.*}} + llvm.mlir.global external @_QMtest_0Ezii() {addr_space = 0 : i32, omp.declare_target = #omp.declaretarget} : !llvm.array<11 x f32> { + %0 = llvm.mlir.zero : !llvm.array<11 x f32> + llvm.return %0 : !llvm.array<11 x f32> + } + + // CHECK-DAG: %[[BASEPTR:.*]] = getelementptr inbounds [1 x ptr], ptr %.offload_baseptrs, i32 0, i32 0 + // CHECK-DAG: store ptr @_QMtest_0Ezii, ptr %[[BASEPTR]], align 8 + // CHECK-DAG: %[[OFFLOADPTR:.*]] = getelementptr inbounds [1 x ptr], ptr %.offload_ptrs, i32 0, i32 0 + // CHECK-DAG: store ptr @_QMtest_0Ezii, ptr %[[OFFLOADPTR]], align 8 + llvm.func @_QQmain() { + %0 = llvm.mlir.constant(1 : index) : i64 + %1 = llvm.mlir.constant(0 : index) : i64 + %2 = llvm.mlir.constant(11 : index) : i64 + %3 = llvm.mlir.addressof @_QMtest_0Ezii : !llvm.ptr + %4 = omp.map.bounds lower_bound(%1 : i64) upper_bound(%2 : i64) extent(%2 : i64) stride(%0 : i64) start_idx(%1 : i64) {stride_in_bytes = true} + %5 = omp.map.info var_ptr(%3 : !llvm.ptr, !llvm.array<11 x f32>) map_clauses(tofrom) capture(ByRef) bounds(%4) -> !llvm.ptr + omp.target map_entries(%5 -> %arg0 : !llvm.ptr) { + %6 = llvm.mlir.constant(1.0 : f32) : f32 + %7 = llvm.mlir.constant(0 : i64) : i64 + %8 = llvm.getelementptr %arg0[%7] : (!llvm.ptr, i64) -> !llvm.ptr, f32 + llvm.store %6, %8 : f32, !llvm.ptr + omp.terminator + } + llvm.return + } + // CHEKC-DAG: !{{.*}} = !{i32 {{.*}}, !"_QMtest_0Ezii", i32 {{.*}}, i32 {{.*}}} +} diff --git a/mlir/test/Target/LLVMIR/omptarget-nowait.mlir b/mlir/test/Target/LLVMIR/omptarget-nowait.mlir index 19333c44322f1..a96756f468df3 100644 --- a/mlir/test/Target/LLVMIR/omptarget-nowait.mlir +++ b/mlir/test/Target/LLVMIR/omptarget-nowait.mlir @@ -25,34 +25,33 @@ module attributes {omp.target_triples = ["amdgcn-amd-amdhsa"]} { // CHECK: %struct.[[TSK_WTH_PRVTS:.*]] = type { %struct.kmp_task_ompbuilder_t, %struct.[[PRVTS:.*]] } // CHECK: %struct.kmp_task_ompbuilder_t = type { ptr, ptr, i32, ptr, ptr } -// CHECK: %struct.[[PRVTS]] = type { [5 x ptr], [5 x ptr], [5 x i64] } +// CHECK: %struct.[[PRVTS]] = type { [6 x ptr], [6 x ptr], [6 x i64] } // CHECK: define void @launch_(ptr captures(none) %0) // CHECK: %[[STRUCTARG:.*]] = alloca { ptr, ptr }, align 8 -// CHECK: %[[BASEPTRS:.*]] = alloca [5 x ptr], align 8 -// CHECK: %[[PTRS:.*]] = alloca [5 x ptr], align 8 -// CHECK: %[[MAPPERS:.*]] = alloca [5 x ptr], align 8 -// CHECK: %[[SIZES:.*]] = alloca [5 x i64], align 4 +// CHECK: %[[BASEPTRS:.*]] = alloca [6 x ptr], align 8 +// CHECK: %[[PTRS:.*]] = alloca [6 x ptr], align 8 +// CHECK: %[[MAPPERS:.*]] = alloca [6 x ptr], align 8 +// CHECK: %[[SIZES:.*]] = alloca [6 x i64], align 4 - -// CHECK: %[[VAL_20:.*]] = getelementptr inbounds [5 x ptr], ptr %[[BASEPTRS]], i32 0, i32 0 -// CHECK: %[[BASEPTRS_GEP:.*]] = getelementptr inbounds [5 x ptr], ptr %[[BASEPTRS]], i32 0, i32 0 -// CHECK: %[[PTRS_GEP:.*]] = getelementptr inbounds [5 x ptr], ptr %[[PTRS]], i32 0, i32 0 -// CHECK: %[[SIZES_GEP:.*]] = getelementptr inbounds [5 x i64], ptr %[[SIZES]], i32 0, i32 0 +// CHECK: %[[VAL_20:.*]] = getelementptr inbounds [6 x ptr], ptr %[[BASEPTRS]], i32 0, i32 0 +// CHECK: %[[BASEPTRS_GEP:.*]] = getelementptr inbounds [6 x ptr], ptr %[[BASEPTRS]], i32 0, i32 0 +// CHECK: %[[PTRS_GEP:.*]] = getelementptr inbounds [6 x ptr], ptr %[[PTRS]], i32 0, i32 0 +// CHECK: %[[SIZES_GEP:.*]] = getelementptr inbounds [6 x i64], ptr %[[SIZES]], i32 0, i32 0 // CHECK: %[[GL_THRD_NUM:.*]] = call i32 @__kmpc_global_thread_num -// CHECK: %[[TASK_DESC:.*]] = call ptr @__kmpc_omp_target_task_alloc(ptr @4, i32 {{.*}}, i32 0, i64 160, i64 16, ptr [[TGT_TSK_PRXY_FNC:.*]], i64 -1) +// CHECK: %[[TASK_DESC:.*]] = call ptr @__kmpc_omp_target_task_alloc(ptr @4, i32 {{.*}}, i32 0, i64 184, i64 16, ptr [[TGT_TSK_PRXY_FNC:.*]], i64 -1) // CHECK: %[[TSK_PTR:.*]] = getelementptr inbounds nuw %struct.[[TSK_WTH_PRVTS]], ptr %[[TASK_DESC]], i32 0, i32 0 // CHECK: %[[SHAREDS:.*]] = getelementptr inbounds nuw %struct.kmp_task_ompbuilder_t, ptr %[[TSK_PTR]], i32 0, i32 0 // CHECK: %[[SHAREDS_PTR:.*]] = load ptr, ptr %[[SHAREDS]], align 8 // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 1 %[[SHAREDS_PTR]], ptr align 1 %[[STRUCTARG]], i64 16, i1 false) // CHECK: %[[VAL_50:.*]] = getelementptr inbounds nuw %struct.[[TSK_WTH_PRVTS]], ptr %[[TASK_DESC]], i32 0, i32 1 // CHECK: %[[VAL_51:.*]] = getelementptr inbounds nuw %struct.[[PRVTS]], ptr %[[VAL_50]], i32 0, i32 0 -// CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 1 %[[VAL_51]], ptr align 1 %[[BASEPTRS_GEP]], i64 40, i1 false) +// CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 1 %[[VAL_51]], ptr align 1 %[[BASEPTRS_GEP]], i64 48, i1 false) // CHECK: %[[VAL_53:.*]] = getelementptr inbounds nuw %struct.[[PRVTS]], ptr %[[VAL_50]], i32 0, i32 1 -// CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 1 %[[VAL_53]], ptr align 1 %[[PTRS_GEP]], i64 40, i1 false) +// CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 1 %[[VAL_53]], ptr align 1 %[[PTRS_GEP]], i64 48, i1 false) // CHECK: %[[VAL_54:.*]] = getelementptr inbounds nuw %struct.[[PRVTS]], ptr %[[VAL_50]], i32 0, i32 2 -// CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 1 %[[VAL_54]], ptr align 1 %[[SIZES_GEP]], i64 40, i1 false) +// CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 1 %[[VAL_54]], ptr align 1 %[[SIZES_GEP]], i64 48, i1 false) // CHECK: %[[VAL_55:.*]] = call i32 @__kmpc_omp_task(ptr @4, i32 %[[GL_THRD_NUM]], ptr %[[TASK_DESC]]) // CHECK: define internal void @[[WORKER:.*]](i32 {{.*}}, ptr {{.*}}, ptr {{.*}}, ptr {{.*}}, ptr {{.*}}) { diff --git a/mlir/test/Target/LLVMIR/omptarget-overlapping-record-member-map.mlir b/mlir/test/Target/LLVMIR/omptarget-overlapping-record-member-map.mlir new file mode 100644 index 0000000000000..1e9369f9f8f2f --- /dev/null +++ b/mlir/test/Target/LLVMIR/omptarget-overlapping-record-member-map.mlir @@ -0,0 +1,65 @@ +// RUN: mlir-translate -mlir-to-llvmir %s | FileCheck %s + +module attributes {llvm.target_triple = "x86_64-unknown-linux-gnu", omp.is_gpu = false, omp.is_target_device = false, omp.target_triples = ["amdgcn-amd-amdhsa"]} { + llvm.func @_QQmain() attributes {fir.bindc_name = "main"} { + %0 = llvm.mlir.constant(1 : i64) : i64 + %1 = llvm.alloca %0 x !llvm.struct<"_QFTdtype", (f32, i32)> {bindc_name = "dtypev"} : (i64) -> !llvm.ptr + %2 = llvm.getelementptr %1[0, 1] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"_QFTdtype", (f32, i32)> + %3 = omp.map.info var_ptr(%2 : !llvm.ptr, i32) map_clauses(tofrom) capture(ByRef) -> !llvm.ptr {name = "dtypev%value2"} + %4 = omp.map.info var_ptr(%1 : !llvm.ptr, !llvm.struct<"_QFTdtype", (f32, i32)>) map_clauses(to) capture(ByRef) members(%3 : [1] : !llvm.ptr) -> !llvm.ptr {name = "dtypev"} + omp.target map_entries(%4 -> %arg0, %3 -> %arg1 : !llvm.ptr, !llvm.ptr) { + omp.terminator + } + llvm.return + } +} + +// CHECK: @.offload_sizes = private unnamed_addr constant [4 x i64] [i64 0, i64 0, i64 0, i64 4] +// CHECK: @.offload_maptypes = private unnamed_addr constant [4 x i64] [i64 32, i64 281474976710657, i64 281474976710657, i64 281474976710659] + +// CHECK: %[[ALLOCA:.*]] = alloca %_QFTdtype, i64 1, align 8 +// CHECK: %[[ELEMENT_ACC:.*]] = getelementptr %_QFTdtype, ptr %[[ALLOCA]], i32 0, i32 1 + +// CHECK: %[[SIZE1_CALC_1:.*]] = getelementptr %_QFTdtype, ptr %[[ALLOCA]], i32 1 +// CHECK: %[[SIZE1_CALC_2:.*]] = ptrtoint ptr %[[SIZE1_CALC_1]] to i64 +// CHECK: %[[SIZE1_CALC_3:.*]] = ptrtoint ptr %[[ALLOCA]] to i64 +// CHECK: %[[SIZE1_CALC_4:.*]] = sub i64 %[[SIZE1_CALC_2]], %[[SIZE1_CALC_3]] +// CHECK: %[[SIZE1_CALC_5:.*]] = sdiv exact i64 %[[SIZE1_CALC_4]], ptrtoint (ptr getelementptr (i8, ptr null, i32 1) to i64) + +// CHECK: %[[SIZE2_CALC_1:.*]] = getelementptr %_QFTdtype, ptr %[[ALLOCA]], i32 1 +// CHECK: %[[SIZE2_CALC_2:.*]] = ptrtoint ptr %[[ELEMENT_ACC]] to i64 +// CHECK: %[[SIZE2_CALC_3:.*]] = ptrtoint ptr %[[ALLOCA]] to i64 +// CHECK: %[[SIZE2_CALC_4:.*]] = sub i64 %[[SIZE2_CALC_2]], %[[SIZE2_CALC_3]] +// CHECK: %[[SIZE2_CALC_5:.*]] = sdiv exact i64 %[[SIZE2_CALC_4]], ptrtoint (ptr getelementptr (i8, ptr null, i32 1) to i64) + +// CHECK: %[[SIZE3_CALC_1:.*]] = getelementptr i32, ptr %[[ELEMENT_ACC]], i32 1 +// CHECK: %[[SIZE3_CALC_2:.*]] = ptrtoint ptr %[[SIZE2_CALC_1]] to i64 +// CHECK: %[[SIZE3_CALC_3:.*]] = ptrtoint ptr %[[SIZE3_CALC_1]] to i64 +// CHECK: %[[SIZE3_CALC_4:.*]] = sub i64 %[[SIZE3_CALC_2]], %[[SIZE3_CALC_3]] +// CHECK: %[[SIZE3_CALC_5:.*]] = sdiv exact i64 %[[SIZE3_CALC_4]], ptrtoint (ptr getelementptr (i8, ptr null, i32 1) to i64) + +// CHECK: %[[BASEPTR:.*]] = getelementptr inbounds [4 x ptr], ptr %.offload_baseptrs, i32 0, i32 0 +// CHECK: store ptr %[[ALLOCA]], ptr %[[BASEPTR]], align 8 +// CHECK: %[[PTRS:.*]] = getelementptr inbounds [4 x ptr], ptr %.offload_ptrs, i32 0, i32 0 +// CHECK: store ptr %[[ALLOCA]], ptr %[[PTRS]], align 8 +// CHECK: %[[SIZES:.*]] = getelementptr inbounds [4 x i64], ptr %.offload_sizes, i32 0, i32 0 +// CHECK: store i64 %[[SIZE1_CALC_5]], ptr %[[SIZES]], align 8 + +// CHECK: %[[BASEPTR:.*]] = getelementptr inbounds [4 x ptr], ptr %.offload_baseptrs, i32 0, i32 1 +// CHECK: store ptr %[[ALLOCA]], ptr %[[BASEPTR]], align 8 +// CHECK: %[[PTRS:.*]] = getelementptr inbounds [4 x ptr], ptr %.offload_ptrs, i32 0, i32 1 +// CHECK: store ptr %[[ALLOCA]], ptr %[[PTRS]], align 8 +// CHECK: %[[SIZES:.*]] = getelementptr inbounds [4 x i64], ptr %.offload_sizes, i32 0, i32 1 +// CHECK: store i64 %[[SIZE2_CALC_5]], ptr %[[SIZES]], align 8 + +// CHECK: %[[BASEPTR:.*]] = getelementptr inbounds [4 x ptr], ptr %.offload_baseptrs, i32 0, i32 2 +// CHECK: store ptr %[[ALLOCA]], ptr %[[BASEPTR]], align 8 +// CHECK: %[[PTRS:.*]] = getelementptr inbounds [4 x ptr], ptr %.offload_ptrs, i32 0, i32 2 +// CHECK: store ptr %13, ptr %[[PTRS]], align 8 +// CHECK: %[[SIZES:.*]] = getelementptr inbounds [4 x i64], ptr %.offload_sizes, i32 0, i32 2 +// CHECK: store i64 %[[SIZE3_CALC_5]], ptr %[[SIZES]], align 8 + +// CHECK: %[[BASEPTR:.*]] = getelementptr inbounds [4 x ptr], ptr %.offload_baseptrs, i32 0, i32 3 +// CHECK: store ptr %[[ALLOCA]], ptr %[[BASEPTR]], align 8 +// CHECK: %[[PTRS:.*]] = getelementptr inbounds [4 x ptr], ptr %.offload_ptrs, i32 0, i32 3 +// CHECK: store ptr %[[ELEMENT_ACC]], ptr %[[PTRS]], align 8 diff --git a/mlir/test/Target/LLVMIR/omptarget-record-type-with-ptr-member-host.mlir b/mlir/test/Target/LLVMIR/omptarget-record-type-with-ptr-member-host.mlir index 9640f03311af7..711b50aca4e5a 100644 --- a/mlir/test/Target/LLVMIR/omptarget-record-type-with-ptr-member-host.mlir +++ b/mlir/test/Target/LLVMIR/omptarget-record-type-with-ptr-member-host.mlir @@ -59,9 +59,9 @@ module attributes {omp.is_target_device = false, omp.target_triples = ["amdgcn-a // CHECK: @[[FULL_ARR_GLOB:.*]] = internal global { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] } undef // CHECK: @[[ARR_SECT_GLOB:.*]] = internal global { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] } undef -// CHECK: @.offload_sizes = private unnamed_addr constant [12 x i64] [i64 0, i64 48, i64 8, i64 0, i64 0, i64 48, i64 8, i64 0, i64 0, i64 24, i64 8, i64 0] -// CHECK: @.offload_maptypes = private unnamed_addr constant [12 x i64] [i64 32, i64 281474976710659, i64 281474976710659, i64 281474976710675, i64 32, i64 1407374883553283, i64 1407374883553283, i64 1407374883553299, i64 32, i64 2533274790395907, i64 2533274790395907, i64 2533274790395923] -// CHECK: @.offload_mapnames = private constant [12 x ptr] [ptr @{{.*}}, ptr @{{.*}}, ptr @{{.*}}, ptr @{{.*}}, ptr @{{.*}}, ptr @{{.*}}, ptr @{{.*}}, ptr @{{.*}}, ptr @{{.*}}, ptr @{{.*}}, ptr @{{.*}}, ptr @{{.*}}] +// CHECK: @.offload_sizes = private unnamed_addr constant [15 x i64] [i64 0, i64 0, i64 0, i64 8, i64 0, i64 0, i64 0, i64 0, i64 8, i64 0, i64 0, i64 0, i64 0, i64 8, i64 0] +// CHECK: @.offload_maptypes = private unnamed_addr constant [15 x i64] [i64 32, i64 281474976710659, i64 281474976710659, i64 281474976710659, i64 281474976710675, i64 32, i64 1688849860263939, i64 1688849860263939, i64 1688849860263939, i64 1688849860263955, i64 32, i64 3096224743817219, i64 3096224743817219, i64 3096224743817219, i64 3096224743817235] +// CHECK: @.offload_mapnames = private constant [15 x ptr] [ptr @{{.*}}, ptr @{{.*}}, ptr @{{.*}}, ptr @{{.*}}, ptr @{{.*}}, ptr @{{.*}}, ptr @{{.*}}, ptr @{{.*}}, ptr @{{.*}}, ptr @{{.*}}, ptr @{{.*}}, ptr @{{.*}}, ptr @{{.*}}, ptr @{{.*}}, ptr @{{.*}}] // CHECK: define void @main() // CHECK: %[[SCALAR_ALLOCA:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8 }, i64 1, align 8 @@ -85,74 +85,97 @@ module attributes {omp.is_target_device = false, omp.target_triples = ["amdgcn-a // CHECK: %[[ARR_SECT_PTR:.*]] = getelementptr inbounds i32, ptr %[[LARR_SECT]], i64 %[[ARR_SECT_OFFSET2]] // CHECK: %[[SCALAR_PTR_LOAD:.*]] = load ptr, ptr %[[SCALAR_BASE]], align 8 // CHECK: %[[FULL_ARR_DESC_SIZE:.*]] = sdiv exact i64 48, ptrtoint (ptr getelementptr (i8, ptr null, i32 1) to i64) -// CHECK: %[[FULL_ARR_SIZE_CMP:.*]] = icmp eq ptr %[[FULL_ARR_PTR]], null -// CHECK: %[[FULL_ARR_SIZE_SEL:.*]] = select i1 %[[FULL_ARR_SIZE_CMP]], i64 0, i64 %[[FULL_ARR_SIZE]] +// CHECK: %[[FULL_ARR_SZ:.*]] = sdiv exact i64 40, ptrtoint (ptr getelementptr (i8, ptr null, i32 1) to i64) +// CHECK: %[[NULL_CMP:.*]] = icmp eq ptr %[[FULL_ARR_PTR]], null +// CHECK: %[[IS_NULL:.*]] = select i1 %[[NULL_CMP]], i64 0, i64 %[[FULL_ARR_SIZE]] // CHECK: %[[ARR_SECT_DESC_SIZE:.*]] = sdiv exact i64 48, ptrtoint (ptr getelementptr (i8, ptr null, i32 1) to i64) -// CHECK: %[[ARR_SECT_SIZE_CMP:.*]] = icmp eq ptr %[[ARR_SECT_PTR]], null -// CHECK: %[[ARR_SECT_SIZE_SEL:.*]] = select i1 %[[ARR_SECT_SIZE_CMP]], i64 0, i64 %[[ARR_SECT_SIZE]] +// CHECK: %[[ARR_SECT_SZ:.*]] = sdiv exact i64 40, ptrtoint (ptr getelementptr (i8, ptr null, i32 1) to i64) +// CHECK: %[[NULL_CMP2:.*]] = icmp eq ptr %[[ARR_SECT_PTR]], null +// CHECK: %[[IS_NULL2:.*]] = select i1 %[[NULL_CMP2]], i64 0, i64 %[[ARR_SECT_SIZE]] // CHECK: %[[SCALAR_DESC_SZ4:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8 }, ptr %[[SCALAR_ALLOCA]], i32 1 // CHECK: %[[SCALAR_DESC_SZ3:.*]] = ptrtoint ptr %[[SCALAR_DESC_SZ4]] to i64 // CHECK: %[[SCALAR_DESC_SZ2:.*]] = ptrtoint ptr %[[SCALAR_ALLOCA]] to i64 // CHECK: %[[SCALAR_DESC_SZ1:.*]] = sub i64 %[[SCALAR_DESC_SZ3]], %[[SCALAR_DESC_SZ2]] // CHECK: %[[SCALAR_DESC_SZ:.*]] = sdiv exact i64 %[[SCALAR_DESC_SZ1]], ptrtoint (ptr getelementptr (i8, ptr null, i32 1) to i64) - -// CHECK: %[[OFFLOADBASEPTRS:.*]] = getelementptr inbounds [12 x ptr], ptr %.offload_baseptrs, i32 0, i32 0 +// CHECK: %[[SCALAR_BASE_2:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8 }, ptr %[[SCALAR_ALLOCA]], i32 1 +// CHECK: %[[SCALAR_BASE_OFF:.*]] = getelementptr ptr, ptr %[[SCALAR_BASE]], i32 1 +// CHECK: %[[SCALAR_BASE_OFF_SZ1:.*]] = ptrtoint ptr %[[SCALAR_BASE_2]] to i64 +// CHECK: %[[SCALAR_BASE_OFF_SZ2:.*]] = ptrtoint ptr %[[SCALAR_BASE_OFF]] to i64 +// CHECK: %[[SCALAR_BASE_OFF_SZ3:.*]] = sub i64 %[[SCALAR_BASE_OFF_SZ1]], %[[SCALAR_BASE_OFF_SZ2]] +// CHECK: %[[SCALAR_BASE_OFF_SZ4:.*]] = sdiv exact i64 %[[SCALAR_BASE_OFF_SZ3]], ptrtoint (ptr getelementptr (i8, ptr null, i32 1) to i64) +// CHECK: %[[OFFLOADBASEPTRS:.*]] = getelementptr inbounds [15 x ptr], ptr %.offload_baseptrs, i32 0, i32 0 // CHECK: store ptr @full_arr, ptr %[[OFFLOADBASEPTRS]], align 8 -// CHECK: %[[OFFLOADPTRS:.*]] = getelementptr inbounds [12 x ptr], ptr %.offload_ptrs, i32 0, i32 0 +// CHECK: %[[OFFLOADPTRS:.*]] = getelementptr inbounds [15 x ptr], ptr %.offload_ptrs, i32 0, i32 0 // CHECK: store ptr @full_arr, ptr %[[OFFLOADPTRS]], align 8 -// CHECK: %[[OFFLOADSIZES:.*]] = getelementptr inbounds [12 x i64], ptr %.offload_sizes, i32 0, i32 0 +// CHECK: %[[OFFLOADSIZES:.*]] = getelementptr inbounds [15 x i64], ptr %.offload_sizes, i32 0, i32 0 // CHECK: store i64 %[[FULL_ARR_DESC_SIZE]], ptr %[[OFFLOADSIZES]], align 8 -// CHECK: %[[OFFLOADBASEPTRS:.*]] = getelementptr inbounds [12 x ptr], ptr %.offload_baseptrs, i32 0, i32 1 +// CHECK: %[[OFFLOADBASEPTRS:.*]] = getelementptr inbounds [15 x ptr], ptr %.offload_baseptrs, i32 0, i32 1 // CHECK: store ptr @full_arr, ptr %[[OFFLOADBASEPTRS]], align 8 -// CHECK: %[[OFFLOADPTRS:.*]] = getelementptr inbounds [12 x ptr], ptr %.offload_ptrs, i32 0, i32 1 +// CHECK: %[[OFFLOADPTRS:.*]] = getelementptr inbounds [15 x ptr], ptr %.offload_ptrs, i32 0, i32 1 // CHECK: store ptr @full_arr, ptr %[[OFFLOADPTRS]], align 8 -// CHECK: %[[OFFLOADBASEPTRS:.*]] = getelementptr inbounds [12 x ptr], ptr %.offload_baseptrs, i32 0, i32 2 +// CHECK: %[[OFFLOADBASEPTRS:.*]] = getelementptr inbounds [15 x ptr], ptr %.offload_baseptrs, i32 0, i32 2 +// CHECK: store ptr @full_arr, ptr %[[OFFLOADBASEPTRS]], align 8 +// CHECK: %[[OFFLOADPTRS:.*]] = getelementptr inbounds [15 x ptr], ptr %.offload_ptrs, i32 0, i32 2 +// CHECK: store ptr getelementptr inbounds nuw (i8, ptr @full_arr, i64 8), ptr %[[OFFLOADPTRS]], align 8 +// CHECK: %[[OFFLOADSIZES:.*]] = getelementptr inbounds [15 x i64], ptr %.offload_sizes, i32 0, i32 2 +// CHECK: store i64 %[[FULL_ARR_SZ]], ptr %[[OFFLOADSIZES]], align 8 +// CHECK: %[[OFFLOADBASEPTRS:.*]] = getelementptr inbounds [15 x ptr], ptr %.offload_baseptrs, i32 0, i32 3 // CHECK: store ptr @full_arr, ptr %[[OFFLOADBASEPTRS]], align 8 -// CHECK: %[[OFFLOADPTRS:.*]] = getelementptr inbounds [12 x ptr], ptr %.offload_ptrs, i32 0, i32 2 +// CHECK: %[[OFFLOADPTRS:.*]] = getelementptr inbounds [15 x ptr], ptr %.offload_ptrs, i32 0, i32 3 // CHECK: store ptr @full_arr, ptr %[[OFFLOADPTRS]], align 8 -// CHECK: %[[OFFLOADBASEPTRS:.*]] = getelementptr inbounds [12 x ptr], ptr %.offload_baseptrs, i32 0, i32 3 +// CHECK: %[[OFFLOADBASEPTRS:.*]] = getelementptr inbounds [15 x ptr], ptr %.offload_baseptrs, i32 0, i32 4 // CHECK: store ptr @full_arr, ptr %[[OFFLOADBASEPTRS]], align 8 -// CHECK: %[[OFFLOADPTRS:.*]] = getelementptr inbounds [12 x ptr], ptr %.offload_ptrs, i32 0, i32 3 +// CHECK: %[[OFFLOADPTRS:.*]] = getelementptr inbounds [15 x ptr], ptr %.offload_ptrs, i32 0, i32 4 // CHECK: store ptr %[[FULL_ARR_PTR]], ptr %[[OFFLOADPTRS]], align 8 -// CHECK: %[[OFFLOADSIZES:.*]] = getelementptr inbounds [12 x i64], ptr %.offload_sizes, i32 0, i32 3 -// CHECK: store i64 %[[FULL_ARR_SIZE_SEL]], ptr %[[OFFLOADSIZES]], align 8 - -// CHECK: %[[OFFLOADBASEPTRS:.*]] = getelementptr inbounds [12 x ptr], ptr %.offload_baseptrs, i32 0, i32 4 +// CHECK: %[[OFFLOADSIZES:.*]] = getelementptr inbounds [15 x i64], ptr %.offload_sizes, i32 0, i32 4 +// CHECK: store i64 %[[IS_NULL]], ptr %[[OFFLOADSIZES]], align 8 +// CHECK: %[[OFFLOADBASEPTRS:.*]] = getelementptr inbounds [15 x ptr], ptr %.offload_baseptrs, i32 0, i32 5 // CHECK: store ptr @sect_arr, ptr %[[OFFLOADBASEPTRS]], align 8 -// CHECK: %[[OFFLOADPTRS:.*]] = getelementptr inbounds [12 x ptr], ptr %.offload_ptrs, i32 0, i32 4 +// CHECK: %[[OFFLOADPTRS:.*]] = getelementptr inbounds [15 x ptr], ptr %.offload_ptrs, i32 0, i32 5 // CHECK: store ptr @sect_arr, ptr %[[OFFLOADPTRS]], align 8 -// CHECK: %[[OFFLOADSIZES:.*]] = getelementptr inbounds [12 x i64], ptr %.offload_sizes, i32 0, i32 4 +// CHECK: %[[OFFLOADSIZES:.*]] = getelementptr inbounds [15 x i64], ptr %.offload_sizes, i32 0, i32 5 // CHECK: store i64 %[[ARR_SECT_DESC_SIZE]], ptr %[[OFFLOADSIZES]], align 8 -// CHECK: %[[OFFLOADBASEPTRS:.*]] = getelementptr inbounds [12 x ptr], ptr %.offload_baseptrs, i32 0, i32 5 +// CHECK: %[[OFFLOADBASEPTRS:.*]] = getelementptr inbounds [15 x ptr], ptr %.offload_baseptrs, i32 0, i32 6 // CHECK: store ptr @sect_arr, ptr %[[OFFLOADBASEPTRS]], align 8 -// CHECK: %[[OFFLOADPTRS:.*]] = getelementptr inbounds [12 x ptr], ptr %.offload_ptrs, i32 0, i32 5 +// CHECK: %[[OFFLOADPTRS:.*]] = getelementptr inbounds [15 x ptr], ptr %.offload_ptrs, i32 0, i32 6 // CHECK: store ptr @sect_arr, ptr %[[OFFLOADPTRS]], align 8 -// CHECK: %[[OFFLOADBASEPTRS:.*]] = getelementptr inbounds [12 x ptr], ptr %.offload_baseptrs, i32 0, i32 6 +// CHECK: %[[OFFLOADBASEPTRS:.*]] = getelementptr inbounds [15 x ptr], ptr %.offload_baseptrs, i32 0, i32 7 // CHECK: store ptr @sect_arr, ptr %[[OFFLOADBASEPTRS]], align 8 -// CHECK: %[[OFFLOADPTRS:.*]] = getelementptr inbounds [12 x ptr], ptr %.offload_ptrs, i32 0, i32 6 +// CHECK: %[[OFFLOADPTRS:.*]] = getelementptr inbounds [15 x ptr], ptr %.offload_ptrs, i32 0, i32 7 +// CHECK: store ptr getelementptr inbounds nuw (i8, ptr @sect_arr, i64 8), ptr %[[OFFLOADPTRS]], align 8 +// CHECK: %[[OFFLOADSIZES:.*]] = getelementptr inbounds [15 x i64], ptr %.offload_sizes, i32 0, i32 7 +// CHECK: store i64 %[[ARR_SECT_SZ]], ptr %[[OFFLOADSIZES]], align 8 +// CHECK: %[[OFFLOADBASEPTRS:.*]] = getelementptr inbounds [15 x ptr], ptr %.offload_baseptrs, i32 0, i32 8 +// CHECK: store ptr @sect_arr, ptr %[[OFFLOADBASEPTRS]], align 8 +// CHECK: %[[OFFLOADPTRS:.*]] = getelementptr inbounds [15 x ptr], ptr %.offload_ptrs, i32 0, i32 8 // CHECK: store ptr @sect_arr, ptr %[[OFFLOADPTRS]], align 8 -// CHECK: %[[OFFLOADBASEPTRS:.*]] = getelementptr inbounds [12 x ptr], ptr %.offload_baseptrs, i32 0, i32 7 +// CHECK: %[[OFFLOADBASEPTRS:.*]] = getelementptr inbounds [15 x ptr], ptr %.offload_baseptrs, i32 0, i32 9 // CHECK: store ptr @sect_arr, ptr %[[OFFLOADBASEPTRS]], align 8 -// CHECK: %[[OFFLOADPTRS:.*]] = getelementptr inbounds [12 x ptr], ptr %.offload_ptrs, i32 0, i32 7 +// CHECK: %[[OFFLOADPTRS:.*]] = getelementptr inbounds [15 x ptr], ptr %.offload_ptrs, i32 0, i32 9 // CHECK: store ptr %[[ARR_SECT_PTR]], ptr %[[OFFLOADPTRS]], align 8 -// CHECK: %[[OFFLOADSIZES:.*]] = getelementptr inbounds [12 x i64], ptr %.offload_sizes, i32 0, i32 7 -// CHECK: store i64 %[[ARR_SECT_SIZE_SEL]], ptr %[[OFFLOADSIZES]], align 8 - -// CHECK: %[[OFFLOADBASEPTRS:.*]] = getelementptr inbounds [12 x ptr], ptr %.offload_baseptrs, i32 0, i32 8 +// CHECK: %[[OFFLOADSIZES:.*]] = getelementptr inbounds [15 x i64], ptr %.offload_sizes, i32 0, i32 9 +// CHECK: store i64 %[[IS_NULL2]], ptr %[[OFFLOADSIZES]], align 8 +// CHECK: %[[OFFLOADBASEPTRS:.*]] = getelementptr inbounds [15 x ptr], ptr %.offload_baseptrs, i32 0, i32 10 // CHECK: store ptr %[[SCALAR_ALLOCA]], ptr %[[OFFLOADBASEPTRS]], align 8 -// CHECK: %[[OFFLOADPTRS:.*]] = getelementptr inbounds [12 x ptr], ptr %.offload_ptrs, i32 0, i32 8 +// CHECK: %[[OFFLOADPTRS:.*]] = getelementptr inbounds [15 x ptr], ptr %.offload_ptrs, i32 0, i32 10 // CHECK: store ptr %[[SCALAR_ALLOCA]], ptr %[[OFFLOADPTRS]], align 8 -// CHECK: %[[OFFLOADSIZES:.*]] = getelementptr inbounds [12 x i64], ptr %.offload_sizes, i32 0, i32 8 +// CHECK: %[[OFFLOADSIZES:.*]] = getelementptr inbounds [15 x i64], ptr %.offload_sizes, i32 0, i32 10 // CHECK: store i64 %[[SCALAR_DESC_SZ]], ptr %[[OFFLOADSIZES]], align 8 -// CHECK: %[[OFFLOADBASEPTRS:.*]] = getelementptr inbounds [12 x ptr], ptr %.offload_baseptrs, i32 0, i32 9 +// CHECK: %[[OFFLOADBASEPTRS:.*]] = getelementptr inbounds [15 x ptr], ptr %.offload_baseptrs, i32 0, i32 11 // CHECK: store ptr %[[SCALAR_ALLOCA]], ptr %[[OFFLOADBASEPTRS]], align 8 -// CHECK: %[[OFFLOADPTRS:.*]] = getelementptr inbounds [12 x ptr], ptr %.offload_ptrs, i32 0, i32 9 +// CHECK: %[[OFFLOADPTRS:.*]] = getelementptr inbounds [15 x ptr], ptr %.offload_ptrs, i32 0, i32 11 // CHECK: store ptr %[[SCALAR_ALLOCA]], ptr %[[OFFLOADPTRS]], align 8 -// CHECK: %[[OFFLOADBASEPTRS:.*]] = getelementptr inbounds [12 x ptr], ptr %.offload_baseptrs, i32 0, i32 10 +// CHECK: %[[OFFLOADBASEPTRS:.*]] = getelementptr inbounds [15 x ptr], ptr %.offload_baseptrs, i32 0, i32 12 +// CHECK: store ptr %[[SCALAR_ALLOCA]], ptr %[[OFFLOADBASEPTRS]], align 8 +// CHECK: %[[OFFLOADPTRS:.*]] = getelementptr inbounds [15 x ptr], ptr %.offload_ptrs, i32 0, i32 12 +// CHECK: store ptr %[[SCALAR_BASE_OFF]], ptr %[[OFFLOADPTRS]], align 8 +// CHECK: %[[OFFLOADSIZES:.*]] = getelementptr inbounds [15 x i64], ptr %.offload_sizes, i32 0, i32 12 +// CHECK: store i64 %[[SCALAR_BASE_OFF_SZ4]], ptr %[[OFFLOADSIZES]], align 8 +// CHECK: %[[OFFLOADBASEPTRS:.*]] = getelementptr inbounds [15 x ptr], ptr %.offload_baseptrs, i32 0, i32 13 // CHECK: store ptr %[[SCALAR_ALLOCA]], ptr %[[OFFLOADBASEPTRS]], align 8 -// CHECK: %[[OFFLOADPTRS:.*]] = getelementptr inbounds [12 x ptr], ptr %.offload_ptrs, i32 0, i32 10 +// CHECK: %[[OFFLOADPTRS:.*]] = getelementptr inbounds [15 x ptr], ptr %.offload_ptrs, i32 0, i32 13 // CHECK: store ptr %[[SCALAR_BASE]], ptr %[[OFFLOADPTRS]], align 8 -// CHECK: %[[OFFLOADBASEPTRS:.*]] = getelementptr inbounds [12 x ptr], ptr %.offload_baseptrs, i32 0, i32 11 +// CHECK: %[[OFFLOADBASEPTRS:.*]] = getelementptr inbounds [15 x ptr], ptr %.offload_baseptrs, i32 0, i32 14 // CHECK: store ptr %[[SCALAR_BASE]], ptr %[[OFFLOADBASEPTRS]], align 8 -// CHECK: %[[OFFLOADPTRS:.*]] = getelementptr inbounds [12 x ptr], ptr %.offload_ptrs, i32 0, i32 11 +// CHECK: %[[OFFLOADPTRS:.*]] = getelementptr inbounds [15 x ptr], ptr %.offload_ptrs, i32 0, i32 14 // CHECK: store ptr %[[SCALAR_PTR_LOAD]], ptr %[[OFFLOADPTRS]], align 8 diff --git a/offload/test/offloading/fortran/dtype-member-overlap-map.f90 b/offload/test/offloading/fortran/dtype-member-overlap-map.f90 new file mode 100644 index 0000000000000..e45701441a0f7 --- /dev/null +++ b/offload/test/offloading/fortran/dtype-member-overlap-map.f90 @@ -0,0 +1,56 @@ +! Basic offloading test checking the interaction of an overlapping +! member map. +! REQUIRES: flang, amdgpu + +! RUN: %libomptarget-compile-fortran-run-and-check-generic +program main + implicit none + integer :: i + + type dtype2 + integer :: int + real :: float + end type dtype2 + + type dtype1 + character (LEN=30) :: characters + type(dtype2) :: internal_dtype2 + end type dtype1 + + type dtype + integer :: elements(10) + type(dtype1) :: internal_dtype + integer :: value + end type dtype + + type (dtype) :: single_dtype + + do i = 1, 10 + single_dtype%elements(i) = 0 + end do + + !$omp target map(tofrom: single_dtype%internal_dtype, single_dtype%internal_dtype%internal_dtype2%int) + single_dtype%internal_dtype%internal_dtype2%int = 123 + single_dtype%internal_dtype%characters(1:1) = "Z" + !$omp end target + + !$omp target map(to: single_dtype) map(tofrom: single_dtype%internal_dtype%internal_dtype2, single_dtype%value) + single_dtype%value = 20 + do i = 1, 10 + single_dtype%elements(i) = i + end do + single_dtype%internal_dtype%internal_dtype2%float = 32.0 + !$omp end target + + print *, single_dtype%value + print *, single_dtype%internal_dtype%internal_dtype2%float + print *, single_dtype%elements + print *, single_dtype%internal_dtype%internal_dtype2%int + print *, single_dtype%internal_dtype%characters(1:1) +end program main + +! CHECK: 20 +! CHECK: 32. +! CHECK: 0 0 0 0 0 0 0 0 0 0 +! CHECK: 123 +! CHECK: Z From 173600880b8f469ad9ae8da757bdc94959690ffa Mon Sep 17 00:00:00 2001 From: agozillon Date: Mon, 24 Nov 2025 21:22:49 +0100 Subject: [PATCH 09/50] [Flang][OpenMP][MLIR] Initial declare target to for variables implementation (#119589) While the infrastructure for declare target to/enter and link for variables exists in the MLIR dialect and at the Flang level, the current lowering from MLIR -> LLVM IR isn't in place, it's only in place for variables that have the link clause applied. This PR aims to extend that lowering to an initial implementation that incorporates declare target to as well, which primarily requires changes in the OpenMPToLLVMIRTranslation phase. However, a minor addition to the OpenMP dialect was required to extend the declare target enumerator to include a default None field as well. This also requires a minor change to the Flang lowering's MapInfoFinlization.cpp pass to alter the map type for descriptors to deal with cases where a variable is marked declare to. Currently, when a descriptor variable is mapped declare target to the descriptor component can become attatched, and cannot be updated, this results in issues when an unusual allocation range is specified (effectively an off-by X error). The current solution is to map the descriptor always, as we always require an up-to-date version of this data. However, this also requires an interlinked PR that adds a more intricate type of mapping of structures/record types that clang currently implements, to circumvent the overwriting of the pointer in the descriptor. 3/3 required PRs to enable declare target to mapping, this PR should pass all tests and provide an all green CI. Co-authored-by: Raghu Maddhipatla raghu.maddhipatla@amd.com --- .../Optimizer/OpenMP/MapInfoFinalization.cpp | 14 ++ .../target-private-allocatable.f90 | 2 +- ...rget-teams-private-implicit-scalar-map.f90 | 2 +- .../Lower/OpenMP/allocatable-array-bounds.f90 | 7 +- flang/test/Lower/OpenMP/allocatable-map.f90 | 2 +- flang/test/Lower/OpenMP/array-bounds.f90 | 2 +- flang/test/Lower/OpenMP/declare-mapper.f90 | 4 +- .../OpenMP/declare-target-link-tarop-cap.f90 | 4 +- flang/test/Lower/OpenMP/defaultmap.f90 | 6 +- .../OpenMP/derived-type-allocatable-map.f90 | 16 +- flang/test/Lower/OpenMP/derived-type-map.f90 | 2 +- flang/test/Lower/OpenMP/map-character.f90 | 4 +- .../Lower/OpenMP/map-descriptor-deferral.f90 | 14 +- .../map-neg-alloca-derived-type-array.f90 | 2 +- .../Lower/OpenMP/optional-argument-map-2.f90 | 4 +- .../Lower/OpenMP/optional-argument-map-3.f90 | 4 +- .../target-enter-data-default-openmp52.f90 | 2 +- flang/test/Lower/OpenMP/target.f90 | 4 +- flang/test/Lower/volatile-openmp.f90 | 4 +- .../Transforms/omp-map-info-finalization.fir | 22 +- .../mlir/Dialect/OpenMP/OpenMPEnums.td | 8 +- .../OpenMP/OpenMPToLLVMIRTranslation.cpp | 231 +++++++++++------- .../omptarget-declare-target-to-device.mlir | 35 +++ ...allocatable-vars-in-target-with-update.f90 | 41 ++++ ...arget-to-vars-target-region-and-update.f90 | 40 +++ ...t-to-zero-index-allocatable-target-map.f90 | 30 +++ 26 files changed, 362 insertions(+), 144 deletions(-) create mode 100644 mlir/test/Target/LLVMIR/omptarget-declare-target-to-device.mlir create mode 100644 offload/test/offloading/fortran/declare-target-to-allocatable-vars-in-target-with-update.f90 create mode 100644 offload/test/offloading/fortran/declare-target-to-vars-target-region-and-update.f90 create mode 100644 offload/test/offloading/fortran/declare-target-to-zero-index-allocatable-target-map.f90 diff --git a/flang/lib/Optimizer/OpenMP/MapInfoFinalization.cpp b/flang/lib/Optimizer/OpenMP/MapInfoFinalization.cpp index dd4c9424f7c6f..3fe133d63d24d 100644 --- a/flang/lib/Optimizer/OpenMP/MapInfoFinalization.cpp +++ b/flang/lib/Optimizer/OpenMP/MapInfoFinalization.cpp @@ -437,6 +437,20 @@ class MapInfoFinalizationPass mapFlags flags = mapFlags::to | (mapTypeFlag & (mapFlags::implicit | mapFlags::always)); + + // Descriptors for objects will always be copied. This is because the + // descriptor can be rematerialized by the compiler, and so the address + // of the descriptor for a given object at one place in the code may + // differ from that address in another place. The contents of the + // descriptor (the base address in particular) will remain unchanged + // though. + // TODO/FIXME: We currently cannot have MAP_CLOSE and MAP_ALWAYS on + // the descriptor at once, these are mutually exclusive and when + // both are applied the runtime will fail to map. + flags |= ((mapFlags(mapTypeFlag) & mapFlags::close) == mapFlags::close) + ? mapFlags::close + : mapFlags::always; + // For unified_shared_memory, we additionally add `CLOSE` on the descriptor // to ensure device-local placement where required by tests relying on USM + // close semantics. diff --git a/flang/test/Lower/OpenMP/DelayedPrivatization/target-private-allocatable.f90 b/flang/test/Lower/OpenMP/DelayedPrivatization/target-private-allocatable.f90 index cfe42367b051b..e0fb56882c032 100644 --- a/flang/test/Lower/OpenMP/DelayedPrivatization/target-private-allocatable.f90 +++ b/flang/test/Lower/OpenMP/DelayedPrivatization/target-private-allocatable.f90 @@ -73,7 +73,7 @@ end subroutine target_allocatable ! CPU: %[[VAR_DECL:.*]]:2 = hlfir.declare %[[VAR_ALLOC]] ! CPU: %[[BASE_ADDR:.*]] = fir.box_offset %[[VAR_DECL]]#0 base_addr : (!fir.ref>>) -> [[MEMBER_TYPE:.*]] ! CPU: %[[MEMBER:.*]] = omp.map.info var_ptr(%[[VAR_DECL]]#0 : [[TYPE]], i32) map_clauses(tofrom) capture(ByRef) var_ptr_ptr(%[[BASE_ADDR]] : [[MEMBER_TYPE:.*]]) -> {{.*}} -! CPU: %[[MAP_VAR:.*]] = omp.map.info var_ptr(%[[VAR_DECL]]#0 : [[TYPE]], [[DESC_TYPE]]) map_clauses(to) capture(ByRef) members(%[[MEMBER]] : [0] : !fir.llvm_ptr>) -> !fir.ref>> +! CPU: %[[MAP_VAR:.*]] = omp.map.info var_ptr(%[[VAR_DECL]]#0 : [[TYPE]], [[DESC_TYPE]]) map_clauses(always, to) capture(ByRef) members(%[[MEMBER]] : [0] : !fir.llvm_ptr>) -> !fir.ref>> ! CPU: omp.target map_entries(%[[MAP_VAR]] -> %arg0, %[[MEMBER]] -> %arg1 : [[TYPE]], [[MEMBER_TYPE]]) private( ! CPU-SAME: @[[VAR_PRIVATIZER_SYM]] %[[VAR_DECL]]#0 -> %{{.*}} [map_idx=0] : [[TYPE]]) { diff --git a/flang/test/Lower/OpenMP/DelayedPrivatization/target-teams-private-implicit-scalar-map.f90 b/flang/test/Lower/OpenMP/DelayedPrivatization/target-teams-private-implicit-scalar-map.f90 index 126f341a58192..d476b4859a586 100644 --- a/flang/test/Lower/OpenMP/DelayedPrivatization/target-teams-private-implicit-scalar-map.f90 +++ b/flang/test/Lower/OpenMP/DelayedPrivatization/target-teams-private-implicit-scalar-map.f90 @@ -28,7 +28,7 @@ program test_default_implicit_firstprivate !CHECK: %[[VAL_9:.*]] = omp.map.info var_ptr(%[[VAL_4]] : !fir.ref, i32) map_clauses(implicit) capture(ByCopy) -> !fir.ref {name = "k"} !CHECK: %[[VAL_10:.*]] = fir.box_offset %[[VAL_0]] base_addr : (!fir.ref>>>) -> !fir.llvm_ptr>> !CHECK: %[[VAL_11:.*]] = omp.map.info var_ptr(%[[VAL_0]] : !fir.ref>>>, i32) map_clauses(implicit, tofrom) capture(ByRef) var_ptr_ptr(%[[VAL_10]] : !fir.llvm_ptr>>) bounds({{.*}}) -> !fir.llvm_ptr>> {name = ""} -!CHECK: %[[VAL_12:.*]] = omp.map.info var_ptr(%[[VAL_0]] : !fir.ref>>>, !fir.box>>) map_clauses(implicit, to) capture(ByRef) members(%[[VAL_11]] : [0] : !fir.llvm_ptr>>) -> !fir.ref>>> {name = "allocarr"} +!CHECK: %[[VAL_12:.*]] = omp.map.info var_ptr(%[[VAL_0]] : !fir.ref>>>, !fir.box>>) map_clauses(always, implicit, to) capture(ByRef) members(%[[VAL_11]] : [0] : !fir.llvm_ptr>>) -> !fir.ref>>> {name = "allocarr"} !CHECK: %[[VAL_13:.*]] = omp.map.info var_ptr(%[[VAL_1]] : !fir.ref>, !fir.array<10x10x10xi32>) map_clauses(implicit, tofrom) capture(ByRef) bounds({{.*}}) -> !fir.ref> {name = "arr"} !CHECK: %[[VAL_14:.*]] = omp.map.info var_ptr(%[[VAL_6]] : !fir.ref, i32) map_clauses(to) capture(ByCopy) -> !fir.ref !CHECK: %[[VAL_15:.*]] = omp.map.info var_ptr(%[[VAL_5]] : !fir.ref, i32) map_clauses(to) capture(ByCopy) -> !fir.ref diff --git a/flang/test/Lower/OpenMP/allocatable-array-bounds.f90 b/flang/test/Lower/OpenMP/allocatable-array-bounds.f90 index 465a07cb2baf6..0688f0ddc180d 100644 --- a/flang/test/Lower/OpenMP/allocatable-array-bounds.f90 +++ b/flang/test/Lower/OpenMP/allocatable-array-bounds.f90 @@ -24,7 +24,7 @@ !HOST: %[[BOUNDS_1:.*]] = omp.map.bounds lower_bound(%[[LB_1]] : index) upper_bound(%[[UB_1]] : index) extent(%[[BOX_3]]#1 : index) stride(%[[BOX_2]]#2 : index) start_idx(%[[BOX_1]]#0 : index) {stride_in_bytes = true} !HOST: %[[VAR_PTR_PTR:.*]] = fir.box_offset %[[DECLARE_1]]#1 base_addr : (!fir.ref>>>) -> !fir.llvm_ptr>> !HOST: %[[MAP_INFO_MEMBER:.*]] = omp.map.info var_ptr(%[[DECLARE_1]]#1 : !fir.ref>>>, i32) map_clauses(tofrom) capture(ByRef) var_ptr_ptr(%[[VAR_PTR_PTR]] : !fir.llvm_ptr>>) bounds(%[[BOUNDS_1]]) -> !fir.llvm_ptr>> {name = ""} -!HOST: %[[MAP_INFO_1:.*]] = omp.map.info var_ptr(%[[DECLARE_1]]#1 : !fir.ref>>>, !fir.box>>) map_clauses(to) capture(ByRef) members(%[[MAP_INFO_MEMBER]] : [0] : !fir.llvm_ptr>>) -> !fir.ref>>> {name = "sp_read(2:5)"} +!HOST: %[[MAP_INFO_1:.*]] = omp.map.info var_ptr(%[[DECLARE_1]]#1 : !fir.ref>>>, !fir.box>>) map_clauses(always, to) capture(ByRef) members(%[[MAP_INFO_MEMBER]] : [0] : !fir.llvm_ptr>>) -> !fir.ref>>> {name = "sp_read(2:5)"} !HOST: %[[LOAD_3:.*]] = fir.load %[[DECLARE_2]]#0 : !fir.ref>>> !HOST: %[[LOAD_4:.*]] = fir.load %[[DECLARE_2]]#0 : !fir.ref>>> @@ -42,7 +42,7 @@ !HOST: %[[BOUNDS_2:.*]] = omp.map.bounds lower_bound(%[[LB_2]] : index) upper_bound(%[[UB_2]] : index) extent(%[[BOX_5]]#1 : index) stride(%[[BOX_4]]#2 : index) start_idx(%[[BOX_3]]#0 : index) {stride_in_bytes = true} !HOST: %[[VAR_PTR_PTR:.*]] = fir.box_offset %[[DECLARE_2]]#1 base_addr : (!fir.ref>>>) -> !fir.llvm_ptr>> !HOST: %[[MAP_INFO_MEMBER:.*]] = omp.map.info var_ptr(%[[DECLARE_2]]#1 : !fir.ref>>>, i32) map_clauses(tofrom) capture(ByRef) var_ptr_ptr(%[[VAR_PTR_PTR]] : !fir.llvm_ptr>>) bounds(%[[BOUNDS_2]]) -> !fir.llvm_ptr>> {name = ""} -!HOST: %[[MAP_INFO_2:.*]] = omp.map.info var_ptr(%[[DECLARE_2]]#1 : !fir.ref>>>, !fir.box>>) map_clauses(to) capture(ByRef) members(%[[MAP_INFO_MEMBER]] : [0] : !fir.llvm_ptr>>) -> !fir.ref>>> {name = "sp_write(2:5)"} +!HOST: %[[MAP_INFO_2:.*]] = omp.map.info var_ptr(%[[DECLARE_2]]#1 : !fir.ref>>>, !fir.box>>) map_clauses(always, to) capture(ByRef) members(%[[MAP_INFO_MEMBER]] : [0] : !fir.llvm_ptr>>) -> !fir.ref>>> {name = "sp_write(2:5)"} subroutine read_write_section() integer, allocatable :: sp_read(:) @@ -81,8 +81,7 @@ module assumed_allocatable_array_routines !HOST: %[[BOUNDS:.*]] = omp.map.bounds lower_bound(%[[LB]] : index) upper_bound(%[[UB]] : index) extent(%[[BOX_3]]#1 : index) stride(%[[BOX_2]]#2 : index) start_idx(%[[BOX_1]]#0 : index) {stride_in_bytes = true} !HOST: %[[VAR_PTR_PTR:.*]] = fir.box_offset %[[DECLARE]]#1 base_addr : (!fir.ref>>>) -> !fir.llvm_ptr>> !HOST: %[[MAP_INFO_MEMBER:.*]] = omp.map.info var_ptr(%[[DECLARE]]#1 : !fir.ref>>>, i32) map_clauses(tofrom) capture(ByRef) var_ptr_ptr(%[[VAR_PTR_PTR]] : !fir.llvm_ptr>>) bounds(%[[BOUNDS]]) -> !fir.llvm_ptr>> {name = ""} -!HOST: %[[MAP_INFO:.*]] = omp.map.info var_ptr(%[[DECLARE]]#1 : !fir.ref>>>, !fir.box>>) map_clauses(to) capture(ByRef) members(%[[MAP_INFO_MEMBER]] : [0] : !fir.llvm_ptr>>) -> !fir.ref>>> {name = "arr_read_write(2:5)"} - +!HOST: %[[MAP_INFO:.*]] = omp.map.info var_ptr(%[[DECLARE]]#1 : !fir.ref>>>, !fir.box>>) map_clauses(always, to) capture(ByRef) members(%[[MAP_INFO_MEMBER]] : [0] : !fir.llvm_ptr>>) -> !fir.ref>>> {name = "arr_read_write(2:5)"} subroutine assumed_shape_array(arr_read_write) integer, allocatable, intent(inout) :: arr_read_write(:) diff --git a/flang/test/Lower/OpenMP/allocatable-map.f90 b/flang/test/Lower/OpenMP/allocatable-map.f90 index ee1c621ad860b..114967526b8d5 100644 --- a/flang/test/Lower/OpenMP/allocatable-map.f90 +++ b/flang/test/Lower/OpenMP/allocatable-map.f90 @@ -3,7 +3,7 @@ !HLFIRDIALECT: %[[POINTER:.*]]:2 = hlfir.declare %{{.*}} {fortran_attrs = #fir.var_attrs, uniq_name = "_QFpointer_routineEpoint"} : (!fir.ref>>) -> (!fir.ref>>, !fir.ref>>) !HLFIRDIALECT: %[[BOX_OFF:.*]] = fir.box_offset %[[POINTER]]#1 base_addr : (!fir.ref>>) -> !fir.llvm_ptr> !HLFIRDIALECT: %[[POINTER_MAP_MEMBER:.*]] = omp.map.info var_ptr(%[[POINTER]]#1 : !fir.ref>>, i32) map_clauses(tofrom) capture(ByRef) var_ptr_ptr(%[[BOX_OFF]] : !fir.llvm_ptr>) -> !fir.llvm_ptr> {name = ""} -!HLFIRDIALECT: %[[POINTER_MAP:.*]] = omp.map.info var_ptr(%[[POINTER]]#1 : !fir.ref>>, !fir.box>) map_clauses(to) capture(ByRef) members(%[[POINTER_MAP_MEMBER]] : [0] : !fir.llvm_ptr>) -> !fir.ref>> {name = "point"} +!HLFIRDIALECT: %[[POINTER_MAP:.*]] = omp.map.info var_ptr(%[[POINTER]]#1 : !fir.ref>>, !fir.box>) map_clauses(always, to) capture(ByRef) members(%[[POINTER_MAP_MEMBER]] : [0] : !fir.llvm_ptr>) -> !fir.ref>> {name = "point"} !HLFIRDIALECT: omp.target map_entries(%[[POINTER_MAP]] -> {{.*}}, %[[POINTER_MAP_MEMBER]] -> {{.*}} : !fir.ref>>, !fir.llvm_ptr>) { subroutine pointer_routine() integer, pointer :: point diff --git a/flang/test/Lower/OpenMP/array-bounds.f90 b/flang/test/Lower/OpenMP/array-bounds.f90 index 00ebab315e166..670784254adac 100644 --- a/flang/test/Lower/OpenMP/array-bounds.f90 +++ b/flang/test/Lower/OpenMP/array-bounds.f90 @@ -52,7 +52,7 @@ module assumed_array_routines !HOST: %[[BOUNDS:.*]] = omp.map.bounds lower_bound(%[[C3]] : index) upper_bound(%[[C4]] : index) extent(%[[DIMS1]]#1 : index) stride(%[[DIMS0]]#2 : index) start_idx(%[[C0]] : index) {stride_in_bytes = true} !HOST: %[[VAR_PTR_PTR:.*]] = fir.box_offset %[[INTERMEDIATE_ALLOCA]] base_addr : (!fir.ref>>) -> !fir.llvm_ptr>> !HOST: %[[MAP_INFO_MEMBER:.*]] = omp.map.info var_ptr(%[[INTERMEDIATE_ALLOCA]] : !fir.ref>>, i32) map_clauses(tofrom) capture(ByRef) var_ptr_ptr(%[[VAR_PTR_PTR]] : !fir.llvm_ptr>>) bounds(%[[BOUNDS]]) -> !fir.llvm_ptr>> {name = ""} -!HOST: %[[MAP:.*]] = omp.map.info var_ptr(%[[INTERMEDIATE_ALLOCA]] : !fir.ref>>, !fir.box>) map_clauses(to) capture(ByRef) members(%[[MAP_INFO_MEMBER]] : [0] : !fir.llvm_ptr>>) -> !fir.ref> {name = "arr_read_write(2:5)"} +!HOST: %[[MAP:.*]] = omp.map.info var_ptr(%[[INTERMEDIATE_ALLOCA]] : !fir.ref>>, !fir.box>) map_clauses(always, to) capture(ByRef) members(%[[MAP_INFO_MEMBER]] : [0] : !fir.llvm_ptr>>) -> !fir.ref> {name = "arr_read_write(2:5)"} !HOST: omp.target map_entries(%[[MAP]] -> %{{.*}}, {{.*}} -> {{.*}}, %[[MAP_INFO_MEMBER]] -> %{{.*}} : !fir.ref>, !fir.ref, !fir.llvm_ptr>>) { subroutine assumed_shape_array(arr_read_write) integer, intent(inout) :: arr_read_write(:) diff --git a/flang/test/Lower/OpenMP/declare-mapper.f90 b/flang/test/Lower/OpenMP/declare-mapper.f90 index a24d6bd0bf946..7eda1a4c497be 100644 --- a/flang/test/Lower/OpenMP/declare-mapper.f90 +++ b/flang/test/Lower/OpenMP/declare-mapper.f90 @@ -49,7 +49,7 @@ subroutine declare_mapper_1 !CHECK: %[[VAL_18:.*]] = fir.coordinate_of %[[VAL_1]]#0, values : (!fir.ref<[[MY_TYPE]]>) -> !fir.ref>>> !CHECK: %[[VAL_19:.*]] = fir.box_offset %[[VAL_18]] base_addr : (!fir.ref>>>) -> !fir.llvm_ptr>> !CHECK: %[[VAL_20:.*]] = omp.map.info var_ptr(%[[VAL_18]] : !fir.ref>>>, i32) map_clauses(tofrom) capture(ByRef) var_ptr_ptr(%[[VAL_19]] : !fir.llvm_ptr>>) bounds(%[[VAL_16]]) -> !fir.llvm_ptr>> {name = ""} - !CHECK: %[[VAL_21:.*]] = omp.map.info var_ptr(%[[VAL_18]] : !fir.ref>>>, !fir.box>>) map_clauses(to) capture(ByRef) -> !fir.ref>>> {name = "var%[[VAL_22:.*]](1:var%[[VAL_23:.*]])"} + !CHECK: %[[VAL_21:.*]] = omp.map.info var_ptr(%[[VAL_18]] : !fir.ref>>>, !fir.box>>) map_clauses(always, to) capture(ByRef) -> !fir.ref>>> {name = "var%[[VAL_22:.*]](1:var%[[VAL_23:.*]])"} !CHECK: %[[VAL_24:.*]] = omp.map.info var_ptr(%[[VAL_1]]#1 : !fir.ref<[[MY_TYPE]]>, [[MY_TYPE]]) map_clauses(tofrom) capture(ByRef) members(%[[VAL_21]], %[[VAL_20]] : [1], [1, 0] : !fir.ref>>>, !fir.llvm_ptr>>) -> !fir.ref<[[MY_TYPE]]> {name = "var"} !CHECK: omp.declare_mapper.info map_entries(%[[VAL_24]], %[[VAL_21]], %[[VAL_20]] : !fir.ref<[[MY_TYPE]]>, !fir.ref>>>, !fir.llvm_ptr>>) !CHECK: } @@ -141,7 +141,7 @@ subroutine declare_mapper_3 !CHECK: %[[VAL_18:.*]] = fir.coordinate_of %[[VAL_1]]#0, values : (!fir.ref<[[MY_TYPE]]>) -> !fir.ref>>> !CHECK: %[[VAL_19:.*]] = fir.box_offset %[[VAL_18]] base_addr : (!fir.ref>>>) -> !fir.llvm_ptr>> !CHECK: %[[VAL_20:.*]] = omp.map.info var_ptr(%[[VAL_18]] : !fir.ref>>>, i32) map_clauses(tofrom) capture(ByRef) var_ptr_ptr(%[[VAL_19]] : !fir.llvm_ptr>>) bounds(%[[VAL_16]]) -> !fir.llvm_ptr>> {name = ""} - !CHECK: %[[VAL_21:.*]] = omp.map.info var_ptr(%[[VAL_18]] : !fir.ref>>>, !fir.box>>) map_clauses(to) capture(ByRef) -> !fir.ref>>> {name = "var%[[VAL_22:.*]](1:var%[[VAL_23:.*]])"} + !CHECK: %[[VAL_21:.*]] = omp.map.info var_ptr(%[[VAL_18]] : !fir.ref>>>, !fir.box>>) map_clauses(always, to) capture(ByRef) -> !fir.ref>>> {name = "var%[[VAL_22:.*]](1:var%[[VAL_23:.*]])"} !CHECK: %[[VAL_24:.*]] = omp.map.info var_ptr(%[[VAL_1]]#1 : !fir.ref<[[MY_TYPE]]>, [[MY_TYPE]]) map_clauses(tofrom) capture(ByRef) members(%[[VAL_21]], %[[VAL_20]] : [1], [1, 0] : !fir.ref>>>, !fir.llvm_ptr>>) -> !fir.ref<[[MY_TYPE]]> {name = "var"} !CHECK: omp.declare_mapper.info map_entries(%[[VAL_24]], %[[VAL_21]], %[[VAL_20]] : !fir.ref<[[MY_TYPE]]>, !fir.ref>>>, !fir.llvm_ptr>>) !CHECK: } diff --git a/flang/test/Lower/OpenMP/declare-target-link-tarop-cap.f90 b/flang/test/Lower/OpenMP/declare-target-link-tarop-cap.f90 index cfdcd9eda82d1..0fba1ee9a293d 100644 --- a/flang/test/Lower/OpenMP/declare-target-link-tarop-cap.f90 +++ b/flang/test/Lower/OpenMP/declare-target-link-tarop-cap.f90 @@ -35,7 +35,7 @@ program test_link allocate(test_ptr1) test_ptr1 = 1 - !CHECK-DAG: {{%.*}} = omp.map.info var_ptr({{%.*}} : !fir.ref>>, !fir.box>) map_clauses(implicit, to) capture(ByRef) members({{%.*}} : !fir.llvm_ptr>) -> !fir.ref>> {name = "test_ptr1"} + !CHECK-DAG: {{%.*}} = omp.map.info var_ptr({{%.*}} : !fir.ref>>, !fir.box>) map_clauses(always, implicit, to) capture(ByRef) members({{%.*}} : !fir.llvm_ptr>) -> !fir.ref>> {name = "test_ptr1"} !$omp target test_ptr1 = test_ptr1 + 1 !$omp end target @@ -46,7 +46,7 @@ program test_link !$omp end target - !CHECK-DAG: {{%.*}} = omp.map.info var_ptr({{%.*}} : !fir.ref>>, !fir.box>) map_clauses(implicit, to) capture(ByRef) members({{%.*}} : !fir.llvm_ptr>) -> !fir.ref>> {name = "test_ptr2"} + !CHECK-DAG: {{%.*}} = omp.map.info var_ptr({{%.*}} : !fir.ref>>, !fir.box>) map_clauses(always, implicit, to) capture(ByRef) members({{%.*}} : !fir.llvm_ptr>) -> !fir.ref>> {name = "test_ptr2"} test_ptr2 => test_target !$omp target test_ptr2 = test_ptr2 + 1 diff --git a/flang/test/Lower/OpenMP/defaultmap.f90 b/flang/test/Lower/OpenMP/defaultmap.f90 index b9c902fe43f13..30351f5a8b415 100644 --- a/flang/test/Lower/OpenMP/defaultmap.f90 +++ b/flang/test/Lower/OpenMP/defaultmap.f90 @@ -6,7 +6,7 @@ subroutine defaultmap_allocatable_present() integer, dimension(:), allocatable :: arr ! CHECK: %[[MAP_1:.*]] = omp.map.info var_ptr({{.*}} : !fir.ref>>>, i32) map_clauses(implicit, present) capture(ByRef) var_ptr_ptr({{.*}}) bounds({{.*}}) -> !fir.llvm_ptr>> {name = ""} -! CHECK: %[[MAP_2:.*]] = omp.map.info var_ptr({{.*}} : !fir.ref>>>, !fir.box>>) map_clauses(implicit, to) capture(ByRef) members({{.*}}) -> !fir.ref>>> {name = "arr"} +! CHECK: %[[MAP_2:.*]] = omp.map.info var_ptr({{.*}} : !fir.ref>>>, !fir.box>>) map_clauses(always, implicit, to) capture(ByRef) members({{.*}}) -> !fir.ref>>> {name = "arr"} !$omp target defaultmap(present: allocatable) arr(1) = 10 !$omp end target @@ -34,7 +34,7 @@ subroutine defaultmap_all_default() ! CHECK: %[[MAP_1:.*]] = omp.map.info var_ptr({{.*}} : !fir.ref, i32) map_clauses(implicit) capture(ByCopy) -> !fir.ref {name = "scalar_int"} ! CHECK: %[[MAP_2:.*]] = omp.map.info var_ptr({{.*}} : !fir.ref>>>, i32) map_clauses(implicit, tofrom) capture(ByRef) var_ptr_ptr({{.*}}) bounds({{.*}}) -> !fir.llvm_ptr>> {name = ""} -! CHECK: %[[MAP_3:.*]] = omp.map.info var_ptr({{.*}} : !fir.ref>>>, !fir.box>>) map_clauses(implicit, to) capture(ByRef) members({{.*}}) -> !fir.ref>>> {name = "arr"} +! CHECK: %[[MAP_3:.*]] = omp.map.info var_ptr({{.*}} : !fir.ref>>>, !fir.box>>) map_clauses(always, implicit, to) capture(ByRef) members({{.*}}) -> !fir.ref>>> {name = "arr"} ! CHECK: %[[MAP_4:.*]] = omp.map.info var_ptr({{.*}} : !fir.ref>, !fir.array<16xi32>) map_clauses(implicit, tofrom) capture(ByRef) bounds({{.*}}) -> !fir.ref> {name = "aggregate"} !$omp target defaultmap(default: all) @@ -52,7 +52,7 @@ subroutine defaultmap_pointer_to() ! CHECK-NO-FPRIV: %[[MAP_1:.*]] = omp.map.info var_ptr({{.*}} : !fir.ref>>>, i32) map_clauses(implicit, to) capture(ByRef) var_ptr_ptr({{.*}}) bounds({{.*}}) -> !fir.llvm_ptr>> {name = ""} ! CHECK-FPRIV: %[[MAP_1:.*]] = omp.map.info var_ptr({{.*}} : !fir.ref>>>, i32) map_clauses(implicit, to) capture(ByRef) var_ptr_ptr({{.*}}) bounds({{.*}}) -> !fir.llvm_ptr>> {name = ""} -! CHECK: %[[MAP_2:.*]] = omp.map.info var_ptr({{.*}} : !fir.ref>>>, !fir.box>>) map_clauses(implicit, to) capture(ByRef) members({{.*}}) -> !fir.ref>>> {name = "arr_ptr"} +! CHECK: %[[MAP_2:.*]] = omp.map.info var_ptr({{.*}} : !fir.ref>>>, !fir.box>>) map_clauses(always, implicit, to) capture(ByRef) members({{.*}}) -> !fir.ref>>> {name = "arr_ptr"} ! CHECK-FPRIV: %[[MAP_3:.*]] = omp.map.info var_ptr({{.*}} : !fir.ref, i32) map_clauses(to) capture(ByCopy) -> !fir.ref ! CHECK-NO-FPRIV: %[[MAP_3:.*]] = omp.map.info var_ptr({{.*}} : !fir.ref, i32) map_clauses(implicit) capture(ByCopy) -> !fir.ref {name = "scalar_int"} !$omp target defaultmap(to: pointer) diff --git a/flang/test/Lower/OpenMP/derived-type-allocatable-map.f90 b/flang/test/Lower/OpenMP/derived-type-allocatable-map.f90 index d19a572c1f4fb..74aee4df1f454 100644 --- a/flang/test/Lower/OpenMP/derived-type-allocatable-map.f90 +++ b/flang/test/Lower/OpenMP/derived-type-allocatable-map.f90 @@ -6,7 +6,7 @@ !CHECK: %[[MEMBER_COORD:.*]] = fir.coordinate_of %[[DECLARE]]#0, array_j : (!fir.ref>) -> !fir.ref>>> !CHECK: %[[MEMBER_BASE_ADDR:.*]] = fir.box_offset %[[MEMBER_COORD]] base_addr : (!fir.ref>>>) -> !fir.llvm_ptr>> !CHECK: %[[MAP_MEMBER_BASE_ADDR:.*]] = omp.map.info var_ptr(%[[MEMBER_COORD]] : !fir.ref>>>, i32) map_clauses(tofrom) capture(ByRef) var_ptr_ptr(%[[MEMBER_BASE_ADDR]] : !fir.llvm_ptr>>) bounds(%[[BOUNDS]]) -> !fir.llvm_ptr>> {{.*}} -!CHECK: %[[MAP_MEMBER_DESCRIPTOR:.*]] = omp.map.info var_ptr(%[[MEMBER_COORD]] : !fir.ref>>>, !fir.box>>) map_clauses(to) capture(ByRef) -> !fir.ref>>> {{.*}} +!CHECK: %[[MAP_MEMBER_DESCRIPTOR:.*]] = omp.map.info var_ptr(%[[MEMBER_COORD]] : !fir.ref>>>, !fir.box>>) map_clauses(always, to) capture(ByRef) -> !fir.ref>>> {{.*}} !CHECK: %[[MAP_PARENT:.*]] = omp.map.info var_ptr(%[[DECLARE]]#1 : !fir.ref>, !fir.type<[[ONE_LAYER_TY]]>) map_clauses(tofrom) capture(ByRef) members(%[[MAP_MEMBER_DESCRIPTOR]], %[[MAP_MEMBER_BASE_ADDR]] : [4], [4, 0] : !fir.ref>>>, !fir.llvm_ptr>>) -> !fir.ref> {{{.*}} partial_map = true} !CHECK: omp.target map_entries(%[[MAP_PARENT]] -> %[[ARG0:.*]], %[[MAP_MEMBER_DESCRIPTOR]] -> %[[ARG1:.*]], %[[MAP_MEMBER_BASE_ADDR]] -> %[[ARG2:.*]] : !fir.ref>, !fir.ref>>>, !fir.llvm_ptr>>) { !CHECK: %{{.*}}:2 = hlfir.declare %[[ARG0]] {{{.*}}} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) @@ -35,14 +35,14 @@ subroutine dtype_alloca_map_op_block() !CHECK: %[[LOAD_DTYPE:.*]] = fir.load %[[DECLARE]]#0 : !fir.ref>>> !CHECK: %[[MEMBER_COORD:.*]] = fir.coordinate_of %[[LOAD_DTYPE]], array_j : (!fir.box>>) -> !fir.ref>>> !CHECK: %[[MEMBER_BASE_ADDR:.*]] = fir.box_offset %[[MEMBER_COORD]] base_addr : (!fir.ref>>>) -> !fir.llvm_ptr>> -!CHECK: %[[MAP_MEMBER_BASE_ADDR:.*]] = omp.map.info var_ptr(%[[MEMBER_COORD]] : !fir.ref>>>, i32) map_clauses(tofrom) capture(ByRef) var_ptr_ptr(%[[MEMBER_BASE_ADDR]] : !fir.llvm_ptr>>) bounds(%[[BOUNDS]]) -> !fir.llvm_ptr>> {{.*}} -!CHECK: %[[MAP_MEMBER_DESC:.*]] = omp.map.info var_ptr(%[[MEMBER_COORD]] : !fir.ref>>>, !fir.box>>) map_clauses(to) capture(ByRef) -> !fir.ref>>> {{.*}} +!CHECK: %[[MAP_MEMBER_BASE_ADDR:.*]] = omp.map.info var_ptr(%[[MEMBER_COORD]] : !fir.ref>>>, i32) map_clauses(tofrom) capture(ByRef) var_ptr_ptr(%[[MEMBER_BASE_ADDR]] : !fir.llvm_ptr>>) bounds(%[[BOUNDS]]) -> !fir.llvm_ptr>> {{.*}} +!CHECK: %[[MAP_MEMBER_DESC:.*]] = omp.map.info var_ptr(%[[MEMBER_COORD]] : !fir.ref>>>, !fir.box>>) map_clauses(always, to) capture(ByRef) -> !fir.ref>>> {{.*}} !CHECK: %[[LOAD_DTYPE:.*]] = fir.load %[[DECLARE]]#0 : !fir.ref>>> !CHECK: %[[REGULAR_MEMBER:.*]] = fir.coordinate_of %[[LOAD_DTYPE]], k : (!fir.box>>) -> !fir.ref !CHECK: %[[MAP_REGULAR_MEMBER:.*]] = omp.map.info var_ptr(%[[REGULAR_MEMBER]] : !fir.ref, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref {{.*}} !CHECK: %[[DTYPE_BASE_ADDR:.*]] = fir.box_offset %[[DECLARE]]#1 base_addr : (!fir.ref>>>) -> !fir.llvm_ptr>> -!CHECK: %[[MAP_DTYPE_BASE_ADDR:.*]] = omp.map.info var_ptr(%[[DECLARE]]#1 : !fir.ref>>>, !fir.type<[[REC_TY]]>) map_clauses(tofrom) capture(ByRef) var_ptr_ptr(%[[DTYPE_BASE_ADDR]] : !fir.llvm_ptr>>) -> !fir.llvm_ptr>> {{.*}} -!CHECK: %[[MAP_DTYPE_DESC:.*]] = omp.map.info var_ptr(%[[DECLARE]]#1 : !fir.ref>>>, !fir.box>>) map_clauses(to) capture(ByRef) members(%[[MAP_DTYPE_BASE_ADDR]], %[[MAP_MEMBER_DESC]], %[[MAP_MEMBER_BASE_ADDR]], %[[MAP_REGULAR_MEMBER]] : [0], [0, 4], [0, 4, 0], [0, 5] : !fir.llvm_ptr>>, !fir.ref>>>, !fir.llvm_ptr>>, !fir.ref) -> !fir.ref>>> {{.*}} +!CHECK: %[[MAP_DTYPE_BASE_ADDR:.*]] = omp.map.info var_ptr(%[[DECLARE]]#1 : !fir.ref>>>, !fir.type<[[REC_TY]]>) map_clauses(tofrom) capture(ByRef) var_ptr_ptr(%[[DTYPE_BASE_ADDR]] : !fir.llvm_ptr>>) -> !fir.llvm_ptr>> {{.*}} +!CHECK: %[[MAP_DTYPE_DESC:.*]] = omp.map.info var_ptr(%[[DECLARE]]#1 : !fir.ref>>>, !fir.box>>) map_clauses(always, to) capture(ByRef) members(%[[MAP_DTYPE_BASE_ADDR]], %[[MAP_MEMBER_DESC]], %[[MAP_MEMBER_BASE_ADDR]], %[[MAP_REGULAR_MEMBER]] : [0], [0, 4], [0, 4, 0], [0, 5] : !fir.llvm_ptr>>, !fir.ref>>>, !fir.llvm_ptr>>, !fir.ref) -> !fir.ref>>> {{.*}} !CHECK: omp.target map_entries(%[[MAP_DTYPE_DESC]] -> %[[ARG0:.*]], %[[MAP_DTYPE_BASE_ADDR]] -> %[[ARG1:.*]], %[[MAP_MEMBER_DESC]] -> %[[ARG2:.*]], %[[MAP_MEMBER_BASE_ADDR]] -> %[[ARG3:.*]], %[[MAP_REGULAR_MEMBER]] -> %[[ARG4:.*]] : !fir.ref>>>, !fir.llvm_ptr>>, !fir.ref>>>, !fir.llvm_ptr>>, !fir.ref) { !CHECK: %{{.*}}:2 = hlfir.declare %[[ARG0]] {{{.*}}} : (!fir.ref>>>) -> (!fir.ref>>>, !fir.ref>>>) subroutine alloca_dtype_op_block_add() @@ -74,14 +74,14 @@ subroutine alloca_dtype_op_block_add() !CHECK: %[[NESTED_MEMBER_COORD:.*]] = fir.coordinate_of %[[NESTED_DTYPE_COORD]], array_k : (!fir.ref>) -> !fir.ref>>> !CHECK: %[[NESTED_MEMBER_BASE_ADDR:.*]] = fir.box_offset %[[NESTED_MEMBER_COORD]] base_addr : (!fir.ref>>>) -> !fir.llvm_ptr>> !CHECK: %[[MAP_NESTED_MEMBER_BASE_ADDR:.*]] = omp.map.info var_ptr(%[[NESTED_MEMBER_COORD]] : !fir.ref>>>, i32) map_clauses(tofrom) capture(ByRef) var_ptr_ptr(%[[NESTED_MEMBER_BASE_ADDR]] : !fir.llvm_ptr>>) bounds(%[[BOUNDS]]) -> !fir.llvm_ptr>> {{.*}} -!CHECK: %[[MAP_NESTED_MEMBER_COORD:.*]] = omp.map.info var_ptr(%[[NESTED_MEMBER_COORD]] : !fir.ref>>>, !fir.box>>) map_clauses(to) capture(ByRef) -> !fir.ref>>> {{.*}} +!CHECK: %[[MAP_NESTED_MEMBER_COORD:.*]] = omp.map.info var_ptr(%[[NESTED_MEMBER_COORD]] : !fir.ref>>>, !fir.box>>) map_clauses(always, to) capture(ByRef) -> !fir.ref>>> {{.*}} !CHECK: %[[LOAD:.*]] = fir.load %[[DECLARE]]#0 : !fir.ref}>>>> !CHECK: %[[NESTED_DTYPE_COORD:.*]] = fir.coordinate_of %[[LOAD]], nest : (!fir.box}>>>) -> !fir.ref> !CHECK: %[[REGULAR_NESTED_MEMBER_COORD:.*]] = fir.coordinate_of %[[NESTED_DTYPE_COORD]], k : (!fir.ref>) -> !fir.ref !CHECK: %[[MAP_REGULAR_NESTED_MEMBER:.*]] = omp.map.info var_ptr(%[[REGULAR_NESTED_MEMBER_COORD]] : !fir.ref, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref {{.*}} !CHECK: %[[DTYPE_BASE_ADDR:.*]] = fir.box_offset %[[DECLARE]]#1 base_addr : (!fir.ref}>>>>) -> !fir.llvm_ptr}>>> !CHECK: %[[MAP_DTYPE_BASE_ADDR:.*]] = omp.map.info var_ptr(%[[DECLARE]]#1 : !fir.ref}>>>>, !fir.type<[[REC_TY]]>}>) map_clauses(tofrom) capture(ByRef) var_ptr_ptr(%[[DTYPE_BASE_ADDR]] : !fir.llvm_ptr}>>>) -> !fir.llvm_ptr}>>> {{.*}} -!CHECK: %[[MAP_DTYPE:.*]] = omp.map.info var_ptr(%[[DECLARE]]#1 : !fir.ref}>>>>, !fir.box}>>>) map_clauses(to) capture(ByRef) members(%[[MAP_DTYPE_BASE_ADDR]], %[[MAP_NESTED_MEMBER_COORD]], %[[MAP_NESTED_MEMBER_BASE_ADDR]], %[[MAP_REGULAR_NESTED_MEMBER]] : [0], [0, 6, 2], [0, 6, 2, 0], [0, 6, 3] : !fir.llvm_ptr}>>>, !fir.ref>>>, !fir.llvm_ptr>>, !fir.ref) -> !fir.ref}>>>> {{.*}} +!CHECK: %[[MAP_DTYPE:.*]] = omp.map.info var_ptr(%[[DECLARE]]#1 : !fir.ref}>>>>, !fir.box}>>>) map_clauses(always, to) capture(ByRef) members(%[[MAP_DTYPE_BASE_ADDR]], %[[MAP_NESTED_MEMBER_COORD]], %[[MAP_NESTED_MEMBER_BASE_ADDR]], %[[MAP_REGULAR_NESTED_MEMBER]] : [0], [0, 6, 2], [0, 6, 2, 0], [0, 6, 3] : !fir.llvm_ptr}>>>, !fir.ref>>>, !fir.llvm_ptr>>, !fir.ref) -> !fir.ref}>>>> {{.*}} !CHECK: omp.target map_entries(%[[MAP_DTYPE]] -> %[[ARG0:.*]], %[[MAP_DTYPE_BASE_ADDR]] -> %[[ARG1:.*]], %[[MAP_NESTED_MEMBER_COORD]] -> %[[ARG2:.*]], %[[MAP_NESTED_MEMBER_BASE_ADDR]] -> %[[ARG3:.*]], %[[MAP_REGULAR_NESTED_MEMBER]] -> %[[ARG4:.*]] : !fir.ref}>>>>, !fir.llvm_ptr}>>>, !fir.ref>>>, !fir.llvm_ptr>>, !fir.ref) { !CHECK: %{{.*}}:2 = hlfir.declare %[[ARG0]] {{.*}} : (!fir.ref}>>>>) -> (!fir.ref}>>>>, !fir.ref}>>>>) subroutine alloca_nest_dype_map_op_block_add() @@ -120,7 +120,7 @@ subroutine alloca_nest_dype_map_op_block_add() !CHECK: %[[NESTED_MEMBER_COORD:.*]] = fir.coordinate_of %[[NESTED_DTYPE_COORD]], array_k : (!fir.ref>) -> !fir.ref>>> !CHECK: %[[NESTED_MEMBER_BASE_ADDR:.*]] = fir.box_offset %[[NESTED_MEMBER_COORD]] base_addr : (!fir.ref>>>) -> !fir.llvm_ptr>> !CHECK: %[[MAP_NESTED_MEMBER_BASE_ADDR:.*]] = omp.map.info var_ptr(%[[NESTED_MEMBER_COORD]] : !fir.ref>>>, i32) map_clauses(tofrom) capture(ByRef) var_ptr_ptr(%[[NESTED_MEMBER_BASE_ADDR]] : !fir.llvm_ptr>>) bounds(%[[BOUNDS]]) -> !fir.llvm_ptr>> {{.*}} -!CHECK: %[[MAP_NESTED_MEMBER_DESC:.*]] = omp.map.info var_ptr(%[[NESTED_MEMBER_COORD]] : !fir.ref>>>, !fir.box>>) map_clauses(to) capture(ByRef) -> !fir.ref>>> {{.*}} +!CHECK: %[[MAP_NESTED_MEMBER_DESC:.*]] = omp.map.info var_ptr(%[[NESTED_MEMBER_COORD]] : !fir.ref>>>, !fir.box>>) map_clauses(always, to) capture(ByRef) -> !fir.ref>>> {{.*}} !CHECK: %[[MAP_PARENT:.*]] = omp.map.info var_ptr(%[[DECLARE]]#1 : !fir.ref>, !fir.type<[[REC_TY]]>) map_clauses(tofrom) capture(ByRef) members(%[[MAP_NESTED_MEMBER_DESC]], %[[MAP_NESTED_MEMBER_BASE_ADDR]] : [6, 2], [6, 2, 0] : !fir.ref>>>, !fir.llvm_ptr>>) -> !fir.ref> {{.*}} !CHECK: omp.target map_entries(%[[MAP_PARENT]] -> %[[ARG0:.*]], %[[MAP_NESTED_MEMBER_DESC]] -> %[[ARG1:.*]], %[[MAP_NESTED_MEMBER_BASE_ADDR]] -> %[[ARG2:.*]] : !fir.ref>, !fir.ref>>>, !fir.llvm_ptr>>) { !CHECK: %{{.*}}:2 = hlfir.declare %[[ARG0]] {{.*}} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) diff --git a/flang/test/Lower/OpenMP/derived-type-map.f90 b/flang/test/Lower/OpenMP/derived-type-map.f90 index 921dd5663f8c5..3b39b694c37b2 100644 --- a/flang/test/Lower/OpenMP/derived-type-map.f90 +++ b/flang/test/Lower/OpenMP/derived-type-map.f90 @@ -23,7 +23,7 @@ end subroutine mapType_derived_implicit !CHECK: %[[DECLARE:.*]]:2 = hlfir.declare %[[ALLOCA]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFmaptype_derived_implicit_allocatableEscalar_arr"} : (!fir.ref,int:i32}>>>>) -> (!fir.ref,int:i32}>>>>, !fir.ref,int:i32}>>>>) !CHECK: %[[BOX_ADDR:.*]] = fir.box_offset %[[DECLARE]]#1 base_addr : (!fir.ref,int:i32}>>>>) -> !fir.llvm_ptr,int:i32}>>> !CHECK: %[[BASE_MAP:.*]] = omp.map.info var_ptr(%[[DECLARE]]#1 : !fir.ref,int:i32}>>>>, !fir.type<_QFmaptype_derived_implicit_allocatableTscalar_and_array{real:f32,array:!fir.array<10xi32>,int:i32}>) map_clauses(implicit, tofrom) capture(ByRef) var_ptr_ptr(%[[BOX_ADDR]] : !fir.llvm_ptr,int:i32}>>>) mapper(@[[MAPPER1]]) -> !fir.llvm_ptr,int:i32}>>> {name = ""} -!CHECK: %[[DESC_MAP:.*]] = omp.map.info var_ptr(%[[DECLARE]]#1 : !fir.ref,int:i32}>>>>, !fir.box,int:i32}>>>) map_clauses(implicit, to) capture(ByRef) members(%[[BASE_MAP]] : [0] : !fir.llvm_ptr,int:i32}>>>) -> !fir.ref,int:i32}>>>> {name = "scalar_arr"} +!CHECK: %[[DESC_MAP:.*]] = omp.map.info var_ptr(%[[DECLARE]]#1 : !fir.ref,int:i32}>>>>, !fir.box,int:i32}>>>) map_clauses(always, implicit, to) capture(ByRef) members(%[[BASE_MAP]] : [0] : !fir.llvm_ptr,int:i32}>>>) -> !fir.ref,int:i32}>>>> {name = "scalar_arr"} !CHECK: omp.target map_entries(%[[DESC_MAP]] -> %[[ARG0:.*]], %[[BASE_MAP]] -> %[[ARG1:.*]] : !fir.ref,int:i32}>>>>, !fir.llvm_ptr,int:i32}>>>) { subroutine mapType_derived_implicit_allocatable type :: scalar_and_array diff --git a/flang/test/Lower/OpenMP/map-character.f90 b/flang/test/Lower/OpenMP/map-character.f90 index 9a114238fa9ec..c4197261d2099 100644 --- a/flang/test/Lower/OpenMP/map-character.f90 +++ b/flang/test/Lower/OpenMP/map-character.f90 @@ -43,7 +43,7 @@ end subroutine TestOfCharacter !CHECK: %[[A1_BOXCHAR_MAP:.*]] = omp.map.info var_ptr(%[[A1_BOXCHAR_ALLOCA]] : !fir.ref>, !fir.char<1,?>) map_clauses(implicit, to) !CHECK-SAME: capture(ByRef) var_ptr_ptr(%[[A1_BOX_ADDR]] : !fir.llvm_ptr>>) bounds(%[[BOUNDS_A1_BOXCHAR]]) -> !fir.llvm_ptr>> {name = ""} !CHECK: %[[A1_BOXCHAR_MAP_2:.*]] = omp.map.info var_ptr(%[[A1_BOXCHAR_ALLOCA]] : !fir.ref>, !fir.boxchar<1>) -!CHECK-SAME: map_clauses(implicit, to) capture(ByRef) members(%[[A1_BOXCHAR_MAP]] : [0] : !fir.llvm_ptr>>) -> !fir.ref> {name = ""} +!CHECK-SAME: map_clauses(always, implicit, to) capture(ByRef) members(%[[A1_BOXCHAR_MAP]] : [0] : !fir.llvm_ptr>>) -> !fir.ref> {name = ""} !CHECK: fir.store %[[ARG0]] to %[[A0_BOXCHAR_ALLOCA]] : !fir.ref> !CHECK: %[[CONST_ZERO:.*]] = arith.constant 0 : index !CHECK: %[[CONST_ONE:.*]] = arith.constant 1 : index @@ -54,7 +54,7 @@ end subroutine TestOfCharacter !CHECK: %[[A0_BOX_ADDR:.*]] = fir.box_offset %[[A0_BOXCHAR_ALLOCA]] base_addr : (!fir.ref>) -> !fir.llvm_ptr>> !CHECK: %[[A0_BOXCHAR_MAP:.*]] = omp.map.info var_ptr(%[[A0_BOXCHAR_ALLOCA]] : !fir.ref>, !fir.char<1,?>) map_clauses(implicit, to) !CHECK-SAME: capture(ByRef) var_ptr_ptr(%[[A0_BOX_ADDR]] : !fir.llvm_ptr>>) bounds(%24) -> !fir.llvm_ptr>> {name = ""} -!CHECK: %[[A0_BOXCHAR_MAP_2:.*]] = omp.map.info var_ptr(%[[A0_BOXCHAR_ALLOCA]] : !fir.ref>, !fir.boxchar<1>) map_clauses(implicit, to) +!CHECK: %[[A0_BOXCHAR_MAP_2:.*]] = omp.map.info var_ptr(%[[A0_BOXCHAR_ALLOCA]] : !fir.ref>, !fir.boxchar<1>) map_clauses(always, implicit, to) !CHECK-SAME: capture(ByRef) members(%[[A0_BOXCHAR_MAP]] : [0] : !fir.llvm_ptr>>) -> !fir.ref> {name = ""} !CHECK: omp.target map_entries(%[[A0_MAP]] -> %[[TGT_A0:.*]], %[[A1_MAP]] -> %[[TGT_A1:.*]], %[[A1_BOXCHAR_MAP_2]] -> %[[TGT_A1_BOXCHAR:.*]], %[[A0_BOXCHAR_MAP_2]] -> %[[TGT_A0_BOXCHAR:.*]], %[[A1_BOXCHAR_MAP]] -> %[[TGT_A1_BOXCHAR2:.*]], %[[A0_BOXCHAR_MAP]] -> %[[TGT_A0_BOXCHAR2:.*]] : !fir.ref>, !fir.ref>, !fir.ref>, !fir.ref>, !fir.llvm_ptr>>, !fir.llvm_ptr>>) { !CHECK: %[[TGT_A0_BC_LD:.*]] = fir.load %[[TGT_A0_BOXCHAR]] : !fir.ref> diff --git a/flang/test/Lower/OpenMP/map-descriptor-deferral.f90 b/flang/test/Lower/OpenMP/map-descriptor-deferral.f90 index daea2f321414f..a7165c391f1af 100644 --- a/flang/test/Lower/OpenMP/map-descriptor-deferral.f90 +++ b/flang/test/Lower/OpenMP/map-descriptor-deferral.f90 @@ -23,7 +23,7 @@ subroutine assume_map_target_enter_exit(assumed_arr) !CHECK: omp.target_enter_data map_entries(%[[MAP_ADDR]] : !fir.ref>) !CHECK: %[[BOX_ADDR:.*]] = fir.box_offset %{{.*}} base_addr : (!fir.ref>>) -> !fir.llvm_ptr>> !CHECK: %[[MAP_ADDR:.*]] = omp.map.info var_ptr(%{{.*}} : !fir.ref>>, i32) map_clauses(implicit, tofrom) capture(ByRef) var_ptr_ptr(%[[BOX_ADDR]] : !fir.llvm_ptr>>) bounds(%{{.*}}) -> !fir.llvm_ptr>> {name = ""} -!CHECK: %[[MAP_BOX:.*]] = omp.map.info var_ptr(%{{.*}} : !fir.ref>>, !fir.box>) map_clauses(implicit, to) capture(ByRef) members(%{{.*}} : [0] : !fir.llvm_ptr>>) -> !fir.ref> {name = "assumed_arr"} +!CHECK: %[[MAP_BOX:.*]] = omp.map.info var_ptr(%{{.*}} : !fir.ref>>, !fir.box>) map_clauses(always, implicit, to) capture(ByRef) members(%{{.*}} : [0] : !fir.llvm_ptr>>) -> !fir.ref> {name = "assumed_arr"} !CHECK: omp.target map_entries(%[[MAP_BOX]] -> %{{.*}}, %[[MAP_ADDR]] -> %{{.*}} : !fir.ref>, !fir.llvm_ptr>>) { !CHECK: %[[BOX_ADDR:.*]] = fir.box_offset %{{.*}} base_addr : (!fir.ref>>) -> !fir.llvm_ptr>> !CHECK: %[[LOAD_BOX:.*]] = fir.load %[[BOX_ADDR]] : !fir.llvm_ptr>> @@ -42,11 +42,11 @@ subroutine assume_alloca_map_target_enter_exit(assumed_arr) !CHECK-LABEL: func.func @_QPassume_alloca_map_target_enter_exit( !CHECK: %[[BOX_ADDR:.*]] = fir.box_offset %{{.*}} base_addr : (!fir.ref>>>) -> !fir.llvm_ptr>> !CHECK: %[[BOX_ADDR_MAP:.*]] = omp.map.info var_ptr(%{{.*}} : !fir.ref>>>, i32) map_clauses(to) capture(ByRef) var_ptr_ptr(%[[BOX_ADDR]] : !fir.llvm_ptr>>) bounds(%{{.*}}) -> !fir.llvm_ptr>> {name = ""} -!CHECK: %[[DESC_MAP:.*]] = omp.map.info var_ptr(%{{.*}} : !fir.ref>>>, !fir.box>>) map_clauses(to) capture(ByRef) members(%[[BOX_ADDR_MAP]] : [0] : !fir.llvm_ptr>>) -> !fir.ref>>> {name = "assumed_arr"} +!CHECK: %[[DESC_MAP:.*]] = omp.map.info var_ptr(%{{.*}} : !fir.ref>>>, !fir.box>>) map_clauses(always, to) capture(ByRef) members(%[[BOX_ADDR_MAP]] : [0] : !fir.llvm_ptr>>) -> !fir.ref>>> {name = "assumed_arr"} !CHECK: omp.target_enter_data map_entries(%[[DESC_MAP]], %[[BOX_ADDR_MAP]] : !fir.ref>>>, !fir.llvm_ptr>>) !CHECK: %[[BOX_ADDR:.*]] = fir.box_offset %{{.*}} base_addr : (!fir.ref>>>) -> !fir.llvm_ptr>> !CHECK: %[[BOX_ADDR_MAP:.*]] = omp.map.info var_ptr(%{{.*}} : !fir.ref>>>, i32) map_clauses(implicit, tofrom) capture(ByRef) var_ptr_ptr(%[[BOX_ADDR]] : !fir.llvm_ptr>>) bounds(%{{.*}}) -> !fir.llvm_ptr>> {name = ""} -!CHECK: %[[DESC_MAP:.*]] = omp.map.info var_ptr(%{{.*}} : !fir.ref>>>, !fir.box>>) map_clauses(implicit, to) capture(ByRef) members(%[[BOX_ADDR_MAP]] : [0] : !fir.llvm_ptr>>) -> !fir.ref>>> {name = "assumed_arr"} +!CHECK: %[[DESC_MAP:.*]] = omp.map.info var_ptr(%{{.*}} : !fir.ref>>>, !fir.box>>) map_clauses(always, implicit, to) capture(ByRef) members(%[[BOX_ADDR_MAP]] : [0] : !fir.llvm_ptr>>) -> !fir.ref>>> {name = "assumed_arr"} !CHECK: omp.target map_entries(%[[DESC_MAP]] -> %[[VAL_28:.*]], %[[BOX_ADDR_MAP]] -> %[[VAL_29:.*]] : !fir.ref>>>, !fir.llvm_ptr>>) { !CHECK: %[[BOX_ADDR:.*]] = fir.box_offset %{{.*}} base_addr : (!fir.ref>>>) -> !fir.llvm_ptr>> !CHECK: %[[BOX_ADDR_MAP:.*]] = omp.map.info var_ptr(%{{.*}} : !fir.ref>>>, i32) map_clauses(from) capture(ByRef) var_ptr_ptr(%[[BOX_ADDR]] : !fir.llvm_ptr>>) bounds(%{{.*}}) -> !fir.llvm_ptr>> {name = ""} @@ -65,11 +65,11 @@ subroutine assume_pointer_map_target_enter_exit(assumed_arr) !CHECK-LABEL: func.func @_QPassume_pointer_map_target_enter_exit( !CHECK: %[[BOX_ADDR:.*]] = fir.box_offset %{{.*}} base_addr : (!fir.ref>>>) -> !fir.llvm_ptr>> !CHECK: %[[BOX_ADDR_MAP:.*]] = omp.map.info var_ptr(%{{.*}} : !fir.ref>>>, i32) map_clauses(to) capture(ByRef) var_ptr_ptr(%[[BOX_ADDR]] : !fir.llvm_ptr>>) bounds(%{{.*}}) -> !fir.llvm_ptr>> {name = ""} -!CHECK: %[[DESC_MAP:.*]] = omp.map.info var_ptr(%{{.*}} : !fir.ref>>>, !fir.box>>) map_clauses(to) capture(ByRef) members(%[[BOX_ADDR_MAP]] : [0] : !fir.llvm_ptr>>) -> !fir.ref>>> {name = "assumed_arr"} +!CHECK: %[[DESC_MAP:.*]] = omp.map.info var_ptr(%{{.*}} : !fir.ref>>>, !fir.box>>) map_clauses(always, to) capture(ByRef) members(%[[BOX_ADDR_MAP]] : [0] : !fir.llvm_ptr>>) -> !fir.ref>>> {name = "assumed_arr"} !CHECK: omp.target_enter_data map_entries(%[[DESC_MAP]], %[[BOX_ADDR_MAP]] : !fir.ref>>>, !fir.llvm_ptr>>) !CHECK: %[[BOX_ADDR:.*]] = fir.box_offset %{{.*}} base_addr : (!fir.ref>>>) -> !fir.llvm_ptr>> !CHECK: %[[BOX_ADDR_MAP:.*]] = omp.map.info var_ptr(%{{.*}} : !fir.ref>>>, i32) map_clauses(implicit, tofrom) capture(ByRef) var_ptr_ptr(%[[BOX_ADDR]] : !fir.llvm_ptr>>) bounds(%{{.*}}) -> !fir.llvm_ptr>> {name = ""} -!CHECK: %[[DESC_MAP:.*]] = omp.map.info var_ptr(%{{.*}} : !fir.ref>>>, !fir.box>>) map_clauses(implicit, to) capture(ByRef) members(%[[BOX_ADDR_MAP]] : [0] : !fir.llvm_ptr>>) -> !fir.ref>>> {name = "assumed_arr"} +!CHECK: %[[DESC_MAP:.*]] = omp.map.info var_ptr(%{{.*}} : !fir.ref>>>, !fir.box>>) map_clauses(always, implicit, to) capture(ByRef) members(%[[BOX_ADDR_MAP]] : [0] : !fir.llvm_ptr>>) -> !fir.ref>>> {name = "assumed_arr"} !CHECK: omp.target map_entries(%[[DESC_MAP]] -> %[[VAL_28:.*]], %[[BOX_ADDR_MAP]] -> %[[VAL_29:.*]] : !fir.ref>>>, !fir.llvm_ptr>>) { !CHECK: %[[BOX_ADDR:.*]] = fir.box_offset %{{.*}} base_addr : (!fir.ref>>>) -> !fir.llvm_ptr>> !CHECK: %[[BOX_ADDR_MAP:.*]] = omp.map.info var_ptr(%{{.*}} : !fir.ref>>>, i32) map_clauses(from) capture(ByRef) var_ptr_ptr(%[[BOX_ADDR]] : !fir.llvm_ptr>>) bounds(%{{.*}}) -> !fir.llvm_ptr>> {name = ""} @@ -88,9 +88,9 @@ subroutine assume_map_target_data(assumed_arr) !CHECK-LABEL: func.func @_QPassume_map_target_data( !CHECK: %[[BOX_ADDR:.*]] = fir.box_offset %{{.*}} base_addr : (!fir.ref>>) -> !fir.llvm_ptr>> !CHECK: %[[MAP_ADDR:.*]] = omp.map.info var_ptr(%{{.*}} : !fir.ref>>, i32) map_clauses(to) capture(ByRef) var_ptr_ptr(%[[BOX_ADDR]] : !fir.llvm_ptr>>) bounds(%{{.*}}) -> !fir.llvm_ptr>> {name = ""} -!CHECK: %[[MAP_BOX:.*]] = omp.map.info var_ptr(%{{.*}} : !fir.ref>>, !fir.box>) map_clauses(to) capture(ByRef) members(%[[MAP_ADDR]] : [0] : !fir.llvm_ptr>>) -> !fir.ref> {name = "assumed_arr"} +!CHECK: %[[MAP_BOX:.*]] = omp.map.info var_ptr(%{{.*}} : !fir.ref>>, !fir.box>) map_clauses(always, to) capture(ByRef) members(%[[MAP_ADDR]] : [0] : !fir.llvm_ptr>>) -> !fir.ref> {name = "assumed_arr"} !CHECK: omp.target_data map_entries(%[[MAP_BOX]], %[[MAP_ADDR]] : !fir.ref>, !fir.llvm_ptr>>) { !CHECK: %[[BOX_ADDR:.*]] = fir.box_offset %{{.*}} base_addr : (!fir.ref>>) -> !fir.llvm_ptr>> !CHECK: %[[MAP_ADDR:.*]] = omp.map.info var_ptr(%{{.*}} : !fir.ref>>, i32) map_clauses(implicit, tofrom) capture(ByRef) var_ptr_ptr(%[[BOX_ADDR]] : !fir.llvm_ptr>>) bounds(%{{.*}}) -> !fir.llvm_ptr>> {name = ""} -!CHECK: %[[MAP_BOX:.*]] = omp.map.info var_ptr(%{{.*}} : !fir.ref>>, !fir.box>) map_clauses(implicit, to) capture(ByRef) members(%[[MAP_ADDR]] : [0] : !fir.llvm_ptr>>) -> !fir.ref> {name = "assumed_arr"} +!CHECK: %[[MAP_BOX:.*]] = omp.map.info var_ptr(%{{.*}} : !fir.ref>>, !fir.box>) map_clauses(always, implicit, to) capture(ByRef) members(%[[MAP_ADDR]] : [0] : !fir.llvm_ptr>>) -> !fir.ref> {name = "assumed_arr"} !CHECK: omp.target map_entries(%[[MAP_BOX]] -> %{{.*}}, %[[MAP_ADDR]] -> %{{.*}} : !fir.ref>, !fir.llvm_ptr>>) { diff --git a/flang/test/Lower/OpenMP/map-neg-alloca-derived-type-array.f90 b/flang/test/Lower/OpenMP/map-neg-alloca-derived-type-array.f90 index dd8721b97dccd..0e3e8d7c5ae09 100644 --- a/flang/test/Lower/OpenMP/map-neg-alloca-derived-type-array.f90 +++ b/flang/test/Lower/OpenMP/map-neg-alloca-derived-type-array.f90 @@ -24,4 +24,4 @@ subroutine map_negative_bounds_allocatable_dtype() ! CHECK: %[[VAL_11:.*]] = fir.coordinate_of %[[VAL_10]], data : (!fir.ref>>}>>) -> !fir.ref>>> ! CHECK: %[[VAL_12:.*]] = fir.box_offset %[[VAL_11]] base_addr : (!fir.ref>>>) -> !fir.llvm_ptr>> ! CHECK: %[[VAL_13:.*]] = omp.map.info var_ptr(%[[VAL_11]] : !fir.ref>>>, f32) map_clauses(tofrom) capture(ByRef) var_ptr_ptr(%[[VAL_12]] : !fir.llvm_ptr>>) bounds({{.*}}) -> !fir.llvm_ptr>> {name = ""} -! CHECK: %[[VAL_14:.*]] = omp.map.info var_ptr(%[[VAL_11]] : !fir.ref>>>, !fir.box>>) map_clauses(to) capture(ByRef) -> !fir.ref>>> {name = {{.*}}} +! CHECK: %[[VAL_14:.*]] = omp.map.info var_ptr(%[[VAL_11]] : !fir.ref>>>, !fir.box>>) map_clauses(always, to) capture(ByRef) -> !fir.ref>>> {name = {{.*}}} diff --git a/flang/test/Lower/OpenMP/optional-argument-map-2.f90 b/flang/test/Lower/OpenMP/optional-argument-map-2.f90 index 2eb18448e901f..7b67fd3cad379 100644 --- a/flang/test/Lower/OpenMP/optional-argument-map-2.f90 +++ b/flang/test/Lower/OpenMP/optional-argument-map-2.f90 @@ -73,7 +73,7 @@ end module mod ! CHECK-FPRIV: %[[VAL_14:.*]] = omp.map.bounds lower_bound(%[[VAL_10]] : index) upper_bound(%[[VAL_13]] : index) extent(%[[VAL_12]]#1 : index) stride(%[[VAL_11]] : index) start_idx(%[[VAL_10]] : index) {stride_in_bytes = true} ! CHECK-FPRIV: %[[VAL_16:.*]] = fir.box_offset %[[VAL_0]] base_addr : (!fir.ref>) -> !fir.llvm_ptr>> ! CHECK-FPRIV: %[[VAL_17:.*]] = omp.map.info var_ptr(%[[VAL_0]] : !fir.ref>, !fir.char<1,?>) map_clauses(tofrom) capture(ByRef) var_ptr_ptr(%[[VAL_16]] : !fir.llvm_ptr>>) bounds(%[[VAL_14]]) -> !fir.llvm_ptr>> {name = ""} -! CHECK-FPRIV: %[[VAL_18:.*]] = omp.map.info var_ptr(%[[VAL_0]] : !fir.ref>, !fir.boxchar<1>) map_clauses(to) capture(ByRef) members(%[[VAL_17]] : [0] : !fir.llvm_ptr>>) -> !fir.ref> +! CHECK-FPRIV: %[[VAL_18:.*]] = omp.map.info var_ptr(%[[VAL_0]] : !fir.ref>, !fir.boxchar<1>) map_clauses(always, to) capture(ByRef) members(%[[VAL_17]] : [0] : !fir.llvm_ptr>>) -> !fir.ref> ! CHECK-FPRIV: omp.target map_entries(%[[VAL_7]] -> %[[VAL_19:.*]], %[[VAL_18]] -> %[[VAL_20:.*]], %[[VAL_17]] -> %[[VAL_21:.*]] : !fir.ref>, !fir.ref>, !fir.llvm_ptr>>) private(@_QMmodFroutine_boxcharEa_firstprivate_boxchar_c8xU %[[VAL_3]]#0 -> %[[VAL_22:.*]] [map_idx=1] : !fir.boxchar<1>) { ! CHECK-FPRIV: %[[VAL_23:.*]] = arith.constant 4 : index ! CHECK-FPRIV: %[[VAL_24:.*]]:2 = hlfir.declare %[[VAL_19]] typeparams %[[VAL_23]] {uniq_name = "_QMmodFroutine_boxcharEb"} : (!fir.ref>, index) -> (!fir.ref>, !fir.ref>) @@ -104,7 +104,7 @@ end module mod ! CHECK-NO-FPRIV: %[[VAL_21:.*]] = omp.map.bounds lower_bound(%[[VAL_17]] : index) upper_bound(%[[VAL_20]] : index) extent(%[[VAL_19]]#1 : index) stride(%[[VAL_18]] : index) start_idx(%[[VAL_17]] : index) {stride_in_bytes = true} ! CHECK-NO-FPRIV: %[[VAL_22:.*]] = fir.box_offset %[[VAL_0]] base_addr : (!fir.ref>) -> !fir.llvm_ptr>> ! CHECK-NO-FPRIV: %[[VAL_23:.*]] = omp.map.info var_ptr(%[[VAL_0]] : !fir.ref>, !fir.char<1,?>) map_clauses(implicit, to) capture(ByRef) var_ptr_ptr(%[[VAL_22]] : !fir.llvm_ptr>>) bounds(%14) -> !fir.llvm_ptr>> {name = ""} -! CHECK-NO-FPRIV: %[[VAL_24:.*]] = omp.map.info var_ptr(%[[VAL_0]] : !fir.ref>, !fir.boxchar<1>) map_clauses(implicit, to) capture(ByRef) members(%[[VAL_23]] : [0] : !fir.llvm_ptr>>) -> !fir.ref> {name = ""} +! CHECK-NO-FPRIV: %[[VAL_24:.*]] = omp.map.info var_ptr(%[[VAL_0]] : !fir.ref>, !fir.boxchar<1>) map_clauses(always, implicit, to) capture(ByRef) members(%[[VAL_23]] : [0] : !fir.llvm_ptr>>) -> !fir.ref> {name = ""} ! CHECK-NO-FPRIV: omp.target map_entries(%[[VAL_7]] -> %[[VAL_25:.*]], %[[VAL_16]] -> %[[VAL_26:.*]], %[[VAL_24]] -> %[[VAL_27:.*]], %[[VAL_23]] -> %[[VAL_28:.*]] : !fir.ref>, !fir.ref>, !fir.ref>, !fir.llvm_ptr>>) { ! CHECK-NO-FPRIV: %[[VAL_29:.*]] = fir.load %[[VAL_27]] : !fir.ref> ! CHECK-NO-FPRIV: %[[VAL_30:.*]]:2 = fir.unboxchar %[[VAL_29]] : (!fir.boxchar<1>) -> (!fir.ref>, index) diff --git a/flang/test/Lower/OpenMP/optional-argument-map-3.f90 b/flang/test/Lower/OpenMP/optional-argument-map-3.f90 index 7e2a24e31123e..4dab002ca175a 100644 --- a/flang/test/Lower/OpenMP/optional-argument-map-3.f90 +++ b/flang/test/Lower/OpenMP/optional-argument-map-3.f90 @@ -33,7 +33,7 @@ end subroutine foo ! CHECK: } ! CHECK: %[[VAL_3:.*]] = fir.box_offset %[[VAL_0]] base_addr : (!fir.ref>>) -> !fir.llvm_ptr>> ! CHECK: %[[VAL_4:.*]] = omp.map.info var_ptr(%[[VAL_0]] : !fir.ref>>, f32) map_clauses(implicit, tofrom) capture(ByRef) var_ptr_ptr(%[[VAL_3]] : !fir.llvm_ptr>>) bounds(%{{.*}}) -> !fir.llvm_ptr>> {name = ""} -! CHECK: %[[VAL_5:.*]] = omp.map.info var_ptr(%[[VAL_0]] : !fir.ref>>, !fir.box>) map_clauses(implicit, to) capture(ByRef) members(%[[VAL_4]] : [0] : !fir.llvm_ptr>>) -> !fir.ref> {name = "dt"} +! CHECK: %[[VAL_5:.*]] = omp.map.info var_ptr(%[[VAL_0]] : !fir.ref>>, !fir.box>) map_clauses(always, implicit, to) capture(ByRef) members(%[[VAL_4]] : [0] : !fir.llvm_ptr>>) -> !fir.ref> {name = "dt"} ! CHECK: omp.target host_eval({{.*}}) map_entries({{.*}}%[[VAL_5]] -> {{.*}}, %[[VAL_4]] -> {{.*}} : {{.*}}) { ! CHECK: } else { ! CHECK: %[[VAL_6:.*]] = fir.is_present %[[VAL_1]]#1 : (!fir.box>) -> i1 @@ -42,5 +42,5 @@ end subroutine foo ! CHECK: } ! CHECK: %[[VAL_7:.*]] = fir.box_offset %[[VAL_0]] base_addr : (!fir.ref>>) -> !fir.llvm_ptr>> ! CHECK: %[[VAL_8:.*]] = omp.map.info var_ptr(%[[VAL_0]] : !fir.ref>>, f32) map_clauses(implicit, tofrom) capture(ByRef) var_ptr_ptr(%[[VAL_7]] : !fir.llvm_ptr>>) bounds(%{{.*}}) -> !fir.llvm_ptr>> {name = ""} -! CHECK: %[[VAL_9:.*]] = omp.map.info var_ptr(%[[VAL_0]] : !fir.ref>>, !fir.box>) map_clauses(implicit, to) capture(ByRef) members(%[[VAL_8]] : [0] : !fir.llvm_ptr>>) -> !fir.ref> {name = "dt"} +! CHECK: %[[VAL_9:.*]] = omp.map.info var_ptr(%[[VAL_0]] : !fir.ref>>, !fir.box>) map_clauses(always, implicit, to) capture(ByRef) members(%[[VAL_8]] : [0] : !fir.llvm_ptr>>) -> !fir.ref> {name = "dt"} ! CHECK: omp.target host_eval({{.*}}) map_entries({{.*}}, %[[VAL_9]] ->{{.*}}, %[[VAL_8]] -> {{.*}} : {{.*}}) { diff --git a/flang/test/Lower/OpenMP/target-enter-data-default-openmp52.f90 b/flang/test/Lower/OpenMP/target-enter-data-default-openmp52.f90 index 0d4fd964b71ec..5f7c31bb931f6 100644 --- a/flang/test/Lower/OpenMP/target-enter-data-default-openmp52.f90 +++ b/flang/test/Lower/OpenMP/target-enter-data-default-openmp52.f90 @@ -11,7 +11,7 @@ subroutine initialize() allocate(A) !$omp target enter data map(A) !CHECK-52: omp.map.info var_ptr(%2 : !fir.ref>>, f32) map_clauses(to) capture(ByRef) var_ptr_ptr(%5 : !fir.llvm_ptr>) -> !fir.llvm_ptr> {name = ""} - !CHECK-52: omp.map.info var_ptr(%2 : !fir.ref>>, !fir.box>) map_clauses(to) capture(ByRef) members(%6 : [0] : !fir.llvm_ptr>) -> !fir.ref>> {name = "a"} + !CHECK-52: omp.map.info var_ptr(%2 : !fir.ref>>, !fir.box>) map_clauses(always, to) capture(ByRef) members(%6 : [0] : !fir.llvm_ptr>) -> !fir.ref>> {name = "a"} !CHECK-51: to and alloc map types are permitted end subroutine initialize diff --git a/flang/test/Lower/OpenMP/target.f90 b/flang/test/Lower/OpenMP/target.f90 index 7cd642bcf23cf..d664dbefe1997 100644 --- a/flang/test/Lower/OpenMP/target.f90 +++ b/flang/test/Lower/OpenMP/target.f90 @@ -549,9 +549,9 @@ subroutine omp_target_device_addr !CHECK: %[[VAL_0:.*]] = fir.alloca !fir.box> {bindc_name = "a", uniq_name = "_QFomp_target_device_addrEa"} !CHECK: %[[VAL_0_DECL:.*]]:2 = hlfir.declare %[[VAL_0]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFomp_target_device_addrEa"} : (!fir.ref>>) -> (!fir.ref>>, !fir.ref>>) !CHECK: %[[MAP_MEMBERS:.*]] = omp.map.info var_ptr({{.*}} : !fir.ref>>, i32) map_clauses(tofrom) capture(ByRef) var_ptr_ptr({{.*}} : !fir.llvm_ptr>) -> !fir.llvm_ptr> {name = ""} - !CHECK: %[[MAP:.*]] = omp.map.info var_ptr({{.*}} : !fir.ref>>, !fir.box>) map_clauses(to) capture(ByRef) members(%[[MAP_MEMBERS]] : [0] : !fir.llvm_ptr>) -> !fir.ref>> {name = "a"} + !CHECK: %[[MAP:.*]] = omp.map.info var_ptr({{.*}} : !fir.ref>>, !fir.box>) map_clauses(always, to) capture(ByRef) members(%[[MAP_MEMBERS]] : [0] : !fir.llvm_ptr>) -> !fir.ref>> {name = "a"} !CHECK: %[[DEV_ADDR_MEMBERS:.*]] = omp.map.info var_ptr({{.*}} : !fir.ref>>, i32) map_clauses(return_param) capture(ByRef) var_ptr_ptr({{.*}} : !fir.llvm_ptr>) -> !fir.llvm_ptr> {name = ""} - !CHECK: %[[DEV_ADDR:.*]] = omp.map.info var_ptr({{.*}} : !fir.ref>>, !fir.box>) map_clauses(to) capture(ByRef) members(%[[DEV_ADDR_MEMBERS]] : [0] : !fir.llvm_ptr>) -> !fir.ref>> {name = "a"} + !CHECK: %[[DEV_ADDR:.*]] = omp.map.info var_ptr({{.*}} : !fir.ref>>, !fir.box>) map_clauses(always, to) capture(ByRef) members(%[[DEV_ADDR_MEMBERS]] : [0] : !fir.llvm_ptr>) -> !fir.ref>> {name = "a"} !CHECK: omp.target_data map_entries(%[[MAP]], %[[MAP_MEMBERS]] : {{.*}}) use_device_addr(%[[DEV_ADDR]] -> %[[ARG_0:.*]], %[[DEV_ADDR_MEMBERS]] -> %[[ARG_1:.*]] : !fir.ref>>, !fir.llvm_ptr>) { !$omp target data map(tofrom: a) use_device_addr(a) !CHECK: %[[VAL_1_DECL:.*]]:2 = hlfir.declare %[[ARG_0]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFomp_target_device_addrEa"} : (!fir.ref>>) -> (!fir.ref>>, !fir.ref>>) diff --git a/flang/test/Lower/volatile-openmp.f90 b/flang/test/Lower/volatile-openmp.f90 index d1a844eddd106..fb6cee40c71db 100644 --- a/flang/test/Lower/volatile-openmp.f90 +++ b/flang/test/Lower/volatile-openmp.f90 @@ -36,7 +36,7 @@ ! CHECK: %[[VAL_24:.*]] = fir.coordinate_of %[[VAL_13]]#0, array : (!fir.ref>>}>, volatile>) -> !fir.ref>>> ! CHECK: %[[VAL_25:.*]] = fir.box_offset %[[VAL_24]] base_addr : (!fir.ref>>>) -> !fir.llvm_ptr>> ! CHECK: %[[VAL_26:.*]] = omp.map.info var_ptr(%[[VAL_24]] : !fir.ref>>>, i32) map_clauses(to) capture(ByRef) var_ptr_ptr(%[[VAL_25]] : !fir.llvm_ptr>>) bounds(%[[VAL_23]]) -> !fir.llvm_ptr>> {name = ""} -! CHECK: %[[VAL_27:.*]] = omp.map.info var_ptr(%[[VAL_24]] : !fir.ref>>>, !fir.box>>) map_clauses(to) capture(ByRef) -> !fir.ref>>> {name = "container%[[VAL_28:.*]]"} +! CHECK: %[[VAL_27:.*]] = omp.map.info var_ptr(%[[VAL_24]] : !fir.ref>>>, !fir.box>>) map_clauses(always, to) capture(ByRef) -> !fir.ref>>> {name = "container%[[VAL_28:.*]]"} ! CHECK: %[[VAL_29:.*]] = omp.map.info var_ptr(%[[VAL_13]]#1 : !fir.ref>>}>, volatile>, !fir.type<_QFTt{array:!fir.box>>}>) map_clauses(to) capture(ByRef) members(%[[VAL_27]], %[[VAL_26]] : [0], [0, 0] : !fir.ref>>>, !fir.llvm_ptr>>) -> !fir.ref>>}>, volatile> {name = "container", partial_map = true} ! CHECK: omp.target_enter_data map_entries(%[[VAL_29]], %[[VAL_27]], %[[VAL_26]] : !fir.ref>>}>, volatile>, !fir.ref>>>, !fir.llvm_ptr>>) ! CHECK: %[[VAL_30:.*]] = fir.load %[[VAL_10]]#0 : !fir.ref>, volatile>, volatile> @@ -47,7 +47,7 @@ ! CHECK: %[[VAL_35:.*]] = omp.map.bounds lower_bound(%[[VAL_0]] : index) upper_bound(%[[VAL_34]] : index) extent(%[[VAL_33]]#1 : index) stride(%[[VAL_33]]#2 : index) start_idx(%[[VAL_32]]#0 : index) {stride_in_bytes = true} ! CHECK: %[[VAL_36:.*]] = fir.box_offset %[[VAL_10]]#1 base_addr : (!fir.ref>, volatile>, volatile>) -> !fir.llvm_ptr>> ! CHECK: %[[VAL_37:.*]] = omp.map.info var_ptr(%[[VAL_10]]#1 : !fir.ref>, volatile>, volatile>, i32) map_clauses(to) capture(ByRef) var_ptr_ptr(%[[VAL_36]] : !fir.llvm_ptr>>) bounds(%[[VAL_35]]) -> !fir.llvm_ptr>> {name = ""} -! CHECK: %[[VAL_38:.*]] = omp.map.info var_ptr(%[[VAL_10]]#1 : !fir.ref>, volatile>, volatile>, !fir.box>, volatile>) map_clauses(to) capture(ByRef) members(%[[VAL_37]] : [0] : !fir.llvm_ptr>>) -> !fir.ref>, volatile>, volatile> {name = "array1"} +! CHECK: %[[VAL_38:.*]] = omp.map.info var_ptr(%[[VAL_10]]#1 : !fir.ref>, volatile>, volatile>, !fir.box>, volatile>) map_clauses(always, to) capture(ByRef) members(%[[VAL_37]] : [0] : !fir.llvm_ptr>>) -> !fir.ref>, volatile>, volatile> {name = "array1"} ! CHECK: omp.target_enter_data map_entries(%[[VAL_38]], %[[VAL_37]] : !fir.ref>, volatile>, volatile>, !fir.llvm_ptr>>) ! CHECK: return ! CHECK: } diff --git a/flang/test/Transforms/omp-map-info-finalization.fir b/flang/test/Transforms/omp-map-info-finalization.fir index 5b0fd9f23d63d..a808b81e71356 100644 --- a/flang/test/Transforms/omp-map-info-finalization.fir +++ b/flang/test/Transforms/omp-map-info-finalization.fir @@ -32,11 +32,11 @@ func.func @test_descriptor_expansion_pass(%arg0: !fir.box>) { // CHECK: %[[BOUNDS:.*]] = omp.map.bounds lower_bound(%{{.*}} : index) upper_bound(%{{.*}} : index) extent(%{{.*}} : index) stride(%{{.*}} : index) start_idx(%{{.*}} : index) {stride_in_bytes = true} // CHECK: %[[BASE_ADDR_OFF:.*]] = fir.box_offset %[[DECLARE2]]#1 base_addr : (!fir.ref>>) -> !fir.llvm_ptr> // CHECK: %[[DESC_MEMBER_MAP:.*]] = omp.map.info var_ptr(%[[DECLARE2]]#1 : !fir.ref>>, i32) map_clauses(tofrom) capture(ByRef) var_ptr_ptr(%[[BASE_ADDR_OFF]] : !fir.llvm_ptr>) -> !fir.llvm_ptr> {name = ""} -// CHECK: %[[DESC_PARENT_MAP:.*]] = omp.map.info var_ptr(%[[DECLARE2]]#1 : !fir.ref>>, !fir.box>) map_clauses(to) capture(ByRef) members(%[[DESC_MEMBER_MAP]] : [0] : !fir.llvm_ptr>) -> !fir.ref>> +// CHECK: %[[DESC_PARENT_MAP:.*]] = omp.map.info var_ptr(%[[DECLARE2]]#1 : !fir.ref>>, !fir.box>) map_clauses(always, to) capture(ByRef) members(%[[DESC_MEMBER_MAP]] : [0] : !fir.llvm_ptr>) -> !fir.ref>> // CHECK: fir.store %[[DECLARE1]]#1 to %[[ALLOCA]] : !fir.ref>> // CHECK: %[[BASE_ADDR_OFF_2:.*]] = fir.box_offset %[[ALLOCA]] base_addr : (!fir.ref>>) -> !fir.llvm_ptr>> // CHECK: %[[DESC_MEMBER_MAP_2:.*]] = omp.map.info var_ptr(%[[ALLOCA]] : !fir.ref>>, i32) map_clauses(from) capture(ByRef) var_ptr_ptr(%[[BASE_ADDR_OFF_2]] : !fir.llvm_ptr>>) bounds(%[[BOUNDS]]) -> !fir.llvm_ptr>> {name = ""} -// CHECK: %[[DESC_PARENT_MAP_2:.*]] = omp.map.info var_ptr(%[[ALLOCA]] : !fir.ref>>, !fir.box>) map_clauses(to) capture(ByRef) members(%[[DESC_MEMBER_MAP_2]] : [0] : !fir.llvm_ptr>>) -> !fir.ref> +// CHECK: %[[DESC_PARENT_MAP_2:.*]] = omp.map.info var_ptr(%[[ALLOCA]] : !fir.ref>>, !fir.box>) map_clauses(always, to) capture(ByRef) members(%[[DESC_MEMBER_MAP_2]] : [0] : !fir.llvm_ptr>>) -> !fir.ref> // CHECK: omp.target map_entries(%[[DESC_PARENT_MAP]] -> %[[ARG1:.*]], %[[DESC_PARENT_MAP_2]] -> %[[ARG2:.*]], %[[DESC_MEMBER_MAP]] -> %[[ARG3:.*]], %[[DESC_MEMBER_MAP_2]] -> %[[ARG4:.*]] : {{.*}}) { // ----- @@ -112,7 +112,7 @@ func.func @dtype_alloca_op_block_add(%arg0: !fir.ref>) -> !fir.ref>>> // CHECK: %[[MEMBER_BASE_ADDR:.*]] = fir.box_offset %[[MEMBER_COORD:.*]] base_addr : (!fir.ref>>>) -> !fir.llvm_ptr>> // CHECK: %[[MAP_MEMBER_BASE_ADDR:.*]] = omp.map.info var_ptr(%[[MEMBER_COORD]] : !fir.ref>>>, i32) map_clauses(tofrom) capture(ByRef) var_ptr_ptr(%[[MEMBER_BASE_ADDR]] : !fir.llvm_ptr>>) bounds(%[[BOUNDS]]) -> !fir.llvm_ptr>> {{.*}} -// CHECK: %[[MAP_MEMBER_DESCRIPTOR:.*]] = omp.map.info var_ptr(%[[MEMBER_COORD]] : !fir.ref>>>, !fir.box>>) map_clauses(to) capture(ByRef) -> !fir.ref>>> {name = "one_l%array_j"} +// CHECK: %[[MAP_MEMBER_DESCRIPTOR:.*]] = omp.map.info var_ptr(%[[MEMBER_COORD]] : !fir.ref>>>, !fir.box>>) map_clauses(always, to) capture(ByRef) -> !fir.ref>>> {name = "one_l%array_j"} // CHECK: %[[MAP_MEMBER_PARENT:.*]] = omp.map.info var_ptr(%[[ALLOCA]]#0 : !fir.ref<[[REC_TY]]>>, [[REC_TY]]>) map_clauses(tofrom) capture(ByRef) members(%10, %9 : [4], [4, 0] : !fir.ref>>>, !fir.llvm_ptr>>) -> !fir.ref<[[REC_TY]]>> {{.*}} // CHECK: omp.target map_entries(%[[MAP_MEMBER_PARENT]] -> %[[ARG1:.*]], %[[MAP_MEMBER_DESCRIPTOR]] -> %[[ARG2:.*]], %[[MAP_MEMBER_BASE_ADDR]] -> %[[ARG3:.*]] : !fir.ref<[[REC_TY]]>>, !fir.ref>>>, !fir.llvm_ptr>>) { @@ -152,13 +152,13 @@ func.func @alloca_dtype_map_op_block_add(%arg0 : !fir.ref>>) -> !fir.ref>>> // CHECK: %[[ALLOCATABLE_MEMBER_BASE_ADDR:.*]] = fir.box_offset %[[ALLOCATABLE_MEMBER_COORD]] base_addr : (!fir.ref>>>) -> !fir.llvm_ptr>> // CHECK: %[[MAP_ALLOCA_MEMBER_BASE_ADDR:.*]] = omp.map.info var_ptr(%[[ALLOCATABLE_MEMBER_COORD]] : !fir.ref>>>, i32) map_clauses(tofrom) capture(ByRef) var_ptr_ptr(%[[ALLOCATABLE_MEMBER_BASE_ADDR]] : !fir.llvm_ptr>>) bounds(%[[BOUNDS]]) -> !fir.llvm_ptr>> {{.*}} -// CHECK: %[[MAP_ALLOCA_MEMBER_DESCRIPTOR:.*]] = omp.map.info var_ptr(%[[ALLOCATABLE_MEMBER_COORD]] : !fir.ref>>>, !fir.box>>) map_clauses(to) capture(ByRef) -> !fir.ref>>> {{.*}} +// CHECK: %[[MAP_ALLOCA_MEMBER_DESCRIPTOR:.*]] = omp.map.info var_ptr(%[[ALLOCATABLE_MEMBER_COORD]] : !fir.ref>>>, !fir.box>>) map_clauses(always, to) capture(ByRef) -> !fir.ref>>> {{.*}} // CHECK: %[[LOAD_ALLOCA2:.*]] = fir.load %[[ALLOCA]]#0 : !fir.ref>>> // CHECK: %[[REGULAR_MEMBER_COORD:.*]] = fir.coordinate_of %[[LOAD_ALLOCA2]], k : (!fir.box>>) -> !fir.ref // CHECK: %[[MAP_REGULAR_MEMBER:.*]] = omp.map.info var_ptr(%[[REGULAR_MEMBER_COORD]] : !fir.ref, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref {{.*}} // CHECK: %[[ALLOCATABLE_PARENT_BASE_ADDR:.*]] = fir.box_offset %[[ALLOCA]]#1 base_addr : (!fir.ref>>>) -> !fir.llvm_ptr>> // CHECK: %[[MAP_ALLOCA_PARENT_BASE_ADDR:.*]] = omp.map.info var_ptr(%[[ALLOCA]]#1 : !fir.ref>>>, !fir.type<[[REC_TY]]>) map_clauses(tofrom) capture(ByRef) var_ptr_ptr(%[[ALLOCATABLE_PARENT_BASE_ADDR]] : !fir.llvm_ptr>>) -> !fir.llvm_ptr>> {{.*}} -// CHECK: %[[MAP_PARENT_DESCRIPTOR:.*]] = omp.map.info var_ptr(%[[ALLOCA]]#1 : !fir.ref>>>, !fir.box>>) map_clauses(to) capture(ByRef) members(%18, %13, %12, %16 : [0], [0, 4], [0, 4, 0], [0, 5] : !fir.llvm_ptr>>, !fir.ref>>>, !fir.llvm_ptr>>, !fir.ref) -> !fir.ref>>> {{.*}} +// CHECK: %[[MAP_PARENT_DESCRIPTOR:.*]] = omp.map.info var_ptr(%[[ALLOCA]]#1 : !fir.ref>>>, !fir.box>>) map_clauses(always, to) capture(ByRef) members(%18, %13, %12, %16 : [0], [0, 4], [0, 4, 0], [0, 5] : !fir.llvm_ptr>>, !fir.ref>>>, !fir.llvm_ptr>>, !fir.ref) -> !fir.ref>>> {{.*}} // CHECK: omp.target map_entries(%[[MAP_PARENT_DESCRIPTOR]] -> %[[ARG1:.*]], %[[MAP_ALLOCA_PARENT_BASE_ADDR]] -> %[[ARG2:.*]], %[[MAP_ALLOCA_MEMBER_DESCRIPTOR]] -> %[[ARG3:.*]], %[[MAP_ALLOCA_MEMBER_BASE_ADDR]] -> %[[ARG4:.*]], %[[MAP_REGULAR_MEMBER]] -> %[[ARG5:.*]] : !fir.ref>>>, !fir.llvm_ptr>>, !fir.ref>>>, !fir.llvm_ptr>>, !fir.ref) { // ----- @@ -202,14 +202,14 @@ func.func @alloca_dtype_map_op_block_add(%arg0 : !fir.ref>) -> !fir.ref>>> // CHECK: %[[NESTED_ALLOCA_MEMBER_BASE_ADDR:.*]] = fir.box_offset %[[NESTED_ALLOCA_MEMBER]] base_addr : (!fir.ref>>>) -> !fir.llvm_ptr>> // CHECK: %[[MAP_NESTED_ALLOCA_MEMBER_BASE_ADDR:.*]] = omp.map.info var_ptr(%[[NESTED_ALLOCA_MEMBER]] : !fir.ref>>>, i32) map_clauses(tofrom) capture(ByRef) var_ptr_ptr(%[[NESTED_ALLOCA_MEMBER_BASE_ADDR]] : !fir.llvm_ptr>>) bounds(%[[BOUNDS]]) -> !fir.llvm_ptr>> {{.*}} -// CHECK: %[[MAP_NESTED_ALLOCA_MEMBER:.*]] = omp.map.info var_ptr(%[[NESTED_ALLOCA_MEMBER]] : !fir.ref>>>, !fir.box>>) map_clauses(to) capture(ByRef) -> !fir.ref>>> {{.*}} +// CHECK: %[[MAP_NESTED_ALLOCA_MEMBER:.*]] = omp.map.info var_ptr(%[[NESTED_ALLOCA_MEMBER]] : !fir.ref>>>, !fir.box>>) map_clauses(always, to) capture(ByRef) -> !fir.ref>>> {{.*}} // CHECK: %[[ALLOCA_LOAD2:.*]] = fir.load %[[ALLOCA]]#0 : !fir.ref>>> // CHECK: %[[INTERMEDIATE_DTYPE_NESTED_MEMBER2:.*]] = fir.coordinate_of %[[ALLOCA_LOAD2]], nest : (!fir.box>>) -> !fir.ref> // CHECK: %[[NESTED_REGULAR_MEMBER:.*]] = fir.coordinate_of %[[INTERMEDIATE_DTYPE_NESTED_MEMBER2]], k : (!fir.ref>) -> !fir.ref // CHECK: %[[MAP_NESTED_REGULAR_MEMBER:.*]] = omp.map.info var_ptr(%[[NESTED_REGULAR_MEMBER:.*]] : !fir.ref, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref {{.*}} // CHECK: %[[ALLOCATABLE_PARENT_BASE_ADDR:.*]] = fir.box_offset %[[ALLOCA]]#1 base_addr : (!fir.ref>>>) -> !fir.llvm_ptr>> // CHECK: %[[MAP_ALLOCATABLE_PARENT_BASE_ADDR:.*]] = omp.map.info var_ptr(%[[ALLOCA]]#1 : !fir.ref>>>, !fir.type<[[REC_TY]]>) map_clauses(tofrom) capture(ByRef) var_ptr_ptr(%[[ALLOCATABLE_PARENT_BASE_ADDR]] : !fir.llvm_ptr>>) -> !fir.llvm_ptr>> {{.*}} -// CHECK: %[[MAP_ALLOCATABLE_PARENT_DESCRIPTOR:.*]] = omp.map.info var_ptr(%[[ALLOCA]]#1 : !fir.ref>>>, !fir.box>>) map_clauses(to) capture(ByRef) members(%21, %15, %14, %19 : [0], [0, 6, 2], [0, 6, 2, 0], [0, 6, 3] : !fir.llvm_ptr>>, !fir.ref>>>, !fir.llvm_ptr>>, !fir.ref) -> !fir.ref>>> {{.*}} +// CHECK: %[[MAP_ALLOCATABLE_PARENT_DESCRIPTOR:.*]] = omp.map.info var_ptr(%[[ALLOCA]]#1 : !fir.ref>>>, !fir.box>>) map_clauses(always, to) capture(ByRef) members(%21, %15, %14, %19 : [0], [0, 6, 2], [0, 6, 2, 0], [0, 6, 3] : !fir.llvm_ptr>>, !fir.ref>>>, !fir.llvm_ptr>>, !fir.ref) -> !fir.ref>>> {{.*}} // CHECK: omp.target map_entries(%[[MAP_ALLOCATABLE_PARENT_DESCRIPTOR]] -> %[[ARG1:.*]], %[[MAP_ALLOCATABLE_PARENT_BASE_ADDR]] -> %[[ARG2:.*]], %[[MAP_NESTED_ALLOCA_MEMBER]] -> %[[ARG3:.*]], %[[MAP_NESTED_ALLOCA_MEMBER_BASE_ADDR]] -> %[[ARG4:.*]], %[[MAP_NESTED_REGULAR_MEMBER]] -> %[[ARG5:.*]] : !fir.ref>>>, !fir.llvm_ptr>>, !fir.ref>>>, !fir.llvm_ptr>>, !fir.ref) { // ----- @@ -245,7 +245,7 @@ func.func @alloca_dtype_map_op_block_add(%arg0 : !fir.ref>) -> !fir.ref>>> // CHECK: %[[ALLOCATABLE_MEMBER_BASE_ADDR:.*]] = fir.box_offset %[[ALLOCATABLE_MEMBER]] base_addr : (!fir.ref>>>) -> !fir.llvm_ptr>> // CHECK: %[[MAP_ALLOCATABLE_MEMBER_BASE_ADDR:.*]] = omp.map.info var_ptr(%[[ALLOCATABLE_MEMBER]] : !fir.ref>>>, i32) map_clauses(tofrom) capture(ByRef) var_ptr_ptr(%[[ALLOCATABLE_MEMBER_BASE_ADDR]] : !fir.llvm_ptr>>) bounds(%[[BOUNDS]]) -> !fir.llvm_ptr>> {{.*}} -// CHECK: %[[MAP_ALLOCATABLE_MEMBER_DESCRIPTOR:.*]] = omp.map.info var_ptr(%[[ALLOCATABLE_MEMBER]] : !fir.ref>>>, !fir.box>>) map_clauses(to) capture(ByRef) -> !fir.ref>>> {{.*}} +// CHECK: %[[MAP_ALLOCATABLE_MEMBER_DESCRIPTOR:.*]] = omp.map.info var_ptr(%[[ALLOCATABLE_MEMBER]] : !fir.ref>>>, !fir.box>>) map_clauses(always, to) capture(ByRef) -> !fir.ref>>> {{.*}} // CHECK: %[[MAP_PARENT:.*]] = omp.map.info var_ptr(%[[ALLOCA]]#0 : !fir.ref>, !fir.type<[[REC_TY]]>) map_clauses(tofrom) capture(ByRef) members(%12, %11 : [6, 2], [6, 2, 0] : !fir.ref>>>, !fir.llvm_ptr>>) -> !fir.ref> {{.*}} // CHECK: omp.target map_entries(%[[MAP_PARENT]] -> %[[ARG1:.*]], %[[MAP_ALLOCATABLE_MEMBER_DESCRIPTOR]] -> %[[ARG2:.*]], %[[MAP_ALLOCATABLE_MEMBER_BASE_ADDR]] -> %[[ARG3:.*]] : !fir.ref>, !fir.ref>>>, !fir.llvm_ptr>>) { @@ -278,13 +278,13 @@ func.func @alloca_dtype_map_op_block_add(%arg0 : !fir.ref>) -> !fir.ref>>,vertexy:!fir.box>>}]]>>>>> // CHECK: %[[BASE_ADDR_1:.*]] = fir.box_offset %[[DESC_1]] base_addr : (!fir.ref>>>>) -> !fir.llvm_ptr>>> // CHECK: %[[BASE_ADDR_MAP_1:.*]] = omp.map.info var_ptr(%[[DESC_1]] : !fir.ref>>>>, !fir.type<[[REC_TY2]]>) map_clauses(storage) capture(ByRef) var_ptr_ptr(%[[BASE_ADDR_1]] : !fir.llvm_ptr>>>) bounds(%{{.*}}) -> !fir.llvm_ptr>>> {{.*}} -// CHECK: %[[DESC_MAP_1:.*]] = omp.map.info var_ptr(%[[DESC_1]] : !fir.ref>>>>, !fir.box>>>) map_clauses(to) capture(ByRef) -> !fir.ref>>>> {{.*}} +// CHECK: %[[DESC_MAP_1:.*]] = omp.map.info var_ptr(%[[DESC_1]] : !fir.ref>>>>, !fir.box>>>) map_clauses(always, to) capture(ByRef) -> !fir.ref>>>> {{.*}} // CHECK: %[[DESC_LD_1:.*]] = fir.load %[[DESC_1]] : !fir.ref>>>> // CHECK: %[[MEMBER_ACCESS_1:.*]] = fir.coordinate_of %[[DESC_LD_1]], %{{.*}} : (!fir.box>>>, index) -> !fir.ref> // CHECK: %[[DESC_2:.*]] = fir.coordinate_of %[[MEMBER_ACCESS_1]], vertexy : (!fir.ref>) -> !fir.ref>>> // CHECK: %[[BASE_ADDR_2:.*]] = fir.box_offset %[[DESC_2]] base_addr : (!fir.ref>>>) -> !fir.llvm_ptr>> // CHECK: %[[BASE_ADDR_MAP_2:.*]] = omp.map.info var_ptr(%[[DESC_2]] : !fir.ref>>>, i32) map_clauses(tofrom) capture(ByRef) var_ptr_ptr(%[[BASE_ADDR_2]] : !fir.llvm_ptr>>) bounds(%{{.*}}) -> !fir.llvm_ptr>> {{.*}} -// CHECK: %[[DESC_MAP_2:.*]] = omp.map.info var_ptr(%[[DESC_2]] : !fir.ref>>>, !fir.box>>) map_clauses(to) capture(ByRef) -> !fir.ref>>> {{.*}} +// CHECK: %[[DESC_MAP_2:.*]] = omp.map.info var_ptr(%[[DESC_2]] : !fir.ref>>>, !fir.box>>) map_clauses(always, to) capture(ByRef) -> !fir.ref>>> {{.*}} // CHECK: %[[TOP_PARENT_MAP:.*]] = omp.map.info var_ptr(%0#1 : !fir.ref>, !fir.type<[[REC_TY]]>) map_clauses(storage) capture(ByRef) members(%6, %5, %14, %13 : [1], [1, 0], [1, 0, 2], [1, 0, 2, 0] : !fir.ref>>>>, !fir.llvm_ptr>>>, !fir.ref>>>, !fir.llvm_ptr>>) -> !fir.ref> {{{.*}} partial_map = true} // CHECK: omp.target map_entries(%[[TOP_PARENT_MAP]] -> %{{.*}}, %[[DESC_MAP_1]] -> %{{.*}}, %[[BASE_ADDR_MAP_1]] -> %{{.*}}, %[[DESC_MAP_2]] -> %{{.*}}, %[[BASE_ADDR_MAP_2]] -> %{{.*}} : !fir.ref>, !fir.ref>>>>, !fir.llvm_ptr>>>, !fir.ref>>>, !fir.llvm_ptr>>) { @@ -383,7 +383,7 @@ func.func @_QPrealtest(%arg0: !fir.boxchar<1>) { // CHECK: %[[VAL_10:.*]] = omp.map.bounds lower_bound(%[[VAL_6]] : index) upper_bound(%[[VAL_9]] : index) extent(%[[VAL_8]]#1 : index) stride(%[[VAL_7]] : index) start_idx(%[[VAL_6]] : index) {stride_in_bytes = true} // CHECK: %[[VAL_12:.*]] = fir.box_offset %[[VAL_0]] base_addr : (!fir.ref>) -> !fir.llvm_ptr>> // CHECK: %[[VAL_13:.*]] = omp.map.info var_ptr(%[[VAL_0]] : !fir.ref>, !fir.char<1,?>) map_clauses(to) capture(ByRef) var_ptr_ptr(%[[VAL_12]] : !fir.llvm_ptr>>) bounds(%[[VAL_10]]) -> !fir.llvm_ptr>> -// CHECK: %[[VAL_14:.*]] = omp.map.info var_ptr(%[[VAL_0]] : !fir.ref>, !fir.boxchar<1>) map_clauses(to) capture(ByRef) members(%[[VAL_13]] : [0] : !fir.llvm_ptr>>) -> !fir.ref> +// CHECK: %[[VAL_14:.*]] = omp.map.info var_ptr(%[[VAL_0]] : !fir.ref>, !fir.boxchar<1>) map_clauses(always, to) capture(ByRef) members(%[[VAL_13]] : [0] : !fir.llvm_ptr>>) -> !fir.ref> // CHECK: omp.target map_entries(%[[VAL_14]] -> %[[VAL_15:.*]], %[[VAL_13]] -> %[[VAL_16:.*]] : !fir.ref>, !fir.llvm_ptr>>) private(@boxchar.privatizer %[[VAL_3]]#0 -> %[[VAL_17:.*]] [map_idx=0] : !fir.boxchar<1>) { // CHECK: %[[VAL_18:.*]]:2 = fir.unboxchar %[[VAL_17]] : (!fir.boxchar<1>) -> (!fir.ref>, index) // CHECK: %[[VAL_19:.*]]:2 = hlfir.declare %[[VAL_18]]#0 typeparams %[[VAL_18]]#1 {uniq_name = "tgt_a0"} : (!fir.ref>, index) -> (!fir.boxchar<1>, !fir.ref>) diff --git a/mlir/include/mlir/Dialect/OpenMP/OpenMPEnums.td b/mlir/include/mlir/Dialect/OpenMP/OpenMPEnums.td index d9882cbcb5977..dfdc0b2803763 100644 --- a/mlir/include/mlir/Dialect/OpenMP/OpenMPEnums.td +++ b/mlir/include/mlir/Dialect/OpenMP/OpenMPEnums.td @@ -40,13 +40,15 @@ class OpenMP_EnumAttr // capture_clause enum. //===----------------------------------------------------------------------===// -def CaptureClauseTo : I32EnumAttrCase<"to", 0>; -def CaptureClauseLink : I32EnumAttrCase<"link", 1>; -def CaptureClauseEnter : I32EnumAttrCase<"enter", 2>; +def CaptureClauseNone : I32EnumAttrCase<"none", 0>; +def CaptureClauseTo : I32EnumAttrCase<"to", 1>; +def CaptureClauseLink : I32EnumAttrCase<"link", 2>; +def CaptureClauseEnter : I32EnumAttrCase<"enter", 3>; def DeclareTargetCaptureClause : OpenMP_I32EnumAttr< "DeclareTargetCaptureClause", "capture clause", [ + CaptureClauseNone, CaptureClauseTo, CaptureClauseLink, CaptureClauseEnter diff --git a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp index eb36e68d5ff58..a62bfeb400ee2 100644 --- a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp +++ b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp @@ -3632,10 +3632,23 @@ convertToCaptureClauseKind( return llvm::OffloadEntriesInfoManager::OMPTargetGlobalVarEntryLink; case mlir::omp::DeclareTargetCaptureClause::enter: return llvm::OffloadEntriesInfoManager::OMPTargetGlobalVarEntryEnter; + case mlir::omp::DeclareTargetCaptureClause::none: + return llvm::OffloadEntriesInfoManager::OMPTargetGlobalVarEntryNone; } llvm_unreachable("unhandled capture clause"); } +static Operation *getGlobalOpFromValue(Value value) { + Operation *op = value.getDefiningOp(); + if (auto addrCast = dyn_cast_if_present(op)) + op = addrCast->getOperand(0).getDefiningOp(); + if (auto addressOfOp = dyn_cast_if_present(op)) { + auto modOp = addressOfOp->getParentOfType(); + return modOp.lookupSymbol(addressOfOp.getGlobalName()); + } + return nullptr; +} + static llvm::SmallString<64> getDeclareTargetRefPtrSuffix(LLVM::GlobalOp globalOp, llvm::OpenMPIRBuilder &ompBuilder) { @@ -3658,62 +3671,58 @@ getDeclareTargetRefPtrSuffix(LLVM::GlobalOp globalOp, return suffix; } -static bool isDeclareTargetLink(mlir::Value value) { - if (auto addressOfOp = value.getDefiningOp()) { - auto modOp = addressOfOp->getParentOfType(); - Operation *gOp = modOp.lookupSymbol(addressOfOp.getGlobalName()); - if (auto declareTargetGlobal = - llvm::dyn_cast(gOp)) - if (declareTargetGlobal.getDeclareTargetCaptureClause() == - mlir::omp::DeclareTargetCaptureClause::link) - return true; - } +static bool isDeclareTargetLink(Value value) { + if (auto declareTargetGlobal = + dyn_cast_if_present( + getGlobalOpFromValue(value))) + if (declareTargetGlobal.getDeclareTargetCaptureClause() == + omp::DeclareTargetCaptureClause::link) + return true; return false; } -// Returns the reference pointer generated by the lowering of the declare target -// operation in cases where the link clause is used or the to clause is used in -// USM mode. +static bool isDeclareTargetTo(Value value) { + if (auto declareTargetGlobal = + dyn_cast_if_present( + getGlobalOpFromValue(value))) + if (declareTargetGlobal.getDeclareTargetCaptureClause() == + omp::DeclareTargetCaptureClause::to || + declareTargetGlobal.getDeclareTargetCaptureClause() == + omp::DeclareTargetCaptureClause::enter) + return true; + return false; +} + +// Returns the reference pointer generated by the lowering of the declare +// target operation in cases where the link clause is used or the to clause is +// used in USM mode. static llvm::Value * -getRefPtrIfDeclareTarget(mlir::Value value, +getRefPtrIfDeclareTarget(Value value, LLVM::ModuleTranslation &moduleTranslation) { llvm::OpenMPIRBuilder *ompBuilder = moduleTranslation.getOpenMPBuilder(); - Operation *op = value.getDefiningOp(); - if (auto addrCast = llvm::dyn_cast_if_present(op)) - op = addrCast->getOperand(0).getDefiningOp(); - - // An easier way to do this may just be to keep track of any pointer - // references and their mapping to their respective operation - if (auto addressOfOp = llvm::dyn_cast_if_present(op)) { - if (auto gOp = llvm::dyn_cast_or_null( - addressOfOp->getParentOfType().lookupSymbol( - addressOfOp.getGlobalName()))) { - - if (auto declareTargetGlobal = - llvm::dyn_cast( - gOp.getOperation())) { - - // In this case, we must utilise the reference pointer generated by the - // declare target operation, similar to Clang - if ((declareTargetGlobal.getDeclareTargetCaptureClause() == - mlir::omp::DeclareTargetCaptureClause::link) || - (declareTargetGlobal.getDeclareTargetCaptureClause() == - mlir::omp::DeclareTargetCaptureClause::to && - ompBuilder->Config.hasRequiresUnifiedSharedMemory())) { - llvm::SmallString<64> suffix = - getDeclareTargetRefPtrSuffix(gOp, *ompBuilder); - - if (gOp.getSymName().contains(suffix)) - return moduleTranslation.getLLVMModule()->getNamedValue( - gOp.getSymName()); + if (auto gOp = + dyn_cast_or_null(getGlobalOpFromValue(value))) { + if (auto declareTargetGlobal = + dyn_cast(gOp.getOperation())) { + // In this case, we must utilise the reference pointer generated by + // the declare target operation, similar to Clang + if ((declareTargetGlobal.getDeclareTargetCaptureClause() == + omp::DeclareTargetCaptureClause::link) || + (declareTargetGlobal.getDeclareTargetCaptureClause() == + omp::DeclareTargetCaptureClause::to && + ompBuilder->Config.hasRequiresUnifiedSharedMemory())) { + llvm::SmallString<64> suffix = + getDeclareTargetRefPtrSuffix(gOp, *ompBuilder); + if (gOp.getSymName().contains(suffix)) return moduleTranslation.getLLVMModule()->getNamedValue( - (gOp.getSymName().str() + suffix.str()).str()); - } + gOp.getSymName()); + + return moduleTranslation.getLLVMModule()->getNamedValue( + (gOp.getSymName().str() + suffix.str()).str()); } } } - return nullptr; } @@ -3756,6 +3765,32 @@ struct MapInfoData : MapInfosTy { MapInfosTy::append(CurInfo); } }; + +enum class TargetDirectiveEnumTy : uint32_t { + None = 0, + Target = 1, + TargetData = 2, + TargetEnterData = 3, + TargetExitData = 4, + TargetUpdate = 5 +}; + +static TargetDirectiveEnumTy getTargetDirectiveEnumTyFromOp(Operation *op) { + return llvm::TypeSwitch(op) + .Case([](omp::TargetDataOp) { return TargetDirectiveEnumTy::TargetData; }) + .Case([](omp::TargetEnterDataOp) { + return TargetDirectiveEnumTy::TargetEnterData; + }) + .Case([&](omp::TargetExitDataOp) { + return TargetDirectiveEnumTy::TargetExitData; + }) + .Case([&](omp::TargetUpdateOp) { + return TargetDirectiveEnumTy::TargetUpdate; + }) + .Case([&](omp::TargetOp) { return TargetDirectiveEnumTy::Target; }) + .Default([&](Operation *op) { return TargetDirectiveEnumTy::None; }); +} + } // namespace static uint64_t getArrayElementSizeInBits(LLVM::LLVMArrayType arrTy, @@ -3787,7 +3822,7 @@ static llvm::Value *getSizeInBytes(DataLayout &dl, const mlir::Type &type, // This calculates the size to transfer based on bounds and the underlying // element type, provided bounds have been specified (Fortran // pointers/allocatables/target and arrays that have sections specified fall - // into this as well). + // into this as well) if (!memberClause.getBounds().empty()) { llvm::Value *elementCount = builder.getInt64(1); for (auto bounds : memberClause.getBounds()) { @@ -3910,10 +3945,12 @@ static void collectMapDataFromMapOperands( mapData.Pointers.push_back(mapData.OriginalValue.back()); if (llvm::Value *refPtr = - getRefPtrIfDeclareTarget(offloadPtr, - moduleTranslation)) { // declare target + getRefPtrIfDeclareTarget(offloadPtr, moduleTranslation)) { mapData.IsDeclareTarget.push_back(true); mapData.BasePointers.push_back(refPtr); + } else if (isDeclareTargetTo(offloadPtr)) { + mapData.IsDeclareTarget.push_back(true); + mapData.BasePointers.push_back(mapData.OriginalValue.back()); } else { // regular mapped variable mapData.IsDeclareTarget.push_back(false); mapData.BasePointers.push_back(mapData.OriginalValue.back()); @@ -4269,12 +4306,11 @@ static bool checkIfPointerMap(omp::MapInfoOp mapOp) { // // This function borrows a lot from Clang's emitCombinedEntry function // inside of CGOpenMPRuntime.cpp -static llvm::omp::OpenMPOffloadMappingFlags -mapParentWithMembers(LLVM::ModuleTranslation &moduleTranslation, - llvm::IRBuilderBase &builder, - llvm::OpenMPIRBuilder &ompBuilder, DataLayout &dl, - MapInfosTy &combinedInfo, MapInfoData &mapData, - uint64_t mapDataIndex, TargetDirective targetDirective) { +static llvm::omp::OpenMPOffloadMappingFlags mapParentWithMembers( + LLVM::ModuleTranslation &moduleTranslation, llvm::IRBuilderBase &builder, + llvm::OpenMPIRBuilder &ompBuilder, DataLayout &dl, MapInfosTy &combinedInfo, + MapInfoData &mapData, uint64_t mapDataIndex, + TargetDirectiveEnumTy targetDirective) { assert(!ompBuilder.Config.isTargetDevice() && "function only supported for host device codegen"); @@ -4283,7 +4319,8 @@ mapParentWithMembers(LLVM::ModuleTranslation &moduleTranslation, // base entry so the mapper receives correct copy semantics via its 'type' // parameter. Also keep TARGET_PARAM when required for kernel arguments. llvm::omp::OpenMPOffloadMappingFlags baseFlag = - isTargetParams + (targetDirective == TargetDirectiveEnumTy::Target && + !mapData.IsDeclareTarget[mapDataIndex]) ? llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TARGET_PARAM : llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_NONE; @@ -4368,7 +4405,7 @@ mapParentWithMembers(LLVM::ModuleTranslation &moduleTranslation, llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_CLOSE; ompBuilder.setCorrectMemberOfFlag(mapFlag, memberOfFlag); - if (targetDirective == TargetDirective::TargetUpdate || hasMapClose) { + if (targetDirective == TargetDirectiveEnumTy::TargetUpdate || hasMapClose) { combinedInfo.Types.emplace_back(mapFlag); combinedInfo.DevicePointers.emplace_back( mapData.DevicePointers[mapDataIndex]); @@ -4450,7 +4487,7 @@ static void processMapMembersWithParent( llvm::OpenMPIRBuilder &ompBuilder, DataLayout &dl, MapInfosTy &combinedInfo, MapInfoData &mapData, uint64_t mapDataIndex, llvm::omp::OpenMPOffloadMappingFlags memberOfFlag, - TargetDirective targetDirective) { + TargetDirectiveEnumTy targetDirective) { assert(!ompBuilder.Config.isTargetDevice() && "function only supported for host device codegen"); @@ -4495,8 +4532,15 @@ static void processMapMembersWithParent( mapFlag &= ~llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TARGET_PARAM; mapFlag |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_MEMBER_OF; ompBuilder.setCorrectMemberOfFlag(mapFlag, memberOfFlag); - if (checkIfPointerMap(memberClause)) + bool isDeclTargetTo = isDeclareTargetTo(parentClause.getVarPtr() + ? parentClause.getVarPtr() + : parentClause.getVarPtrPtr()); + if (checkIfPointerMap(memberClause) && + (!isDeclTargetTo || + (targetDirective != TargetDirectiveEnumTy::TargetUpdate && + targetDirective != TargetDirectiveEnumTy::TargetData))) { mapFlag |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_PTR_AND_OBJ; + } combinedInfo.Types.emplace_back(mapFlag); combinedInfo.DevicePointers.emplace_back( @@ -4523,7 +4567,7 @@ static void processMapMembersWithParent( static void processIndividualMap(MapInfoData &mapData, size_t mapDataIdx, MapInfosTy &combinedInfo, - TargetDirective targetDirective, + TargetDirectiveEnumTy targetDirective, int mapDataParentIdx = -1) { // Declare Target Mappings are excluded from being marked as // OMP_MAP_TARGET_PARAM as they are not passed as parameters, they're @@ -4535,7 +4579,8 @@ static void processIndividualMap(MapInfoData &mapData, size_t mapDataIdx, if (isPtrTy) mapFlag |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_PTR_AND_OBJ; - if (isTargetParams && !mapData.IsDeclareTarget[mapDataIdx]) + if (targetDirective == TargetDirectiveEnumTy::Target && + !mapData.IsDeclareTarget[mapDataIdx]) mapFlag |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TARGET_PARAM; if (mapInfoOp.getMapCaptureType() == omp::VariableCaptureKind::ByCopy && @@ -4564,7 +4609,7 @@ static void processMapWithMembersOf(LLVM::ModuleTranslation &moduleTranslation, llvm::OpenMPIRBuilder &ompBuilder, DataLayout &dl, MapInfosTy &combinedInfo, MapInfoData &mapData, uint64_t mapDataIndex, - TargetDirective targetDirective) { + TargetDirectiveEnumTy targetDirective) { assert(!ompBuilder.Config.isTargetDevice() && "function only supported for host device codegen"); @@ -4588,17 +4633,18 @@ static void processMapWithMembersOf(LLVM::ModuleTranslation &moduleTranslation, // Clang maps array without bounds as pointers (which we do not // currently do), whereas we treat them as arrays in all cases // currently. - processIndividualMap(mapData, memberDataIdx, combinedInfo, isTargetParams, + processIndividualMap(mapData, memberDataIdx, combinedInfo, targetDirective, mapDataIndex); return; } llvm::omp::OpenMPOffloadMappingFlags memberOfParentFlag = mapParentWithMembers(moduleTranslation, builder, ompBuilder, dl, - combinedInfo, mapData, mapDataIndex, isTargetParams); + combinedInfo, mapData, mapDataIndex, + targetDirective); processMapMembersWithParent(moduleTranslation, builder, ompBuilder, dl, combinedInfo, mapData, mapDataIndex, - memberOfParentFlag); + memberOfParentFlag, targetDirective); } // This is a variation on Clang's GenerateOpenMPCapturedVars, which @@ -4676,10 +4722,10 @@ createAlteredByCaptureMap(MapInfoData &mapData, static void genMapInfos(llvm::IRBuilderBase &builder, LLVM::ModuleTranslation &moduleTranslation, DataLayout &dl, MapInfosTy &combinedInfo, - MapInfoData &mapData, TargetDirective targetDirective) { + MapInfoData &mapData, + TargetDirectiveEnumTy targetDirective) { assert(!moduleTranslation.getOpenMPBuilder()->Config.isTargetDevice() && "function only supported for host device codegen"); - // We wish to modify some of the methods in which arguments are // passed based on their capture type by the target region, this can // involve generating new loads and stores, which changes the @@ -4709,11 +4755,11 @@ static void genMapInfos(llvm::IRBuilderBase &builder, auto mapInfoOp = dyn_cast(mapData.MapClause[i]); if (!mapInfoOp.getMembers().empty()) { processMapWithMembersOf(moduleTranslation, builder, *ompBuilder, dl, - combinedInfo, mapData, i, isTargetParams); + combinedInfo, mapData, i, targetDirective); continue; } - processIndividualMap(mapData, i, combinedInfo, isTargetParams); + processIndividualMap(mapData, i, combinedInfo, targetDirective); } } @@ -4721,12 +4767,12 @@ static llvm::Expected emitUserDefinedMapper(Operation *declMapperOp, llvm::IRBuilderBase &builder, LLVM::ModuleTranslation &moduleTranslation, llvm::StringRef mapperFuncName, - TargetDirective targetDirective); + TargetDirectiveEnumTy targetDirective); static llvm::Expected getOrCreateUserDefinedMapperFunc(Operation *op, llvm::IRBuilderBase &builder, LLVM::ModuleTranslation &moduleTranslation, - TargetDirective targetDirective) { + TargetDirectiveEnumTy targetDirective) { assert(!moduleTranslation.getOpenMPBuilder()->Config.isTargetDevice() && "function only supported for host device codegen"); auto declMapperOp = cast(op); @@ -4745,7 +4791,7 @@ static llvm::Expected emitUserDefinedMapper(Operation *op, llvm::IRBuilderBase &builder, LLVM::ModuleTranslation &moduleTranslation, llvm::StringRef mapperFuncName, - TargetDirective targetDirective) { + TargetDirectiveEnumTy targetDirective) { assert(!moduleTranslation.getOpenMPBuilder()->Config.isTargetDevice() && "function only supported for host device codegen"); auto declMapperOp = cast(op); @@ -4776,8 +4822,8 @@ emitUserDefinedMapper(Operation *op, llvm::IRBuilderBase &builder, genMapInfos(builder, moduleTranslation, dl, combinedInfo, mapData, targetDirective); - // Drop the mapping that is no longer necessary so that the same region can - // be processed multiple times. + // Drop the mapping that is no longer necessary so that the same region + // can be processed multiple times. moduleTranslation.forgetMapping(declMapperOp.getRegion()); return combinedInfo; }; @@ -4807,10 +4853,12 @@ convertOmpTargetData(Operation *op, llvm::IRBuilderBase &builder, SmallVector useDeviceAddrVars; llvm::omp::RuntimeFunction RTLFn; DataLayout DL = DataLayout(op->getParentOfType()); + TargetDirectiveEnumTy targetDirective = getTargetDirectiveEnumTyFromOp(op); llvm::OpenMPIRBuilder *ompBuilder = moduleTranslation.getOpenMPBuilder(); - llvm::OpenMPIRBuilder::TargetDataInfo info(/*RequiresDevicePointerInfo=*/true, - /*SeparateBeginEndCalls=*/true); + llvm::OpenMPIRBuilder::TargetDataInfo info( + /*RequiresDevicePointerInfo=*/true, + /*SeparateBeginEndCalls=*/true); bool isTargetDevice = ompBuilder->Config.isTargetDevice(); bool isOffloadEntry = isTargetDevice || !ompBuilder->Config.TargetTriples.empty(); @@ -4909,7 +4957,8 @@ convertOmpTargetData(Operation *op, llvm::IRBuilderBase &builder, MapInfosTy combinedInfo; auto genMapInfoCB = [&](InsertPointTy codeGenIP) -> MapInfosTy & { builder.restoreIP(codeGenIP); - genMapInfos(builder, moduleTranslation, DL, combinedInfo, mapData); + genMapInfos(builder, moduleTranslation, DL, combinedInfo, mapData, + targetDirective); return combinedInfo; }; @@ -5287,11 +5336,16 @@ handleDeclareTargetMapVar(MapInfoData &mapData, for (llvm::User *user : userVec) { if (auto *insn = dyn_cast(user)) { if (insn->getFunction() == func) { - builder.SetCurrentDebugLocation(insn->getDebugLoc()); - auto *load = builder.CreateLoad(mapData.BasePointers[i]->getType(), - mapData.BasePointers[i]); - load->moveBefore(insn->getIterator()); - user->replaceUsesOfWith(mapData.OriginalValue[i], load); + auto mapOp = cast(mapData.MapClause[i]); + llvm::Value *substitute = mapData.BasePointers[i]; + if (isDeclareTargetLink(mapOp.getVarPtrPtr() ? mapOp.getVarPtrPtr() + : mapOp.getVarPtr())) { + builder.SetCurrentDebugLocation(insn->getDebugLoc()); + substitute = builder.CreateLoad( + mapData.BasePointers[i]->getType(), mapData.BasePointers[i]); + cast(substitute)->moveBefore(insn->getIterator()); + } + user->replaceUsesOfWith(mapData.OriginalValue[i], substitute); } } } @@ -5583,8 +5637,8 @@ initTargetDefaultAttrs(omp::TargetOp targetOp, Operation *capturedOp, int32_t minTeamsVal = 1, maxTeamsVal = -1; if (castOrGetParentOfType(capturedOp)) { - // TODO: Use `hostNumTeamsLower` to initialize `minTeamsVal`. For now, match - // clang and set min and max to the same value. + // TODO: Use `hostNumTeamsLower` to initialize `minTeamsVal`. For now, + // match clang and set min and max to the same value. if (numTeamsUpper) { if (auto val = extractConstInteger(numTeamsUpper)) minTeamsVal = maxTeamsVal = *val; @@ -5776,9 +5830,9 @@ convertOmpTarget(Operation &opInst, llvm::IRBuilderBase &builder, auto parentFn = opInst.getParentOfType(); auto argIface = cast(opInst); auto &targetRegion = targetOp.getRegion(); - // Holds the private vars that have been mapped along with the block argument - // that corresponds to the MapInfoOp corresponding to the private var in - // question. So, for instance: + // Holds the private vars that have been mapped along with the block + // argument that corresponds to the MapInfoOp corresponding to the private + // var in question. So, for instance: // // %10 = omp.map.info var_ptr(%6#0 : !fir.ref>>, ..) // omp.target map_entries(%10 -> %arg0) private(@box.privatizer %6#0-> %arg1) @@ -5793,6 +5847,8 @@ convertOmpTarget(Operation &opInst, llvm::IRBuilderBase &builder, ArrayRef mapBlockArgs = argIface.getMapBlockArgs(); ArrayRef hdaBlockArgs = argIface.getHasDeviceAddrBlockArgs(); llvm::Function *llvmOutlinedFn = nullptr; + TargetDirectiveEnumTy targetDirective = + getTargetDirectiveEnumTyFromOp(&opInst); // TODO: It can also be false if a compile-time constant `false` IF clause is // specified. @@ -5954,7 +6010,8 @@ convertOmpTarget(Operation &opInst, llvm::IRBuilderBase &builder, auto genMapInfoCB = [&](llvm::OpenMPIRBuilder::InsertPointTy codeGenIP) -> MapInfosTy & { builder.restoreIP(codeGenIP); - genMapInfos(builder, moduleTranslation, dl, combinedInfos, mapData, true); + genMapInfos(builder, moduleTranslation, dl, combinedInfos, mapData, + targetDirective); return combinedInfos; }; diff --git a/mlir/test/Target/LLVMIR/omptarget-declare-target-to-device.mlir b/mlir/test/Target/LLVMIR/omptarget-declare-target-to-device.mlir new file mode 100644 index 0000000000000..fa330b697a5cf --- /dev/null +++ b/mlir/test/Target/LLVMIR/omptarget-declare-target-to-device.mlir @@ -0,0 +1,35 @@ +// RUN: mlir-translate -mlir-to-llvmir %s | FileCheck %s + +// This tests the replacement of operations for `declare target to` with the +// generated `declare target to` global variable inside of target op regions when +// lowering to IR for device. Unfortunately, as the host file is not passed as a +// module attribute, we miss out on the metadata and entry info. + +module attributes {llvm.target_triple = "amdgcn-amd-amdhsa", omp.is_gpu = true, omp.is_target_device = true} { + // CHECK-DAG: @_QMtest_0Ezii = global [11 x float] zeroinitializer + llvm.mlir.global external @_QMtest_0Ezii() {addr_space = 0 : i32, omp.declare_target = #omp.declaretarget} : !llvm.array<11 x f32> { + %0 = llvm.mlir.zero : !llvm.array<11 x f32> + llvm.return %0 : !llvm.array<11 x f32> + } + + // CHECK-LABEL: define weak_odr protected amdgpu_kernel void @{{.*}}(ptr %{{.*}}) {{.*}} { + // CHECK-DAG: omp.target: + // CHECK-DAG: store float 1.000000e+00, ptr @_QMtest_0Ezii, align 4 + // CHECK-DAG: br label %omp.region.cont + llvm.func @_QQmain() { + %0 = llvm.mlir.constant(1 : index) : i64 + %1 = llvm.mlir.constant(0 : index) : i64 + %2 = llvm.mlir.constant(11 : index) : i64 + %3 = llvm.mlir.addressof @_QMtest_0Ezii : !llvm.ptr + %4 = omp.map.bounds lower_bound(%1 : i64) upper_bound(%2 : i64) extent(%2 : i64) stride(%0 : i64) start_idx(%1 : i64) {stride_in_bytes = true} + %5 = omp.map.info var_ptr(%3 : !llvm.ptr, !llvm.array<11 x f32>) map_clauses(tofrom) capture(ByRef) bounds(%4) -> !llvm.ptr + omp.target map_entries(%5 -> %arg0 : !llvm.ptr) { + %6 = llvm.mlir.constant(1.0 : f32) : f32 + %7 = llvm.mlir.constant(0 : i64) : i64 + %8 = llvm.getelementptr %arg0[%7] : (!llvm.ptr, i64) -> !llvm.ptr, f32 + llvm.store %6, %8 : f32, !llvm.ptr + omp.terminator + } + llvm.return + } +} diff --git a/offload/test/offloading/fortran/declare-target-to-allocatable-vars-in-target-with-update.f90 b/offload/test/offloading/fortran/declare-target-to-allocatable-vars-in-target-with-update.f90 new file mode 100644 index 0000000000000..727a08b093400 --- /dev/null +++ b/offload/test/offloading/fortran/declare-target-to-allocatable-vars-in-target-with-update.f90 @@ -0,0 +1,41 @@ +! Test that checks an allocatable array can be marked implicit +! `declare target to` and functions without issue. +! REQUIRES: flang, amdgpu + +! RUN: %libomptarget-compile-fortran-run-and-check-generic +module test + implicit none + integer, allocatable, dimension(:) :: alloca_arr + !$omp declare target(alloca_arr) +end module test + +program main + use test + implicit none + integer :: cycle, i + + allocate(alloca_arr(10)) + + do i = 1, 10 + alloca_arr(i) = 0 + end do + + !$omp target data map(to:alloca_arr) + do cycle = 1, 2 + !$omp target + do i = 1, 10 + alloca_arr(i) = alloca_arr(i) + i + end do + !$omp end target + + ! NOTE: Technically doesn't affect the results, but there is a + ! regression case that'll cause a runtime crash if this is + ! invoked more than once, so this checks for that. + !$omp target update from(alloca_arr) + end do + !$omp end target data + + print *, alloca_arr +end program + +! CHECK: 2 4 6 8 10 12 14 16 18 20 diff --git a/offload/test/offloading/fortran/declare-target-to-vars-target-region-and-update.f90 b/offload/test/offloading/fortran/declare-target-to-vars-target-region-and-update.f90 new file mode 100644 index 0000000000000..16433af2c922c --- /dev/null +++ b/offload/test/offloading/fortran/declare-target-to-vars-target-region-and-update.f90 @@ -0,0 +1,40 @@ +! Test the implicit `declare target to` interaction with `target update from` +! REQUIRES: flang, amdgpu + +! RUN: %libomptarget-compile-fortran-run-and-check-generic +module test + implicit none + integer :: array(10) + !$omp declare target(array) +end module test + +PROGRAM main + use test + implicit none + integer :: i + + do i = 1, 10 + array(i) = 0 + end do + + !$omp target + do i = 1, 10 + array(i) = i + end do + !$omp end target + + !$omp target + do i = 1, 10 + array(i) = array(i) + i + end do + !$omp end target + + print *, array + + !$omp target update from(array) + + print *, array +END PROGRAM + +! CHECK: 0 0 0 0 0 0 0 0 0 0 +! CHECK: 2 4 6 8 10 12 14 16 18 20 diff --git a/offload/test/offloading/fortran/declare-target-to-zero-index-allocatable-target-map.f90 b/offload/test/offloading/fortran/declare-target-to-zero-index-allocatable-target-map.f90 new file mode 100644 index 0000000000000..0d650f6b44009 --- /dev/null +++ b/offload/test/offloading/fortran/declare-target-to-zero-index-allocatable-target-map.f90 @@ -0,0 +1,30 @@ +! Test `declare target to` interaction with an allocatable with a non-default +! range +! REQUIRES: flang, amdgpu + +! RUN: %libomptarget-compile-fortran-run-and-check-generic +module test_0 + real(4), allocatable :: zero_off(:) + !$omp declare target(zero_off) +end module test_0 + +program main + use test_0 + implicit none + + allocate(zero_off(0:10)) + + zero_off(0) = 30.0 + zero_off(1) = 40.0 + zero_off(10) = 25.0 + + !$omp target map(tofrom: zero_off) + zero_off(0) = zero_off(1) + !$omp end target + + print *, zero_off(0) + print *, zero_off(1) +end program + +! CHECK: 40. +! CHECK: 40. From ff80de72c4ce5cb5fa2a764e1e1a6097e82fc5f9 Mon Sep 17 00:00:00 2001 From: Florian Mayer Date: Mon, 24 Nov 2025 12:44:32 -0800 Subject: [PATCH 10/50] Reapply "[UBSan] [compiler-rt] add preservecc variants of handlers" (#168973) (#169091) This reverts commit 418204d9c108351340fe21194ace0e31157b7189. --- .../ubsan_minimal/ubsan_minimal_handlers.cpp | 41 ++++++++++++++++++- .../TestCases/test-darwin-interface.c | 1 + 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/compiler-rt/lib/ubsan_minimal/ubsan_minimal_handlers.cpp b/compiler-rt/lib/ubsan_minimal/ubsan_minimal_handlers.cpp index ebc36a8583e05..480c5917877a3 100644 --- a/compiler-rt/lib/ubsan_minimal/ubsan_minimal_handlers.cpp +++ b/compiler-rt/lib/ubsan_minimal/ubsan_minimal_handlers.cpp @@ -12,6 +12,22 @@ static void message(const char *msg) { ubsan_message(msg); } static void message(const char *msg) { (void)write(2, msg, strlen(msg)); } #endif +// If for some reason we cannot build the runtime with preserve_all, don't +// emit any symbol. Programs that need them will fail to link, but that is +// better than randomly corrupted registers. +// Some architectures don't support preserve_all (but clang still has the) +// attribute. For now, only support x86-64 and aarch64. +#if defined(__clang__) && defined(__has_cpp_attribute) && \ + (defined(__x86_64__) || defined(__aarch64__)) +#if __has_cpp_attribute(clang::preserve_all) +#define PRESERVE_HANDLERS true +#else +#define PRESERVE_HANDLERS false +#endif +#else +#define PRESERVE_HANDLERS false +#endif + static const int kMaxCallerPcs = 20; static __sanitizer::atomic_uintptr_t caller_pcs[kMaxCallerPcs]; // Number of elements in caller_pcs. A special value of kMaxCallerPcs + 1 means @@ -85,6 +101,18 @@ SANITIZER_INTERFACE_WEAK_DEF(void, __ubsan_report_error, const char *kind, } } +#if PRESERVE_HANDLERS +SANITIZER_INTERFACE_WEAK_DEF(void, __ubsan_report_error_preserve, + const char *kind, uintptr_t caller) +[[clang::preserve_all]] { + // Additional indirecton so the user can override this with their own + // preserve_all function. This would allow, e.g., a function that reports the + // first error only, so for all subsequent calls we can skip the register save + // / restore. + __ubsan_report_error(kind, caller); +} +#endif + SANITIZER_INTERFACE_WEAK_DEF(void, __ubsan_report_error_fatal, const char *kind, uintptr_t caller) { // Use another handlers, in case it's already overriden. @@ -119,6 +147,16 @@ void NORETURN CheckFailed(const char *file, int, const char *cond, u64, u64) { #define INTERFACE extern "C" __attribute__((visibility("default"))) +#if PRESERVE_HANDLERS +#define HANDLER_PRESERVE(name, kind) \ + INTERFACE void __ubsan_handle_##name##_minimal_preserve() \ + [[clang::preserve_all]] { \ + __ubsan_report_error_preserve(kind, GET_CALLER_PC()); \ + } +#else +#define HANDLER_PRESERVE(name, kind) +#endif + #define HANDLER_RECOVER(name, kind) \ INTERFACE void __ubsan_handle_##name##_minimal() { \ __ubsan_report_error(kind, GET_CALLER_PC()); \ @@ -133,7 +171,8 @@ void NORETURN CheckFailed(const char *file, int, const char *cond, u64, u64) { #define HANDLER(name, kind) \ HANDLER_RECOVER(name, kind) \ - HANDLER_NORECOVER(name, kind) + HANDLER_NORECOVER(name, kind) \ + HANDLER_PRESERVE(name, kind) HANDLER(type_mismatch, "type-mismatch") HANDLER(alignment_assumption, "alignment-assumption") diff --git a/compiler-rt/test/ubsan_minimal/TestCases/test-darwin-interface.c b/compiler-rt/test/ubsan_minimal/TestCases/test-darwin-interface.c index 849401ef78741..f7702c99ee709 100644 --- a/compiler-rt/test/ubsan_minimal/TestCases/test-darwin-interface.c +++ b/compiler-rt/test/ubsan_minimal/TestCases/test-darwin-interface.c @@ -8,6 +8,7 @@ // RUN: sed -e 's/.*"\(.*libclang_rt.ubsan_minimal_osx_dynamic.dylib\)".*/\1/' | \ // RUN: tr -d '\n' > %t.dylib_path1 // RUN: nm -jgU %{readfile:%t.dylib_path1} | grep "^___ubsan_handle" \ +// RUN: | grep -vE "_minimal_preserve" \ // RUN: | sed 's/_minimal//g' \ // RUN: > %t.minimal.symlist // From 51d93e73975e5fc70008c286aaae2216fde097b6 Mon Sep 17 00:00:00 2001 From: Danila Malyutin Date: Tue, 25 Nov 2025 00:47:43 +0400 Subject: [PATCH 11/50] [ADT] Fix implicit reliance on cassert in StringTable.h (#169324) Adds an explicit include of `` in StringTable.h rather than relying on the one in StringRef.h. Fixes potential compile errors if assert() was undef'ed between StringRef.h and StringTable.h inclusion. --- llvm/include/llvm/ADT/StringTable.h | 1 + 1 file changed, 1 insertion(+) diff --git a/llvm/include/llvm/ADT/StringTable.h b/llvm/include/llvm/ADT/StringTable.h index 9422a6da1ce8e..3a08e56e8f501 100644 --- a/llvm/include/llvm/ADT/StringTable.h +++ b/llvm/include/llvm/ADT/StringTable.h @@ -11,6 +11,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/iterator.h" +#include #include #include From f581d8ad8f0cd08da6465c6843f9c6841d49e522 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolai=20H=C3=A4hnle?= Date: Mon, 24 Nov 2025 12:54:53 -0800 Subject: [PATCH 12/50] AMDGPU: Fix a comment (#169403) This verifier check will complain if there aren't enough implicit operands -- so it doesn't *allow* those operands, it *requires* them. --- llvm/lib/Target/AMDGPU/SIInstrInfo.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/llvm/lib/Target/AMDGPU/SIInstrInfo.cpp b/llvm/lib/Target/AMDGPU/SIInstrInfo.cpp index a7333e3373f38..7504452dc777f 100644 --- a/llvm/lib/Target/AMDGPU/SIInstrInfo.cpp +++ b/llvm/lib/Target/AMDGPU/SIInstrInfo.cpp @@ -5518,9 +5518,10 @@ bool SIInstrInfo::verifyInstruction(const MachineInstr &MI, Desc.getNumOperands() + Desc.implicit_uses().size(); const unsigned NumImplicitOps = IsDst ? 2 : 1; - // Allow additional implicit operands. This allows a fixup done by the post - // RA scheduler where the main implicit operand is killed and implicit-defs - // are added for sub-registers that remain live after this instruction. + // Require additional implicit operands. This allows a fixup done by the + // post RA scheduler where the main implicit operand is killed and + // implicit-defs are added for sub-registers that remain live after this + // instruction. if (MI.getNumOperands() < StaticNumOps + NumImplicitOps) { ErrInfo = "missing implicit register operands"; return false; From 3e86f056217afbe46cd515b3d3c2f1dc7664bebf Mon Sep 17 00:00:00 2001 From: Jan Leyonberg Date: Mon, 24 Nov 2025 16:00:46 -0500 Subject: [PATCH 13/50] [OpenMP][flang] Lowering of OpenMP custom reductions to MLIR (#168417) This patch add support for lowering of custom reductions to MLIR. It also enhances the capability of the pass to automatically mark functions as "declare target" by traversing custom reduction initializers and combiners. --- .../flang/Lower/Support/ReductionProcessor.h | 18 +++ flang/lib/Lower/OpenMP/ClauseProcessor.cpp | 60 +++++++ flang/lib/Lower/OpenMP/ClauseProcessor.h | 4 + flang/lib/Lower/OpenMP/Clauses.cpp | 17 +- flang/lib/Lower/OpenMP/OpenMP.cpp | 152 +++++++++++++++++- .../lib/Lower/Support/ReductionProcessor.cpp | 88 +++++++--- .../Optimizer/OpenMP/MarkDeclareTarget.cpp | 137 +++++++++++----- .../omp-declare-reduction-advanced-types.f90 | 19 +++ .../Todo/omp-declare-reduction-initsub.f90 | 28 ---- .../OpenMP/Todo/omp-declare-reduction.f90 | 10 -- ...are-target-deferred-marking-reductions.f90 | 37 +++++ .../omp-declare-reduction-derivedtype.f90 | 112 +++++++++++++ .../OpenMP/omp-declare-reduction-initsub.f90 | 59 +++++++ .../Lower/OpenMP/omp-declare-reduction.f90 | 33 ++++ .../OpenMP/OpenMPToLLVMIRTranslation.cpp | 16 +- .../target-custom-reduction-derivedtype.f90 | 88 ++++++++++ 16 files changed, 772 insertions(+), 106 deletions(-) create mode 100644 flang/test/Lower/OpenMP/Todo/omp-declare-reduction-advanced-types.f90 delete mode 100644 flang/test/Lower/OpenMP/Todo/omp-declare-reduction-initsub.f90 delete mode 100644 flang/test/Lower/OpenMP/Todo/omp-declare-reduction.f90 create mode 100644 flang/test/Lower/OpenMP/declare-target-deferred-marking-reductions.f90 create mode 100644 flang/test/Lower/OpenMP/omp-declare-reduction-derivedtype.f90 create mode 100644 flang/test/Lower/OpenMP/omp-declare-reduction-initsub.f90 create mode 100644 flang/test/Lower/OpenMP/omp-declare-reduction.f90 create mode 100644 offload/test/offloading/fortran/target-custom-reduction-derivedtype.f90 diff --git a/flang/include/flang/Lower/Support/ReductionProcessor.h b/flang/include/flang/Lower/Support/ReductionProcessor.h index 66f26b3b55630..bd0447360f089 100644 --- a/flang/include/flang/Lower/Support/ReductionProcessor.h +++ b/flang/include/flang/Lower/Support/ReductionProcessor.h @@ -40,6 +40,13 @@ namespace omp { class ReductionProcessor { public: + using GenInitValueCBTy = + std::function; + using GenCombinerCBTy = std::function; + // TODO: Move this enumeration to the OpenMP dialect enum ReductionIdentifier { ID, @@ -58,6 +65,9 @@ class ReductionProcessor { IEOR }; + static bool doReductionByRef(mlir::Type reductionType); + static bool doReductionByRef(mlir::Value reductionVar); + static ReductionIdentifier getReductionType(const omp::clause::ProcedureDesignator &pd); @@ -109,6 +119,14 @@ class ReductionProcessor { ReductionIdentifier redId, mlir::Type type, mlir::Value op1, mlir::Value op2); + /// Creates an OpenMP reduction declaration and inserts it into the provided + /// symbol table. The init and combiner regions are generated by the callback + /// functions genCombinerCB and genInitValueCB. + template + static DeclareRedType createDeclareReductionHelper( + AbstractConverter &converter, llvm::StringRef reductionOpName, + mlir::Type type, mlir::Location loc, bool isByRef, + GenCombinerCBTy genCombinerCB, GenInitValueCBTy genInitValueCB); /// Creates an OpenMP reduction declaration and inserts it into the provided /// symbol table. The declaration has a constant initializer with the neutral diff --git a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp index 4a392381287d5..dd0cb3c42ba26 100644 --- a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp +++ b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp @@ -13,6 +13,7 @@ #include "ClauseProcessor.h" #include "Utils.h" +#include "flang/Lower/ConvertCall.h" #include "flang/Lower/ConvertExprToHLFIR.h" #include "flang/Lower/OpenMP/Clauses.h" #include "flang/Lower/PFTBuilder.h" @@ -402,6 +403,65 @@ bool ClauseProcessor::processInclusive( return false; } +bool ClauseProcessor::processInitializer( + lower::SymMap &symMap, const parser::OmpClause::Initializer &inp, + ReductionProcessor::GenInitValueCBTy &genInitValueCB) const { + if (auto *clause = findUniqueClause()) { + genInitValueCB = [&, clause](fir::FirOpBuilder &builder, mlir::Location loc, + mlir::Type type, mlir::Value ompOrig) { + lower::SymMapScope scope(symMap); + const parser::OmpInitializerExpression &iexpr = inp.v.v; + const parser::OmpStylizedInstance &styleInstance = iexpr.v.front(); + const std::list &declList = + std::get>(styleInstance.t); + mlir::Value ompPrivVar; + for (const parser::OmpStylizedDeclaration &decl : declList) { + auto &name = std::get(decl.var.t); + assert(name.symbol && "Name does not have a symbol"); + mlir::Value addr = builder.createTemporary(loc, ompOrig.getType()); + fir::StoreOp::create(builder, loc, ompOrig, addr); + fir::FortranVariableFlagsEnum extraFlags = {}; + fir::FortranVariableFlagsAttr attributes = + Fortran::lower::translateSymbolAttributes(builder.getContext(), + *name.symbol, extraFlags); + auto declareOp = hlfir::DeclareOp::create( + builder, loc, addr, name.ToString(), nullptr, {}, nullptr, nullptr, + 0, attributes); + if (name.ToString() == "omp_priv") + ompPrivVar = declareOp.getResult(0); + symMap.addVariableDefinition(*name.symbol, declareOp); + } + // Lower the expression/function call + lower::StatementContext stmtCtx; + mlir::Value result = common::visit( + common::visitors{ + [&](const evaluate::ProcedureRef &procRef) -> mlir::Value { + convertCallToHLFIR(loc, converter, procRef, std::nullopt, + symMap, stmtCtx); + auto privVal = fir::LoadOp::create(builder, loc, ompPrivVar); + return privVal; + }, + [&](const auto &expr) -> mlir::Value { + mlir::Value exprResult = fir::getBase(convertExprToValue( + loc, converter, clause->v, symMap, stmtCtx)); + // Conversion can either give a value or a refrence to a value, + // we need to return the reduction type, so an optional load may + // be generated. + if (auto refType = llvm::dyn_cast( + exprResult.getType())) + if (ompPrivVar.getType() == refType) + exprResult = fir::LoadOp::create(builder, loc, exprResult); + return exprResult; + }}, + clause->v.u); + stmtCtx.finalizeAndPop(); + return result; + }; + return true; + } + return false; +} + bool ClauseProcessor::processMergeable( mlir::omp::MergeableClauseOps &result) const { return markClauseOccurrence(result.mergeable); diff --git a/flang/lib/Lower/OpenMP/ClauseProcessor.h b/flang/lib/Lower/OpenMP/ClauseProcessor.h index d524b4ddc8ac4..529b871330052 100644 --- a/flang/lib/Lower/OpenMP/ClauseProcessor.h +++ b/flang/lib/Lower/OpenMP/ClauseProcessor.h @@ -18,6 +18,7 @@ #include "flang/Lower/Bridge.h" #include "flang/Lower/DirectivesCommon.h" #include "flang/Lower/OpenMP/Clauses.h" +#include "flang/Lower/Support/ReductionProcessor.h" #include "flang/Optimizer/Builder/Todo.h" #include "flang/Parser/dump-parse-tree.h" #include "flang/Parser/parse-tree.h" @@ -88,6 +89,9 @@ class ClauseProcessor { bool processHint(mlir::omp::HintClauseOps &result) const; bool processInclusive(mlir::Location currentLocation, mlir::omp::InclusiveClauseOps &result) const; + bool processInitializer( + lower::SymMap &symMap, const parser::OmpClause::Initializer &inp, + ReductionProcessor::GenInitValueCBTy &genInitValueCB) const; bool processMergeable(mlir::omp::MergeableClauseOps &result) const; bool processNogroup(mlir::omp::NogroupClauseOps &result) const; bool processNowait(mlir::omp::NowaitClauseOps &result) const; diff --git a/flang/lib/Lower/OpenMP/Clauses.cpp b/flang/lib/Lower/OpenMP/Clauses.cpp index b1a3c3d3c5439..dc49a8118b0a5 100644 --- a/flang/lib/Lower/OpenMP/Clauses.cpp +++ b/flang/lib/Lower/OpenMP/Clauses.cpp @@ -981,7 +981,22 @@ Init make(const parser::OmpClause::Init &inp, Initializer make(const parser::OmpClause::Initializer &inp, semantics::SemanticsContext &semaCtx) { - llvm_unreachable("Empty: initializer"); + const parser::OmpInitializerExpression &iexpr = inp.v.v; + const parser::OmpStylizedInstance &styleInstance = iexpr.v.front(); + const parser::OmpStylizedInstance::Instance &instance = + std::get(styleInstance.t); + if (const auto *as = std::get_if(&instance.u)) { + auto &expr = std::get(as->t); + return Initializer{makeExpr(expr, semaCtx)}; + } else if (const auto *call = std::get_if(&instance.u)) { + if (call->typedCall) { + const auto &procRef = *call->typedCall; + semantics::SomeExpr evalProcRef{procRef}; + return Initializer{evalProcRef}; + } + } + + llvm_unreachable("Unexpected initializer"); } InReduction make(const parser::OmpClause::InReduction &inp, diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp index b11a1a14db066..6ca8636bb6459 100644 --- a/flang/lib/Lower/OpenMP/OpenMP.cpp +++ b/flang/lib/Lower/OpenMP/OpenMP.cpp @@ -18,12 +18,15 @@ #include "Decomposer.h" #include "Utils.h" #include "flang/Common/idioms.h" +#include "flang/Evaluate/type.h" #include "flang/Lower/Bridge.h" #include "flang/Lower/ConvertExpr.h" +#include "flang/Lower/ConvertExprToHLFIR.h" #include "flang/Lower/ConvertVariable.h" #include "flang/Lower/DirectivesCommon.h" #include "flang/Lower/OpenMP/Clauses.h" #include "flang/Lower/StatementContext.h" +#include "flang/Lower/Support/ReductionProcessor.h" #include "flang/Lower/SymbolMap.h" #include "flang/Optimizer/Builder/BoxValue.h" #include "flang/Optimizer/Builder/FIRBuilder.h" @@ -2847,7 +2850,6 @@ genTeamsOp(lower::AbstractConverter &converter, lower::SymMap &symTable, // TODO: Add private syms and vars. args.reduction.syms = reductionSyms; args.reduction.vars = clauseOps.reductionVars; - return genOpWithBody( OpWithBodyGenInfo(converter, symTable, semaCtx, loc, eval, llvm::omp::Directive::OMPD_teams) @@ -3570,12 +3572,156 @@ genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable, TODO(converter.getCurrentLocation(), "OmpDeclareVariantDirective"); } +static ReductionProcessor::GenCombinerCBTy +processReductionCombiner(lower::AbstractConverter &converter, + lower::SymMap &symTable, + semantics::SemanticsContext &semaCtx, + const parser::OmpReductionSpecifier &specifier) { + ReductionProcessor::GenCombinerCBTy genCombinerCB; + const auto &combinerExpression = + std::get>(specifier.t) + .value(); + const parser::OmpStylizedInstance &combinerInstance = + combinerExpression.v.front(); + const parser::OmpStylizedInstance::Instance &instance = + std::get(combinerInstance.t); + + const auto *as = std::get_if(&instance.u); + if (!as) { + TODO(converter.getCurrentLocation(), + "A combiner that is a subroutine call is not yet supported"); + } + auto &expr = std::get(as->t); + genCombinerCB = [&](fir::FirOpBuilder &builder, mlir::Location loc, + mlir::Type type, mlir::Value lhs, mlir::Value rhs, + bool isByRef) { + const auto &evalExpr = makeExpr(expr, semaCtx); + lower::SymMapScope scope(symTable); + const std::list &declList = + std::get>(combinerInstance.t); + for (const parser::OmpStylizedDeclaration &decl : declList) { + auto &name = std::get(decl.var.t); + mlir::Value addr = lhs; + mlir::Type type = lhs.getType(); + bool isRhs = name.ToString() == std::string("omp_in"); + if (isRhs) { + addr = rhs; + type = rhs.getType(); + } + + assert(name.symbol && "Reduction object name does not have a symbol"); + if (!fir::conformsWithPassByRef(type)) { + addr = builder.createTemporary(loc, type); + fir::StoreOp::create(builder, loc, isRhs ? rhs : lhs, addr); + } + fir::FortranVariableFlagsEnum extraFlags = {}; + fir::FortranVariableFlagsAttr attributes = + Fortran::lower::translateSymbolAttributes(builder.getContext(), + *name.symbol, extraFlags); + auto declareOp = + hlfir::DeclareOp::create(builder, loc, addr, name.ToString(), nullptr, + {}, nullptr, nullptr, 0, attributes); + symTable.addVariableDefinition(*name.symbol, declareOp); + } + + lower::StatementContext stmtCtx; + mlir::Value result = fir::getBase( + convertExprToValue(loc, converter, evalExpr, symTable, stmtCtx)); + if (auto refType = llvm::dyn_cast(result.getType())) + if (lhs.getType() == refType.getElementType()) + result = fir::LoadOp::create(builder, loc, result); + stmtCtx.finalizeAndPop(); + if (isByRef) { + fir::StoreOp::create(builder, loc, result, lhs); + mlir::omp::YieldOp::create(builder, loc, lhs); + } else { + mlir::omp::YieldOp::create(builder, loc, result); + } + }; + return genCombinerCB; +} + +// Checks that the reduction type is either a trivial type or a derived type of +// trivial types. +static bool isSimpleReductionType(mlir::Type reductionType) { + if (fir::isa_trivial(reductionType)) + return true; + if (auto recordTy = mlir::dyn_cast(reductionType)) { + for (auto [_, fieldType] : recordTy.getTypeList()) { + if (!fir::isa_trivial(fieldType)) + return false; + } + } + return true; +} + +// Getting the type from a symbol compared to a DeclSpec is simpler since we do +// not need to consider derived vs intrinsic types. Semantics is guaranteed to +// generate these symbols. +static mlir::Type +getReductionType(lower::AbstractConverter &converter, + const parser::OmpReductionSpecifier &specifier) { + const auto &combinerExpression = + std::get>(specifier.t) + .value(); + const parser::OmpStylizedInstance &combinerInstance = + combinerExpression.v.front(); + const std::list &declList = + std::get>(combinerInstance.t); + const parser::OmpStylizedDeclaration &decl = declList.front(); + const auto &name = std::get(decl.var.t); + const auto &symbol = semantics::SymbolRef(*name.symbol); + mlir::Type reductionType = converter.genType(symbol); + + if (!isSimpleReductionType(reductionType)) + TODO(converter.getCurrentLocation(), + "declare reduction currently only supports trival types or derived " + "types containing trivial types"); + return reductionType; +} + static void genOMP( lower::AbstractConverter &converter, lower::SymMap &symTable, semantics::SemanticsContext &semaCtx, lower::pft::Evaluation &eval, const parser::OpenMPDeclareReductionConstruct &declareReductionConstruct) { - if (!semaCtx.langOptions().OpenMPSimd) - TODO(converter.getCurrentLocation(), "OpenMPDeclareReductionConstruct"); + if (semaCtx.langOptions().OpenMPSimd) + return; + + const parser::OmpArgumentList &args{declareReductionConstruct.v.Arguments()}; + const parser::OmpArgument &arg{args.v.front()}; + const auto &specifier = std::get(arg.u); + + if (std::get(specifier.t).v.size() > 1) + TODO(converter.getCurrentLocation(), + "multiple types in declare reduction is not yet supported"); + + mlir::Type reductionType = getReductionType(converter, specifier); + ReductionProcessor::GenCombinerCBTy genCombinerCB = + processReductionCombiner(converter, symTable, semaCtx, specifier); + const parser::OmpClauseList &initializer = + declareReductionConstruct.v.Clauses(); + if (initializer.v.size() > 0) { + List clauses = makeClauses(initializer, semaCtx); + ReductionProcessor::GenInitValueCBTy genInitValueCB; + ClauseProcessor cp(converter, semaCtx, clauses); + const parser::OmpClause::Initializer &iclause{ + std::get(initializer.v.front().u)}; + cp.processInitializer(symTable, iclause, genInitValueCB); + const auto &identifier = + std::get(specifier.t); + const auto &designator = + std::get(identifier.u); + const auto &reductionName = std::get(designator.u); + bool isByRef = ReductionProcessor::doReductionByRef(reductionType); + ReductionProcessor::createDeclareReductionHelper< + mlir::omp::DeclareReductionOp>( + converter, reductionName.ToString(), reductionType, + converter.getCurrentLocation(), isByRef, genCombinerCB, genInitValueCB); + } else { + TODO(converter.getCurrentLocation(), + "declare reduction without an initializer clause is not yet " + "supported"); + } } static void diff --git a/flang/lib/Lower/Support/ReductionProcessor.cpp b/flang/lib/Lower/Support/ReductionProcessor.cpp index 605a5b6b20b94..721cb45cd7d24 100644 --- a/flang/lib/Lower/Support/ReductionProcessor.cpp +++ b/flang/lib/Lower/Support/ReductionProcessor.cpp @@ -501,7 +501,7 @@ static mlir::Type unwrapSeqOrBoxedType(mlir::Type ty) { template static void createReductionAllocAndInitRegions( AbstractConverter &converter, mlir::Location loc, OpType &reductionDecl, - const ReductionProcessor::ReductionIdentifier redId, mlir::Type type, + ReductionProcessor::GenInitValueCBTy genInitValueCB, mlir::Type type, bool isByRef) { fir::FirOpBuilder &builder = converter.getFirOpBuilder(); auto yield = [&](mlir::Value ret) { genYield(builder, loc, ret); }; @@ -523,9 +523,8 @@ static void createReductionAllocAndInitRegions( mlir::Type ty = fir::unwrapRefType(type); builder.setInsertionPointToEnd(initBlock); - mlir::Value initValue = ReductionProcessor::getReductionInitValue( - loc, unwrapSeqOrBoxedType(ty), redId, builder); - + mlir::Value initValue = + genInitValueCB(builder, loc, ty, initBlock->getArgument(0)); if (isByRef) { populateByRefInitAndCleanupRegions( converter, loc, type, initValue, initBlock, @@ -536,7 +535,7 @@ static void createReductionAllocAndInitRegions( /*isDoConcurrent*/ std::is_same_v); } - if (fir::isa_trivial(ty)) { + if (fir::isa_trivial(ty) || fir::isa_derived(ty)) { if (isByRef) { // alloc region builder.setInsertionPointToEnd(allocBlock); @@ -556,18 +555,18 @@ static void createReductionAllocAndInitRegions( yield(boxAlloca); } -template -OpType ReductionProcessor::createDeclareReduction( +template +DeclareRedType ReductionProcessor::createDeclareReductionHelper( AbstractConverter &converter, llvm::StringRef reductionOpName, - const ReductionIdentifier redId, mlir::Type type, mlir::Location loc, - bool isByRef) { + mlir::Type type, mlir::Location loc, bool isByRef, + GenCombinerCBTy genCombinerCB, GenInitValueCBTy genInitValueCB) { fir::FirOpBuilder &builder = converter.getFirOpBuilder(); mlir::OpBuilder::InsertionGuard guard(builder); mlir::ModuleOp module = builder.getModule(); assert(!reductionOpName.empty()); - auto decl = module.lookupSymbol(reductionOpName); + auto decl = module.lookupSymbol(reductionOpName); if (decl) return decl; @@ -576,23 +575,54 @@ OpType ReductionProcessor::createDeclareReduction( if (!isByRef) type = valTy; - decl = OpType::create(modBuilder, loc, reductionOpName, type); - createReductionAllocAndInitRegions(converter, loc, decl, redId, type, + decl = DeclareRedType::create(modBuilder, loc, reductionOpName, type); + createReductionAllocAndInitRegions(converter, loc, decl, genInitValueCB, type, isByRef); - builder.createBlock(&decl.getReductionRegion(), decl.getReductionRegion().end(), {type, type}, {loc, loc}); - builder.setInsertionPointToEnd(&decl.getReductionRegion().back()); mlir::Value op1 = decl.getReductionRegion().front().getArgument(0); mlir::Value op2 = decl.getReductionRegion().front().getArgument(1); - genCombiner(builder, loc, redId, type, op1, op2, isByRef); - + genCombinerCB(builder, loc, type, op1, op2, isByRef); return decl; } -static bool doReductionByRef(mlir::Value reductionVar) { +template +OpType ReductionProcessor::createDeclareReduction( + AbstractConverter &converter, llvm::StringRef reductionOpName, + const ReductionIdentifier redId, mlir::Type type, mlir::Location loc, + bool isByRef) { + auto genInitValueCB = [&](fir::FirOpBuilder &builder, mlir::Location loc, + mlir::Type type, mlir::Value val) { + mlir::Type ty = fir::unwrapRefType(type); + mlir::Value initValue = ReductionProcessor::getReductionInitValue( + loc, unwrapSeqOrBoxedType(ty), redId, builder); + return initValue; + }; + auto genCombinerCB = [&](fir::FirOpBuilder &builder, mlir::Location loc, + mlir::Type type, mlir::Value op1, mlir::Value op2, + bool isByRef) { + genCombiner(builder, loc, redId, type, op1, op2, isByRef); + }; + + return createDeclareReductionHelper(converter, reductionOpName, type, + loc, isByRef, genCombinerCB, + genInitValueCB); +} + +bool ReductionProcessor::doReductionByRef(mlir::Type reductionType) { + if (forceByrefReduction) + return true; + + if (!fir::isa_trivial(fir::unwrapRefType(reductionType)) && + !fir::isa_derived(fir::unwrapRefType(reductionType))) + return true; + + return false; +} + +bool ReductionProcessor::doReductionByRef(mlir::Value reductionVar) { if (forceByrefReduction) return true; @@ -600,10 +630,7 @@ static bool doReductionByRef(mlir::Value reductionVar) { mlir::dyn_cast(reductionVar.getDefiningOp())) reductionVar = declare.getMemref(); - if (!fir::isa_trivial(fir::unwrapRefType(reductionVar.getType()))) - return true; - - return false; + return doReductionByRef(reductionVar.getType()); } template @@ -614,6 +641,8 @@ bool ReductionProcessor::processReductionArguments( llvm::SmallVectorImpl &reduceVarByRef, llvm::SmallVectorImpl &reductionDeclSymbols, const llvm::SmallVectorImpl &reductionSymbols) { + fir::FirOpBuilder &builder = converter.getFirOpBuilder(); + if constexpr (std::is_same_v) { // For OpenMP reduction clauses, check if the reduction operator is @@ -627,7 +656,13 @@ bool ReductionProcessor::processReductionArguments( std::get_if(&redOperator.u)) { if (!ReductionProcessor::supportedIntrinsicProcReduction( *reductionIntrinsic)) { - return false; + // If not an intrinsic is has to be a custom reduction op, and should + // be available in the module. + semantics::Symbol *sym = reductionIntrinsic->v.sym(); + mlir::ModuleOp module = builder.getModule(); + auto decl = module.lookupSymbol(getRealName(sym).ToString()); + if (!decl) + return false; } } else { return false; @@ -637,7 +672,6 @@ bool ReductionProcessor::processReductionArguments( // Reduction variable processing common to both intrinsic operators and // procedure designators - fir::FirOpBuilder &builder = converter.getFirOpBuilder(); mlir::OpBuilder::InsertPoint dcIP; constexpr bool isDoConcurrent = std::is_same_v; @@ -741,7 +775,13 @@ bool ReductionProcessor::processReductionArguments( &redOperator.u)) { if (!ReductionProcessor::supportedIntrinsicProcReduction( *reductionIntrinsic)) { - TODO(currentLocation, "Unsupported intrinsic proc reduction"); + // Custom reductions we can just add to the symbols without + // generating the declare reduction op. + semantics::Symbol *sym = reductionIntrinsic->v.sym(); + reductionDeclSymbols.push_back(mlir::SymbolRefAttr::get( + builder.getContext(), sym->name().ToString())); + ++idx; + continue; } redId = getReductionType(*reductionIntrinsic); reductionName = diff --git a/flang/lib/Optimizer/OpenMP/MarkDeclareTarget.cpp b/flang/lib/Optimizer/OpenMP/MarkDeclareTarget.cpp index 0b0e6bd9ecf34..5fa77fb2080df 100644 --- a/flang/lib/Optimizer/OpenMP/MarkDeclareTarget.cpp +++ b/flang/lib/Optimizer/OpenMP/MarkDeclareTarget.cpp @@ -21,6 +21,7 @@ #include "mlir/Pass/Pass.h" #include "mlir/Support/LLVM.h" #include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/TypeSwitch.h" namespace flangomp { #define GEN_PASS_DEF_MARKDECLARETARGETPASS @@ -31,9 +32,93 @@ namespace { class MarkDeclareTargetPass : public flangomp::impl::MarkDeclareTargetPassBase { - void markNestedFuncs(mlir::omp::DeclareTargetDeviceType parentDevTy, - mlir::omp::DeclareTargetCaptureClause parentCapClause, - bool parentAutomap, mlir::Operation *currOp, + struct ParentInfo { + mlir::omp::DeclareTargetDeviceType devTy; + mlir::omp::DeclareTargetCaptureClause capClause; + bool automap; + }; + + void processSymbolRef(mlir::SymbolRefAttr symRef, ParentInfo parentInfo, + llvm::SmallPtrSet visited) { + if (auto currFOp = + getOperation().lookupSymbol(symRef)) { + auto current = llvm::dyn_cast( + currFOp.getOperation()); + + if (current.isDeclareTarget()) { + auto currentDt = current.getDeclareTargetDeviceType(); + + // Found the same function twice, with different device_types, + // mark as Any as it belongs to both + if (currentDt != parentInfo.devTy && + currentDt != mlir::omp::DeclareTargetDeviceType::any) { + current.setDeclareTarget(mlir::omp::DeclareTargetDeviceType::any, + current.getDeclareTargetCaptureClause(), + current.getDeclareTargetAutomap()); + } + } else { + current.setDeclareTarget(parentInfo.devTy, parentInfo.capClause, + parentInfo.automap); + } + + markNestedFuncs(parentInfo, currFOp, visited); + } + } + + void processReductionRefs(std::optional symRefs, + ParentInfo parentInfo, + llvm::SmallPtrSet visited) { + if (!symRefs) + return; + + for (auto symRef : symRefs->getAsRange()) { + if (auto declareReductionOp = + getOperation().lookupSymbol( + symRef)) { + markNestedFuncs(parentInfo, declareReductionOp, visited); + } + } + } + + void + processReductionClauses(mlir::Operation *op, ParentInfo parentInfo, + llvm::SmallPtrSet visited) { + llvm::TypeSwitch(*op) + .Case([&](mlir::omp::LoopOp op) { + processReductionRefs(op.getReductionSyms(), parentInfo, visited); + }) + .Case([&](mlir::omp::ParallelOp op) { + processReductionRefs(op.getReductionSyms(), parentInfo, visited); + }) + .Case([&](mlir::omp::SectionsOp op) { + processReductionRefs(op.getReductionSyms(), parentInfo, visited); + }) + .Case([&](mlir::omp::SimdOp op) { + processReductionRefs(op.getReductionSyms(), parentInfo, visited); + }) + .Case([&](mlir::omp::TargetOp op) { + processReductionRefs(op.getInReductionSyms(), parentInfo, visited); + }) + .Case([&](mlir::omp::TaskgroupOp op) { + processReductionRefs(op.getTaskReductionSyms(), parentInfo, visited); + }) + .Case([&](mlir::omp::TaskloopOp op) { + processReductionRefs(op.getReductionSyms(), parentInfo, visited); + processReductionRefs(op.getInReductionSyms(), parentInfo, visited); + }) + .Case([&](mlir::omp::TaskOp op) { + processReductionRefs(op.getInReductionSyms(), parentInfo, visited); + }) + .Case([&](mlir::omp::TeamsOp op) { + processReductionRefs(op.getReductionSyms(), parentInfo, visited); + }) + .Case([&](mlir::omp::WsloopOp op) { + processReductionRefs(op.getReductionSyms(), parentInfo, visited); + }) + .Default([](mlir::Operation &) {}); + } + + void markNestedFuncs(ParentInfo parentInfo, mlir::Operation *currOp, llvm::SmallPtrSet visited) { if (visited.contains(currOp)) return; @@ -43,33 +128,10 @@ class MarkDeclareTargetPass if (auto callOp = llvm::dyn_cast(op)) { if (auto symRef = llvm::dyn_cast_if_present( callOp.getCallableForCallee())) { - if (auto currFOp = - getOperation().lookupSymbol(symRef)) { - auto current = llvm::dyn_cast( - currFOp.getOperation()); - - if (current.isDeclareTarget()) { - auto currentDt = current.getDeclareTargetDeviceType(); - - // Found the same function twice, with different device_types, - // mark as Any as it belongs to both - if (currentDt != parentDevTy && - currentDt != mlir::omp::DeclareTargetDeviceType::any) { - current.setDeclareTarget( - mlir::omp::DeclareTargetDeviceType::any, - current.getDeclareTargetCaptureClause(), - current.getDeclareTargetAutomap()); - } - } else { - current.setDeclareTarget(parentDevTy, parentCapClause, - parentAutomap); - } - - markNestedFuncs(parentDevTy, parentCapClause, parentAutomap, - currFOp, visited); - } + processSymbolRef(symRef, parentInfo, visited); } } + processReductionClauses(op, parentInfo, visited); }); } @@ -82,10 +144,10 @@ class MarkDeclareTargetPass functionOp.getOperation()); if (declareTargetOp.isDeclareTarget()) { llvm::SmallPtrSet visited; - markNestedFuncs(declareTargetOp.getDeclareTargetDeviceType(), - declareTargetOp.getDeclareTargetCaptureClause(), - declareTargetOp.getDeclareTargetAutomap(), functionOp, - visited); + ParentInfo parentInfo{declareTargetOp.getDeclareTargetDeviceType(), + declareTargetOp.getDeclareTargetCaptureClause(), + declareTargetOp.getDeclareTargetAutomap()}; + markNestedFuncs(parentInfo, functionOp, visited); } } @@ -96,12 +158,13 @@ class MarkDeclareTargetPass // the contents of the device clause getOperation()->walk([&](mlir::omp::TargetOp tarOp) { llvm::SmallPtrSet visited; - markNestedFuncs( - /*parentDevTy=*/mlir::omp::DeclareTargetDeviceType::nohost, - /*parentCapClause=*/mlir::omp::DeclareTargetCaptureClause::to, - /*parentAutomap=*/false, tarOp, visited); + ParentInfo parentInfo = { + /*devTy=*/mlir::omp::DeclareTargetDeviceType::nohost, + /*capClause=*/mlir::omp::DeclareTargetCaptureClause::to, + /*automap=*/false, + }; + markNestedFuncs(parentInfo, tarOp, visited); }); } }; - } // namespace diff --git a/flang/test/Lower/OpenMP/Todo/omp-declare-reduction-advanced-types.f90 b/flang/test/Lower/OpenMP/Todo/omp-declare-reduction-advanced-types.f90 new file mode 100644 index 0000000000000..e40e3d9285adc --- /dev/null +++ b/flang/test/Lower/OpenMP/Todo/omp-declare-reduction-advanced-types.f90 @@ -0,0 +1,19 @@ +! This test checks lowering of OpenMP declare reduction with non-trivial types + +! RUN: not %flang_fc1 -emit-fir -fopenmp %s 2>&1 | FileCheck %s + +module mymod + type advancedtype + integer(4)::myarray(10) + integer(4)::val + integer(4)::otherval + end type advancedtype + !CHECK: not yet implemented: declare reduction currently only supports trival types or derived types containing trivial types + !$omp declare reduction(myreduction: advancedtype: omp_out = omp_in) initializer(omp_priv = omp_orig) +end module mymod + +program mymaxtest + use mymod + +end program + diff --git a/flang/test/Lower/OpenMP/Todo/omp-declare-reduction-initsub.f90 b/flang/test/Lower/OpenMP/Todo/omp-declare-reduction-initsub.f90 deleted file mode 100644 index f2c744599fdc5..0000000000000 --- a/flang/test/Lower/OpenMP/Todo/omp-declare-reduction-initsub.f90 +++ /dev/null @@ -1,28 +0,0 @@ -! This test checks lowering of OpenMP declare reduction Directive, with initialization -! via a subroutine. This functionality is currently not implemented. - -! RUN: not %flang_fc1 -emit-fir -fopenmp %s 2>&1 | FileCheck %s - -!CHECK: not yet implemented: OpenMPDeclareReductionConstruct -subroutine initme(x,n) - integer x,n - x=n -end subroutine initme - -function func(x, n, init) - integer func - integer x(n) - integer res - interface - subroutine initme(x,n) - integer x,n - end subroutine initme - end interface -!$omp declare reduction(red_add:integer(4):omp_out=omp_out+omp_in) initializer(initme(omp_priv,0)) - res=init -!$omp simd reduction(red_add:res) - do i=1,n - res=res+x(i) - enddo - func=res -end function func diff --git a/flang/test/Lower/OpenMP/Todo/omp-declare-reduction.f90 b/flang/test/Lower/OpenMP/Todo/omp-declare-reduction.f90 deleted file mode 100644 index 11e83cc710f05..0000000000000 --- a/flang/test/Lower/OpenMP/Todo/omp-declare-reduction.f90 +++ /dev/null @@ -1,10 +0,0 @@ -! This test checks lowering of OpenMP declare reduction Directive. - -! RUN: not %flang_fc1 -emit-fir -fopenmp %s 2>&1 | FileCheck %s - -subroutine declare_red() - integer :: my_var - !CHECK: not yet implemented: OpenMPDeclareReductionConstruct - !$omp declare reduction (my_red : integer : omp_out = omp_in) initializer (omp_priv = 0) - my_var = 0 -end subroutine declare_red diff --git a/flang/test/Lower/OpenMP/declare-target-deferred-marking-reductions.f90 b/flang/test/Lower/OpenMP/declare-target-deferred-marking-reductions.f90 new file mode 100644 index 0000000000000..66697ef6bbe70 --- /dev/null +++ b/flang/test/Lower/OpenMP/declare-target-deferred-marking-reductions.f90 @@ -0,0 +1,37 @@ +!RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=52 %s -o - | FileCheck %s +!RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=52 -fopenmp-is-device %s -o - | FileCheck %s + +program main + use, intrinsic :: iso_c_binding + implicit none + interface + subroutine myinit(priv, orig) bind(c,name="myinit") + use, intrinsic :: iso_c_binding + implicit none + integer::priv, orig + end subroutine myinit + + function mycombine(lhs, rhs) bind(c,name="mycombine") + use, intrinsic :: iso_c_binding + implicit none + integer::lhs, rhs, mycombine + end function mycombine + end interface + !$omp declare reduction(myreduction:integer:omp_out = mycombine(omp_out, omp_in)) initializer(myinit(omp_priv, omp_orig)) + + integer :: i, s, a(10) + !$omp target + s = 0 + !$omp do reduction(myreduction:s) + do i = 1, 10 + s = mycombine(s, a(i)) + enddo + !$omp end do + !$omp end target + end program main + +!CHECK: func.func {{.*}} @myinit(!fir.ref, !fir.ref) +!CHECK-SAME: {{.*}}, omp.declare_target = #omp.declaretarget{{.*}} +!CHECK-LABEL: func.func {{.*}} @mycombine(!fir.ref, !fir.ref) +!CHECK-SAME: {{.*}}, omp.declare_target = #omp.declaretarget{{.*}} + diff --git a/flang/test/Lower/OpenMP/omp-declare-reduction-derivedtype.f90 b/flang/test/Lower/OpenMP/omp-declare-reduction-derivedtype.f90 new file mode 100644 index 0000000000000..36bb131e677a3 --- /dev/null +++ b/flang/test/Lower/OpenMP/omp-declare-reduction-derivedtype.f90 @@ -0,0 +1,112 @@ +! This test checks lowering of OpenMP declare reduction Directive, with initialization +! via a subroutine. This functionality is currently not implemented. + +!RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=52 %s -o - | FileCheck %s +module maxtype_mod + implicit none + + type maxtype + integer::sumval + integer::maxval + end type maxtype + +contains + + subroutine initme(x,n) + type(maxtype) :: x,n + x%sumval=0 + x%maxval=0 + end subroutine initme + + function mycombine(lhs, rhs) + type(maxtype) :: lhs, rhs + type(maxtype) :: mycombine + mycombine%sumval = lhs%sumval + rhs%sumval + mycombine%maxval = max(lhs%maxval, rhs%maxval) + end function mycombine + + function func(x, n, init) + type(maxtype) :: func + integer :: n, i + type(maxtype) :: x(n) + type(maxtype) :: init + type(maxtype) :: res +!$omp declare reduction(red_add_max:maxtype:omp_out=mycombine(omp_out,omp_in)) initializer(initme(omp_priv,omp_orig)) + res=init +!$omp simd reduction(red_add_max:res) + do i=1,n + res=mycombine(res,x(i)) + enddo + func=res + end function func + +end module maxtype_mod +!CHECK: omp.declare_reduction @red_add_max : [[MAXTYPE:.*]] init { +!CHECK: ^bb0(%[[OMP_ORIG_ARG_I:.*]]: [[MAXTYPE]]): +!CHECK: %[[OMP_PRIV:.*]] = fir.alloca [[MAXTYPE]] +!CHECK: %[[OMP_ORIG:.*]] = fir.alloca [[MAXTYPE]] +!CHECK: fir.store %[[OMP_ORIG_ARG_I]] to %[[OMP_ORIG]] : !fir.ref<[[MAXTYPE]]> +!CHECK: %[[OMP_ORIG_DECL:.*]]:2 = hlfir.declare %[[OMP_ORIG]] {uniq_name = "omp_orig"} : (!fir.ref<[[MAXTYPE]]>) -> (!fir.ref<[[MAXTYPE]]>, !fir.ref<[[MAXTYPE]]>) +!CHECK: fir.store %[[OMP_ORIG_ARG_I]] to %[[OMP_PRIV]] : !fir.ref<[[MAXTYPE]]> +!CHECK: %[[OMP_PRIV_DECL:.*]]:2 = hlfir.declare %[[OMP_PRIV]] {uniq_name = "omp_priv"} : (!fir.ref<[[MAXTYPE]]>) -> (!fir.ref<[[MAXTYPE]]>, !fir.ref<[[MAXTYPE]]>) +!CHECK: fir.call @_QMmaxtype_modPinitme(%[[OMP_PRIV_DECL]]#0, %[[OMP_ORIG_DECL]]#0) fastmath : (!fir.ref<[[MAXTYPE]]>, !fir.ref<[[MAXTYPE]]>) -> () +!CHECK: %[[OMP_PRIV_VAL:.*]] = fir.load %[[OMP_PRIV_DECL]]#0 : !fir.ref<[[MAXTYPE]]> +!CHECK: omp.yield(%[[OMP_PRIV_VAL]] : [[MAXTYPE]]) +!CHECK: } combiner { +!CHECK: ^bb0(%[[LHS_ARG:.*]]: [[MAXTYPE]], %[[RHS_ARG:.*]]: [[MAXTYPE]]): +!CHECK: %[[RESULT:.*]] = fir.alloca [[MAXTYPE]] {bindc_name = ".result"} +!CHECK: %[[OMP_OUT:.*]] = fir.alloca [[MAXTYPE]] +!CHECK: %[[OMP_IN:.*]] = fir.alloca [[MAXTYPE]] +!CHECK: fir.store %[[RHS_ARG]] to %[[OMP_IN]] : !fir.ref<[[MAXTYPE]]> +!CHECK: %[[OMP_IN_DECL:.*]]:2 = hlfir.declare %[[OMP_IN]] {uniq_name = "omp_in"} : (!fir.ref<[[MAXTYPE]]>) -> (!fir.ref<[[MAXTYPE]]>, !fir.ref<[[MAXTYPE]]>) +!CHECK: fir.store %[[LHS_ARG]] to %[[OMP_OUT]] : !fir.ref<[[MAXTYPE]]> +!CHECK: %[[OMP_OUT_DECL:.*]]:2 = hlfir.declare %[[OMP_OUT]] {uniq_name = "omp_out"} : (!fir.ref<[[MAXTYPE]]>) -> (!fir.ref<[[MAXTYPE]]>, !fir.ref<[[MAXTYPE]]>) +!CHECK: %[[COMBINE_RESULT:.*]] = fir.call @_QMmaxtype_modPmycombine(%[[OMP_OUT_DECL]]#0, %[[OMP_IN_DECL]]#0) fastmath : (!fir.ref<[[MAXTYPE]]>, !fir.ref<[[MAXTYPE]]>) -> [[MAXTYPE]] +!CHECK: fir.save_result %[[COMBINE_RESULT]] to %[[RESULT]] : [[MAXTYPE]], !fir.ref<[[MAXTYPE]]> +!CHECK: %[[TMPRESULT:.*]]:2 = hlfir.declare %[[RESULT]] {uniq_name = ".tmp.func_result"} : (!fir.ref<[[MAXTYPE]]>) -> (!fir.ref<[[MAXTYPE]]>, !fir.ref<[[MAXTYPE]]>) +!CHECK: %false = arith.constant false +!CHECK: %[[EXPRRESULT:.*]] = hlfir.as_expr %[[TMPRESULT]]#0 move %false : (!fir.ref<[[MAXTYPE]]>, i1) -> !hlfir.expr<[[MAXTYPE]]> +!CHECK: %[[ASSOCIATE:.*]]:3 = hlfir.associate %[[EXPRRESULT]] {adapt.valuebyref} : (!hlfir.expr<[[MAXTYPE]]>) -> (!fir.ref<[[MAXTYPE]]>, !fir.ref<[[MAXTYPE]]>, i1) +!CHECK: %[[RESULT_VAL:.*]] = fir.load %[[ASSOCIATE]]#0 : !fir.ref<[[MAXTYPE]]> +!CHECK: hlfir.end_associate %[[ASSOCIATE]]#1, %[[ASSOCIATE]]#2 : !fir.ref<[[MAXTYPE]]>, i1 +!CHECK: omp.yield(%[[RESULT_VAL]] : [[MAXTYPE]]) +!CHECK: } + +!CHECK: func.func @_QMmaxtype_modPinitme(%[[X_ARG:.*]]: !fir.ref<[[MAXTYPE]]> {fir.bindc_name = "x"}, %[[N_ARG:.*]]: !fir.ref<[[MAXTYPE]]> {fir.bindc_name = "n"}) { +!CHECK: %[[SCOPE:.*]] = fir.dummy_scope : !fir.dscope +!CHECK: %[[N_DECL:.*]]:2 = hlfir.declare %[[N_ARG]] dummy_scope %[[SCOPE]] arg 2 {uniq_name = "_QMmaxtype_modFinitmeEn"} : (!fir.ref<[[MAXTYPE]]>, !fir.dscope) -> (!fir.ref<[[MAXTYPE]]>, !fir.ref<[[MAXTYPE]]>) +!CHECK: %[[X_DECL:.*]]:2 = hlfir.declare %[[X_ARG]] dummy_scope %[[SCOPE]] arg 1 {uniq_name = "_QMmaxtype_modFinitmeEx"} : (!fir.ref<[[MAXTYPE]]>, !fir.dscope) -> (!fir.ref<[[MAXTYPE]]>, !fir.ref<[[MAXTYPE]]>) +!CHECK: %[[ZERO_0:.*]] = arith.constant 0 : i32 +!CHECK: %[[X_DESIGNATE_SUMVAL:.*]] = hlfir.designate %[[X_DECL]]#0{"sumval"} : (!fir.ref<[[MAXTYPE]]>) -> !fir.ref +!CHECK: hlfir.assign %[[ZERO_0]] to %[[X_DESIGNATE_SUMVAL]] : i32, !fir.ref +!CHECK: %[[ZERO_1:.*]] = arith.constant 0 : i32 +!CHECK: %[[X_DESIGNATE_MAXVAL:.*]] = hlfir.designate %[[X_DECL]]#0{"maxval"} : (!fir.ref<[[MAXTYPE]]>) -> !fir.ref +!CHECK: hlfir.assign %[[ZERO_1]] to %[[X_DESIGNATE_MAXVAL]] : i32, !fir.ref +!CHECK: return +!CHECK: } + + +!CHECK: func.func @_QMmaxtype_modPmycombine(%[[LHS:.*]]: !fir.ref<[[MAXTYPE]]> {fir.bindc_name = "lhs"}, %[[RHS:.*]]: !fir.ref<[[MAXTYPE]]> {fir.bindc_name = "rhs"}) -> [[MAXTYPE]] { +!CHECK: %[[SCOPE:.*]] = fir.dummy_scope : !fir.dscope +!CHECK: %[[LHS_DECL:.*]]:2 = hlfir.declare %[[LHS]] dummy_scope %[[SCOPE]] arg 1 {uniq_name = "_QMmaxtype_modFmycombineElhs"} : (!fir.ref<[[MAXTYPE]]>, !fir.dscope) -> (!fir.ref<[[MAXTYPE]]>, !fir.ref<[[MAXTYPE]]>) +!CHECK: %[[RESULT_ALLOC:.*]] = fir.alloca [[MAXTYPE]] {bindc_name = "mycombine", uniq_name = "_QMmaxtype_modFmycombineEmycombine"} +!CHECK: %[[RESULT_DECL:.*]]:2 = hlfir.declare %[[RESULT_ALLOC]] {uniq_name = "_QMmaxtype_modFmycombineEmycombine"} : (!fir.ref<[[MAXTYPE]]>) -> (!fir.ref<[[MAXTYPE]]>, !fir.ref<[[MAXTYPE]]>) +!CHECK: %[[RHS_DECL:.*]]:2 = hlfir.declare %[[RHS]] dummy_scope %[[SCOPE]] arg 2 {uniq_name = "_QMmaxtype_modFmycombineErhs"} : (!fir.ref<[[MAXTYPE]]>, !fir.dscope) -> (!fir.ref<[[MAXTYPE]]>, !fir.ref<[[MAXTYPE]]>) +!CHECK: %[[LHS_DESIGNATE_SUMVAL:.*]] = hlfir.designate %[[LHS_DECL]]#0{"sumval"} : (!fir.ref<[[MAXTYPE]]>) -> !fir.ref +!CHECK: %[[LHS_SUMVAL:.*]] = fir.load %[[LHS_DESIGNATE_SUMVAL]] : !fir.ref +!CHECK: %[[RHS_DESIGNATE_SUMVAL:.*]] = hlfir.designate %[[RHS_DECL]]#0{"sumval"} : (!fir.ref<[[MAXTYPE]]>) -> !fir.ref +!CHECK: %[[RHS_SUMVAL:.*]] = fir.load %[[RHS_DESIGNATE_SUMVAL]] : !fir.ref +!CHECK: %[[SUM:.*]] = arith.addi %[[LHS_SUMVAL]], %[[RHS_SUMVAL]] : i32 +!CHECK: %[[RESULT_DESIGNATE_SUMVAL:.*]] = hlfir.designate %[[RESULT_DECL]]#0{"sumval"} : (!fir.ref<[[MAXTYPE]]>) -> !fir.ref +!CHECK: hlfir.assign %[[SUM]] to %[[RESULT_DESIGNATE_SUMVAL]] : i32, !fir.ref +!CHECK: %[[LHS_DESIGNATE_MAXVAL:.*]] = hlfir.designate %[[LHS_DECL]]#0{"maxval"} : (!fir.ref<[[MAXTYPE]]>) -> !fir.ref +!CHECK: %[[LHS_MAXVAL:.*]] = fir.load %[[LHS_DESIGNATE_MAXVAL]] : !fir.ref +!CHECK: %[[RHS_DESIGNATE_MAXVAL:.*]] = hlfir.designate %[[RHS_DECL]]#0{"maxval"} : (!fir.ref<[[MAXTYPE]]>) -> !fir.ref +!CHECK: %[[RHS_MAXVAL:.*]] = fir.load %[[RHS_DESIGNATE_MAXVAL]] : !fir.ref +!CHECK: %[[CMP:.*]] = arith.cmpi sgt, %[[LHS_MAXVAL]], %[[RHS_MAXVAL]] : i32 +!CHECK: %[[MAX_VAL:.*]] = arith.select %[[CMP]], %[[LHS_MAXVAL]], %[[RHS_MAXVAL]] : i32 +!CHECK: %[[RESULT_DESIGNAGE_MAXVAL:.*]] = hlfir.designate %[[RESULT_DECL]]#0{"maxval"} : (!fir.ref<[[MAXTYPE]]>) -> !fir.ref +!CHECK: hlfir.assign %[[MAX_VAL]] to %[[RESULT_DESIGNAGE_MAXVAL]] : i32, !fir.ref +!CHECK: %[[RESULT:.*]] = fir.load %[[RESULT_DECL]]#0 : !fir.ref<[[MAXTYPE]]> +!CHECK: return %[[RESULT]] : [[MAXTYPE]] +!CHECK: } diff --git a/flang/test/Lower/OpenMP/omp-declare-reduction-initsub.f90 b/flang/test/Lower/OpenMP/omp-declare-reduction-initsub.f90 new file mode 100644 index 0000000000000..4aacc7cb2efba --- /dev/null +++ b/flang/test/Lower/OpenMP/omp-declare-reduction-initsub.f90 @@ -0,0 +1,59 @@ +! This test checks lowering of OpenMP declare reduction Directive, with initialization +! via a subroutine. This functionality is currently not implemented. + +!RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=52 %s -o - | FileCheck %s + +subroutine initme(x,n) + integer x,n + x=0 +end subroutine initme + +function func(x, n, init) + integer func + integer x(n) + integer res + interface + subroutine initme(x,n) + integer x,n + end subroutine initme + end interface +!CHECK: omp.declare_reduction @red_add : i32 init { +!CHECK: ^bb0(%[[OMP_ORIG_ARG_I:.*]]: i32): +!CHECK: %[[OMP_PRIV:.*]] = fir.alloca i32 +!CHECK: %[[OMP_ORIG:.*]] = fir.alloca i32 +!CHECK: fir.store %[[OMP_ORIG_ARG_I]] to %[[OMP_ORIG]] : !fir.ref +!CHECK: %[[OMP_ORIG_DECL:.*]]:2 = hlfir.declare %[[OMP_ORIG]] {uniq_name = "omp_orig"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK: fir.store %[[OMP_ORIG_ARG_I]] to %[[OMP_PRIV]] : !fir.ref +!CHECK: %[[OMP_PRIV_DECL:.*]]:2 = hlfir.declare %[[OMP_PRIV]] {uniq_name = "omp_priv"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK: fir.call @_QPinitme(%[[OMP_PRIV_DECL]]#0, %[[OMP_ORIG_DECL]]#0) fastmath : (!fir.ref, !fir.ref) -> () +!CHECK: %[[OMP_PRIV_VAL:.*]] = fir.load %[[OMP_PRIV_DECL]]#0 : !fir.ref +!CHECK: omp.yield(%[[OMP_PRIV_VAL]] : i32) +!CHECK: } combiner { +!CHECK: ^bb0(%[[LHS_ARG:.*]]: i32, %[[RHS_ARG:.*]]: i32): +!CHECK: %[[OMP_OUT:.*]] = fir.alloca i32 +!CHECK: %[[OMP_IN:.*]] = fir.alloca i32 +!CHECK: fir.store %[[RHS_ARG]] to %[[OMP_IN]] : !fir.ref +!CHECK: %[[OMP_IN_DECL:.*]]:2 = hlfir.declare %[[OMP_IN]] {uniq_name = "omp_in"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK: fir.store %[[LHS_ARG]] to %[[OMP_OUT]] : !fir.ref +!CHECK: %[[OMP_OUT_DECL:.*]]:2 = hlfir.declare %[[OMP_OUT]] {uniq_name = "omp_out"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK: %[[OMP_OUT_VAL:.*]] = fir.load %[[OMP_OUT_DECL]]#0 : !fir.ref +!CHECK: %[[OMP_IN_VAL:.*]] = fir.load %[[OMP_IN_DECL]]#0 : !fir.ref +!CHECK: %[[SUM:.*]] = arith.addi %[[OMP_OUT_VAL]], %[[OMP_IN_VAL]] : i32 +!CHECK: omp.yield(%[[SUM]] : i32) +!CHECK: } +!CHECK: func.func @_QPinitme(%[[X:.*]]: !fir.ref {fir.bindc_name = "x"}, %[[N:.*]]: !fir.ref {fir.bindc_name = "n"}) { +!CHECK: %[[SCOPE:.*]] = fir.dummy_scope : !fir.dscope +!CHECK: %[[N_DECL:.*]]:2 = hlfir.declare %[[N]] dummy_scope %[[SCOPE]] arg 2 {uniq_name = "_QFinitmeEn"} : (!fir.ref, !fir.dscope) -> (!fir.ref, !fir.ref) +!CHECK: %[[X_DECL:.*]]:2 = hlfir.declare %[[X]] dummy_scope %[[OMP_OUT]] arg 1 {uniq_name = "_QFinitmeEx"} : (!fir.ref, !fir.dscope) -> (!fir.ref, !fir.ref) +!CHECK: %[[CONST_0:.*]] = arith.constant 0 : i32 +!CHECK: hlfir.assign %[[CONST_0]] to %[[X_DECL]]#0 : i32, !fir.ref +!CHECK: return +!CHECK: } +!$omp declare reduction(red_add:integer(4):omp_out=omp_out+omp_in) initializer(initme(omp_priv,omp_orig)) + res=init +!$omp simd reduction(red_add:res) + do i=1,n + res=res+x(i) + enddo + func=res +end function func diff --git a/flang/test/Lower/OpenMP/omp-declare-reduction.f90 b/flang/test/Lower/OpenMP/omp-declare-reduction.f90 new file mode 100644 index 0000000000000..a41f6b214b9d8 --- /dev/null +++ b/flang/test/Lower/OpenMP/omp-declare-reduction.f90 @@ -0,0 +1,33 @@ +! This test checks lowering of OpenMP declare reduction Directive. + +!RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=52 %s -o - | FileCheck %s + +subroutine declare_red() + integer :: my_var +!CHECK: omp.declare_reduction @my_red : i32 init { +!CHECK: ^bb0(%[[OMP_ORIG_ARG_I:.*]]: i32): +!CHECK: %[[OMP_PRIV:.*]] = fir.alloca i32 +!CHECK: %[[OMP_ORIG:.*]] = fir.alloca i32 +!CHECK: fir.store %[[OMP_ORIG_ARG_I]] to %[[OMP_ORIG]] : !fir.ref +!CHECK: %[[OMP_ORIG_DECL:.*]]:2 = hlfir.declare %[[OMP_ORIG]] {uniq_name = "omp_orig"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK: fir.store %[[OMP_ORIG_ARG_I]] to %[[OMP_PRIV]] : !fir.ref +!CHECK: %[[OMP_PRIV_DECL:.*]]:2 = hlfir.declare %[[OMP_PRIV]] {uniq_name = "omp_priv"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK: %[[CONST_0:.*]] = arith.constant 0 : i32 +!CHECK: omp.yield(%[[CONST_0]] : i32) +!CHECK: } combiner { +!CHECK: ^bb0(%[[LHS_ARG:.*]]: i32, %[[RHS_ARG:.*]]: i32): +!CHECK: %[[OMP_OUT:.*]] = fir.alloca i32 +!CHECK: %[[OMP_IN:.*]] = fir.alloca i32 +!CHECK: fir.store %[[RHS_ARG]] to %[[OMP_IN]] : !fir.ref +!CHECK: %[[OMP_IN_DECL:.*]]:2 = hlfir.declare %[[OMP_IN]] {uniq_name = "omp_in"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK: fir.store %[[LHS_ARG]] to %[[OMP_OUT]] : !fir.ref +!CHECK: %[[OMP_OUT_DECL:.*]]:2 = hlfir.declare %[[OMP_OUT]] {uniq_name = "omp_out"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK: %[[OMP_OUT_VAL:.*]] = fir.load %[[OMP_OUT_DECL]]#0 : !fir.ref +!CHECK: %[[OMP_IN_VAL:.*]] = fir.load %[[OMP_IN_DECL]]#0 : !fir.ref +!CHECK: %[[SUM:.*]] = arith.addi %[[OMP_OUT_VAL]], %[[OMP_IN_VAL]] : i32 +!CHECK: omp.yield(%[[SUM]] : i32) +!CHECK: } + + !$omp declare reduction (my_red : integer : omp_out = omp_out + omp_in) initializer (omp_priv = 0) + my_var = 0 +end subroutine declare_red diff --git a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp index a62bfeb400ee2..5511f4f1af1ad 100644 --- a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp +++ b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp @@ -1170,6 +1170,7 @@ allocReductionVars(T loop, ArrayRef reductionArgs, template static void mapInitializationArgs(T loop, LLVM::ModuleTranslation &moduleTranslation, + llvm::IRBuilderBase &builder, SmallVectorImpl &reductionDecls, DenseMap &reductionVariableMap, unsigned i) { @@ -1180,8 +1181,17 @@ mapInitializationArgs(T loop, LLVM::ModuleTranslation &moduleTranslation, mlir::Value mlirSource = loop.getReductionVars()[i]; llvm::Value *llvmSource = moduleTranslation.lookupValue(mlirSource); - assert(llvmSource && "lookup reduction var"); - moduleTranslation.mapValue(reduction.getInitializerMoldArg(), llvmSource); + llvm::Value *origVal = llvmSource; + // If a non-pointer value is expected, load the value from the source pointer. + if (!isa( + reduction.getInitializerMoldArg().getType()) && + isa(mlirSource.getType())) { + origVal = + builder.CreateLoad(moduleTranslation.convertType( + reduction.getInitializerMoldArg().getType()), + llvmSource, "omp_orig"); + } + moduleTranslation.mapValue(reduction.getInitializerMoldArg(), origVal); if (entry.getNumArguments() > 1) { llvm::Value *allocation = @@ -1254,7 +1264,7 @@ initReductionVars(OP op, ArrayRef reductionArgs, SmallVector phis; // map block argument to initializer region - mapInitializationArgs(op, moduleTranslation, reductionDecls, + mapInitializationArgs(op, moduleTranslation, builder, reductionDecls, reductionVariableMap, i); // TODO In some cases (specially on the GPU), the init regions may diff --git a/offload/test/offloading/fortran/target-custom-reduction-derivedtype.f90 b/offload/test/offloading/fortran/target-custom-reduction-derivedtype.f90 new file mode 100644 index 0000000000000..cc390cf0881f3 --- /dev/null +++ b/offload/test/offloading/fortran/target-custom-reduction-derivedtype.f90 @@ -0,0 +1,88 @@ +! Basic offloading test with custom OpenMP reduction on derived type +! REQUIRES: flang, amdgpu +! +! RUN: %libomptarget-compile-fortran-generic +! RUN: env LIBOMPTARGET_INFO=16 %libomptarget-run-generic 2>&1 | %fcheck-generic +module maxtype_mod + implicit none + + type maxtype + integer::sumval + integer::maxval + end type maxtype + +contains + + subroutine initme(x,n) + type(maxtype) :: x,n + x%sumval=0 + x%maxval=0 + end subroutine initme + + function mycombine(lhs, rhs) + type(maxtype) :: lhs, rhs + type(maxtype) :: mycombine + mycombine%sumval = lhs%sumval + rhs%sumval + mycombine%maxval = max(lhs%maxval, rhs%maxval) + end function mycombine + +end module maxtype_mod + +program main + use maxtype_mod + implicit none + + integer :: n = 100 + integer :: i + integer :: error = 0 + type(maxtype) :: x(100) + type(maxtype) :: res + integer :: expected_sum, expected_max + +!$omp declare reduction(red_add_max:maxtype:omp_out=mycombine(omp_out,omp_in)) initializer(initme(omp_priv,omp_orig)) + + ! Initialize array with test data + do i = 1, n + x(i)%sumval = i + x(i)%maxval = i + end do + + ! Initialize reduction variable + res%sumval = 0 + res%maxval = 0 + + ! Perform reduction in target region + !$omp target parallel do map(to:x) reduction(red_add_max:res) + do i = 1, n + res = mycombine(res, x(i)) + end do + !$omp end target parallel do + + ! Compute expected values + expected_sum = 0 + expected_max = 0 + do i = 1, n + expected_sum = expected_sum + i + expected_max = max(expected_max, i) + end do + + ! Check results + if (res%sumval /= expected_sum) then + error = 1 + endif + + if (res%maxval /= expected_max) then + error = 1 + endif + + if (error == 0) then + print *,"PASSED" + else + print *,"FAILED" + endif + +end program main + +! CHECK: "PluginInterface" device {{[0-9]+}} info: Launching kernel {{.*}} +! CHECK: PASSED + From 01a98b383c700c2580e11a166dce1180188cb236 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Storsj=C3=B6?= Date: Mon, 24 Nov 2025 23:07:27 +0200 Subject: [PATCH 14/50] [libcxx] [test] Fix the gets-removed.verify.cpp test with Clang 21 (#169235) This fixes test errors like this, at least for a mingw target, if building with Clang 21 instead of Clang 20, as in the CI environment: # .---command stderr------------ # | error: 'expected-error' diagnostics seen but not expected: # | File C:\a\llvm-mingw\llvm-mingw\llvm-project\libcxx\test\std\input.output\file.streams\c.files\gets-removed.verify.cpp Line 16: cannot initialize a parameter of type 'char *' with an lvalue of type 'const char *' # | 1 error generated. # `----------------------------- # error: command failed with exit status: 1 This extra, unexpected diagnostic appears in Clang 21, since commit 9eef4d1c5fa6b1bcbbe675c14ca8301d5d346f7b ("Remove delayed typo expressions"). Before this, we got the expected diagnostic `error: no member named 'gets' in namespace 'std'`, with the typo correction hint `did you mean 'puts'?`. After this change, we get the typo correction hint `did you mean simply 'gets'?` instead. And with the typo correction finding `::gets`, it goes on to produce a second diagnostic about mismatched parameter for that function. Avoid these unexpected diagnostics by passing the right type of parameter to the gets function. --- .../input.output/file.streams/c.files/gets-removed.verify.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcxx/test/std/input.output/file.streams/c.files/gets-removed.verify.cpp b/libcxx/test/std/input.output/file.streams/c.files/gets-removed.verify.cpp index 281ef37e92d27..fb49375a21baa 100644 --- a/libcxx/test/std/input.output/file.streams/c.files/gets-removed.verify.cpp +++ b/libcxx/test/std/input.output/file.streams/c.files/gets-removed.verify.cpp @@ -12,6 +12,6 @@ #include -void f(char const* str) { +void f(char* str) { (void)std::gets(str); // expected-error {{no member named 'gets' in namespace 'std'}} } From 89206de09c698f0f2e9ba106ebf3b67953041d2c Mon Sep 17 00:00:00 2001 From: David Peixotto Date: Mon, 24 Nov 2025 13:10:53 -0800 Subject: [PATCH 15/50] [lldb] Add mock dwarf delegate for testing dwarf expressions (#168468) This commit adds a `MockDwarfDelegate` class that can be used to control what dwarf version is used when evaluating an expression. We also add a simple test that shows how dwarf version can change the result of the expression. --- .../Expression/DWARFExpressionTest.cpp | 64 ++++++++++++++++++- 1 file changed, 63 insertions(+), 1 deletion(-) diff --git a/lldb/unittests/Expression/DWARFExpressionTest.cpp b/lldb/unittests/Expression/DWARFExpressionTest.cpp index a95456119956e..e0c2193d27c36 100644 --- a/lldb/unittests/Expression/DWARFExpressionTest.cpp +++ b/lldb/unittests/Expression/DWARFExpressionTest.cpp @@ -40,6 +40,51 @@ using namespace lldb_private; using namespace llvm::dwarf; namespace { +/// A mock implementation of DWARFExpression::Delegate for testing. +/// This class provides default implementations of all delegate methods, +/// with the DWARF version being configurable via the constructor. +class MockDwarfDelegate : public DWARFExpression::Delegate { +public: + static constexpr uint16_t DEFAULT_DWARF_VERSION = 5; + static MockDwarfDelegate Dwarf5() { return MockDwarfDelegate(5); } + static MockDwarfDelegate Dwarf2() { return MockDwarfDelegate(2); } + + MockDwarfDelegate() : MockDwarfDelegate(DEFAULT_DWARF_VERSION) {} + explicit MockDwarfDelegate(uint16_t version) : m_dwarf_version(version) {} + + uint16_t GetVersion() const override { return m_dwarf_version; } + + dw_addr_t GetBaseAddress() const override { return 0; } + + uint8_t GetAddressByteSize() const override { return 4; } + + llvm::Expected> + GetDIEBitSizeAndSign(uint64_t relative_die_offset) const override { + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "GetDIEBitSizeAndSign not implemented"); + } + + dw_addr_t ReadAddressFromDebugAddrSection(uint32_t index) const override { + return 0; + } + + lldb::offset_t GetVendorDWARFOpcodeSize(const DataExtractor &data, + const lldb::offset_t data_offset, + const uint8_t op) const override { + return LLDB_INVALID_OFFSET; + } + + bool ParseVendorDWARFOpcode(uint8_t op, const DataExtractor &opcodes, + lldb::offset_t &offset, RegisterContext *reg_ctx, + lldb::RegisterKind reg_kind, + DWARFExpression::Stack &stack) const override { + return false; + } + +private: + uint16_t m_dwarf_version; +}; + /// Mock memory implementation for testing. /// Stores predefined memory contents indexed by {address, size} pairs. class MockMemory { @@ -189,7 +234,7 @@ class MockRegisterContext : public RegisterContext { static llvm::Expected Evaluate(llvm::ArrayRef expr, lldb::ModuleSP module_sp = {}, - DWARFUnit *unit = nullptr, + DWARFExpression::Delegate *unit = nullptr, ExecutionContext *exe_ctx = nullptr, RegisterContext *reg_ctx = nullptr) { DataExtractor extractor(expr.data(), expr.size(), lldb::eByteOrderLittle, @@ -534,6 +579,23 @@ TEST(DWARFExpression, DW_OP_stack_value) { EXPECT_THAT_EXPECTED(Evaluate({DW_OP_stack_value}), llvm::Failed()); } +// This test shows that the dwarf version is used by the expression evaluation. +// Note that the different behavior tested here is not meant to imply that this +// is the correct interpretation of dwarf2 vs. dwarf5, but rather it was picked +// as an easy example that evaluates differently based on the dwarf version. +TEST(DWARFExpression, dwarf_version) { + MockDwarfDelegate dwarf2 = MockDwarfDelegate::Dwarf2(); + MockDwarfDelegate dwarf5 = MockDwarfDelegate::Dwarf5(); + + // In dwarf2 the constant on top of the stack is treated as a value. + EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit1}, {}, &dwarf2), ExpectScalar(1)); + + // In dwarf5 the constant on top of the stack is implicitly converted to an + // address. + EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit1}, {}, &dwarf5), + ExpectLoadAddress(1)); +} + TEST(DWARFExpression, DW_OP_piece) { EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const2u, 0x11, 0x22, DW_OP_piece, 2, DW_OP_const2u, 0x33, 0x44, DW_OP_piece, 2}), From 3dcdb4c7658fb955d61fde5bd5232bdeadfc7eeb Mon Sep 17 00:00:00 2001 From: Nikolas Klauser Date: Mon, 24 Nov 2025 22:36:13 +0100 Subject: [PATCH 16/50] [libc++][NFC] Move __memory/aligned_alloc.h into src/ (#166172) This header is only ever used inside `src/`, so we might as well move it there. As a drive-by this also removes some dead code. --- libcxx/include/CMakeLists.txt | 1 - libcxx/include/__config | 21 ------------------- libcxx/include/module.modulemap.in | 1 - .../__memory => src/include}/aligned_alloc.h | 10 +++++---- .../support.dynamic/libcpp_deallocate.sh.cpp | 7 +++---- libcxxabi/src/fallback_malloc.cpp | 2 +- libcxxabi/src/stdlib_new_delete.cpp | 2 +- 7 files changed, 11 insertions(+), 33 deletions(-) rename libcxx/{include/__memory => src/include}/aligned_alloc.h (90%) diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt index f289666ec12ab..a6bd3eacc095c 100644 --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -569,7 +569,6 @@ set(files __mdspan/mdspan.h __memory/addressof.h __memory/align.h - __memory/aligned_alloc.h __memory/allocate_at_least.h __memory/allocation_guard.h __memory/allocator.h diff --git a/libcxx/include/__config b/libcxx/include/__config index 1b27f28f9ddef..ba10d95b92827 100644 --- a/libcxx/include/__config +++ b/libcxx/include/__config @@ -495,27 +495,6 @@ typedef __char32_t char32_t; # define _LIBCPP_HAS_ALIGNED_ALLOCATION 1 # endif -// It is not yet possible to use aligned_alloc() on all Apple platforms since -// 10.15 was the first version to ship an implementation of aligned_alloc(). -# if defined(__APPLE__) -# if (defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && \ - __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 101500) || \ - (defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && \ - __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ < 130000) || \ - (defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) && \ - __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ < 60000) || \ - (defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ < 130000) -# define _LIBCPP_HAS_C11_ALIGNED_ALLOC 0 -# else -# define _LIBCPP_HAS_C11_ALIGNED_ALLOC 1 -# endif -# elif defined(__ANDROID__) && __ANDROID_API__ < 28 -// Android only provides aligned_alloc when targeting API 28 or higher. -# define _LIBCPP_HAS_C11_ALIGNED_ALLOC 0 -# else -# define _LIBCPP_HAS_C11_ALIGNED_ALLOC 1 -# endif - # if defined(__APPLE__) || defined(__FreeBSD__) # define _LIBCPP_WCTYPE_IS_MASK # endif diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in index 492708792cbbf..1ee418b0b4337 100644 --- a/libcxx/include/module.modulemap.in +++ b/libcxx/include/module.modulemap.in @@ -1628,7 +1628,6 @@ module std [system] { module memory { module addressof { header "__memory/addressof.h" } module align { header "__memory/align.h" } - module aligned_alloc { header "__memory/aligned_alloc.h" } module allocate_at_least { header "__memory/allocate_at_least.h" } module allocation_guard { header "__memory/allocation_guard.h" } module allocator { diff --git a/libcxx/include/__memory/aligned_alloc.h b/libcxx/src/include/aligned_alloc.h similarity index 90% rename from libcxx/include/__memory/aligned_alloc.h rename to libcxx/src/include/aligned_alloc.h index fb36983d9c3dc..24ca26ce04525 100644 --- a/libcxx/include/__memory/aligned_alloc.h +++ b/libcxx/src/include/aligned_alloc.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef _LIBCPP___MEMORY_ALIGNED_ALLOC_H -#define _LIBCPP___MEMORY_ALIGNED_ALLOC_H +#ifndef _LIBCPP_SRC_ALIGNED_ALLOC_H +#define _LIBCPP_SRC_ALIGNED_ALLOC_H #include <__config> #include @@ -29,7 +29,9 @@ _LIBCPP_BEGIN_NAMESPACE_STD inline _LIBCPP_HIDE_FROM_ABI void* __libcpp_aligned_alloc(std::size_t __alignment, std::size_t __size) { # if defined(_LIBCPP_MSVCRT_LIKE) return ::_aligned_malloc(__size, __alignment); -# elif _LIBCPP_STD_VER >= 17 && _LIBCPP_HAS_C11_ALIGNED_ALLOC + +// Android only provides aligned_alloc when targeting API 28 or higher. +# elif !defined(__ANDROID__) || __ANDROID_API__ >= 28 // aligned_alloc() requires that __size is a multiple of __alignment, // but for C++ [new.delete.general], only states "if the value of an // alignment argument passed to any of these functions is not a valid @@ -60,4 +62,4 @@ inline _LIBCPP_HIDE_FROM_ABI void __libcpp_aligned_free(void* __ptr) { _LIBCPP_END_NAMESPACE_STD -#endif // _LIBCPP___MEMORY_ALIGNED_ALLOC_H +#endif // _LIBCPP_SRC_ALIGNED_ALLOC_H diff --git a/libcxx/test/libcxx/language.support/support.dynamic/libcpp_deallocate.sh.cpp b/libcxx/test/libcxx/language.support/support.dynamic/libcpp_deallocate.sh.cpp index 4bb42cb532078..282d49d727c8c 100644 --- a/libcxx/test/libcxx/language.support/support.dynamic/libcpp_deallocate.sh.cpp +++ b/libcxx/test/libcxx/language.support/support.dynamic/libcpp_deallocate.sh.cpp @@ -21,6 +21,8 @@ // GCC doesn't support the aligned-allocation flags. // XFAIL: gcc +// ADDITIONAL_COMPILE_FLAGS: -I %{libcxx-dir}/src -Wno-macro-redefined + // RUN: %{build} -faligned-allocation -fsized-deallocation // RUN: %{run} // RUN: %{build} -faligned-allocation -fno-sized-deallocation -DNO_SIZE @@ -36,10 +38,7 @@ #include "test_macros.h" -TEST_DIAGNOSTIC_PUSH -TEST_CLANG_DIAGNOSTIC_IGNORED("-Wprivate-header") -#include <__memory/aligned_alloc.h> -TEST_DIAGNOSTIC_POP +#include "include/aligned_alloc.h" struct alloc_stats { alloc_stats() { reset(); } diff --git a/libcxxabi/src/fallback_malloc.cpp b/libcxxabi/src/fallback_malloc.cpp index 75788fe9be8d9..6a261e6f009fe 100644 --- a/libcxxabi/src/fallback_malloc.cpp +++ b/libcxxabi/src/fallback_malloc.cpp @@ -16,7 +16,7 @@ #endif #endif -#include <__memory/aligned_alloc.h> +#include "include/aligned_alloc.h" // from libc++ #include <__assert> #include // for malloc, calloc, free #include // for memset diff --git a/libcxxabi/src/stdlib_new_delete.cpp b/libcxxabi/src/stdlib_new_delete.cpp index b5ed59958d17e..dbb75b128a2a4 100644 --- a/libcxxabi/src/stdlib_new_delete.cpp +++ b/libcxxabi/src/stdlib_new_delete.cpp @@ -8,8 +8,8 @@ #include "__cxxabi_config.h" #include "abort_message.h" +#include "include/aligned_alloc.h" // from libc++ #include "include/overridable_function.h" // from libc++ -#include <__memory/aligned_alloc.h> #include #include #include From 8a431db0045b33ad9a7e4d4d89f5691ffc897088 Mon Sep 17 00:00:00 2001 From: LLVM GN Syncbot Date: Mon, 24 Nov 2025 21:36:29 +0000 Subject: [PATCH 17/50] [gn build] Port 3dcdb4c7658f --- llvm/utils/gn/secondary/libcxx/include/BUILD.gn | 1 - 1 file changed, 1 deletion(-) diff --git a/llvm/utils/gn/secondary/libcxx/include/BUILD.gn b/llvm/utils/gn/secondary/libcxx/include/BUILD.gn index 82fe916645635..3985e4b73fcfc 100644 --- a/llvm/utils/gn/secondary/libcxx/include/BUILD.gn +++ b/llvm/utils/gn/secondary/libcxx/include/BUILD.gn @@ -1216,7 +1216,6 @@ if (current_toolchain == default_toolchain) { "__mdspan/mdspan.h", "__memory/addressof.h", "__memory/align.h", - "__memory/aligned_alloc.h", "__memory/allocate_at_least.h", "__memory/allocation_guard.h", "__memory/allocator.h", From e737f67fcf883e90683e1dd46247bd176fe15b5f Mon Sep 17 00:00:00 2001 From: Yu Hao Date: Mon, 24 Nov 2025 13:46:29 -0800 Subject: [PATCH 18/50] [clang][transformer] Fix `node` range-selector to include type name qualifiers of type locs. (#167619) Previously, e.g. for TypeLoc "MyNamespace::MyClass", `node()` selects only "MyClass" without the qualifier. With this change, it now selects "MyNamespace::MyClass". --------- Co-authored-by: Florian Mayer --- clang/lib/Tooling/Transformer/RangeSelector.cpp | 3 ++- clang/unittests/Tooling/RangeSelectorTest.cpp | 7 +++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/clang/lib/Tooling/Transformer/RangeSelector.cpp b/clang/lib/Tooling/Transformer/RangeSelector.cpp index b4bdec1fcdd69..54a1590d3106d 100644 --- a/clang/lib/Tooling/Transformer/RangeSelector.cpp +++ b/clang/lib/Tooling/Transformer/RangeSelector.cpp @@ -139,7 +139,8 @@ RangeSelector transformer::node(std::string ID) { (Node->get() != nullptr && Node->get() == nullptr)) ? tooling::getExtendedRange(*Node, tok::TokenKind::semi, *Result.Context) - : CharSourceRange::getTokenRange(Node->getSourceRange()); + : CharSourceRange::getTokenRange( + Node->getSourceRange(/*IncludeQualifier=*/true)); }; } diff --git a/clang/unittests/Tooling/RangeSelectorTest.cpp b/clang/unittests/Tooling/RangeSelectorTest.cpp index a1fcbb023832f..d441da165b09b 100644 --- a/clang/unittests/Tooling/RangeSelectorTest.cpp +++ b/clang/unittests/Tooling/RangeSelectorTest.cpp @@ -339,6 +339,13 @@ TEST(RangeSelectorTest, NodeOpExpression) { EXPECT_THAT_EXPECTED(select(node("id"), Match), HasValue("3")); } +TEST(RangeSelectorTest, NodeOpTypeLoc) { + StringRef Code = "namespace ns {struct Foo{};} ns::Foo a;"; + TestMatch Match = + matchCode(Code, varDecl(hasTypeLoc(typeLoc().bind("typeloc")))); + EXPECT_THAT_EXPECTED(select(node("typeloc"), Match), HasValue("ns::Foo")); +} + TEST(RangeSelectorTest, StatementOp) { StringRef Code = "int f() { return 3; }"; TestMatch Match = matchCode(Code, expr().bind("id")); From 1e1974a903c505de1f42257044b7a03a390d7a8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Storsj=C3=B6?= Date: Mon, 24 Nov 2025 23:51:40 +0200 Subject: [PATCH 19/50] [compiler-rt] [test] Avoid error printouts if os.sysconf is missing (#168857) This avoids dozens of instances of benign error messages being printed when running the tests on e.g. Windows: Traceback (most recent call last): File "", line 1, in AttributeError: module 'os' has no attribute 'sysconf' Co-authored-by: Florian Mayer --- compiler-rt/test/lit.common.cfg.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler-rt/test/lit.common.cfg.py b/compiler-rt/test/lit.common.cfg.py index ea22fb0babc46..dce01cc9743b3 100644 --- a/compiler-rt/test/lit.common.cfg.py +++ b/compiler-rt/test/lit.common.cfg.py @@ -971,7 +971,9 @@ def target_page_size(): stdin=subprocess.PIPE, stdout=subprocess.PIPE, ) - out, err = proc.communicate(b'import os; print(os.sysconf("SC_PAGESIZE"))') + out, err = proc.communicate( + b'import os; print(os.sysconf("SC_PAGESIZE") if hasattr(os, "sysconf") else "")' + ) return int(out) except: return 4096 From adf4c1dbb62600747fc74843efcdca5c3ee9c26a Mon Sep 17 00:00:00 2001 From: Jordan Rupprecht Date: Mon, 24 Nov 2025 15:54:39 -0600 Subject: [PATCH 20/50] [bazel][clang] Port dea330b38d9c18b68219abdb52baaa72c9f1103d (#169410) --- utils/bazel/llvm-project-overlay/clang/BUILD.bazel | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/bazel/llvm-project-overlay/clang/BUILD.bazel b/utils/bazel/llvm-project-overlay/clang/BUILD.bazel index 020b2aa68a357..4ac3e75b9c1ce 100644 --- a/utils/bazel/llvm-project-overlay/clang/BUILD.bazel +++ b/utils/bazel/llvm-project-overlay/clang/BUILD.bazel @@ -1563,7 +1563,6 @@ cc_library( ":basic", ":config", ":driver_options_inc_gen", - ":frontend", ":lex", ":options", ":parse", @@ -1719,6 +1718,7 @@ cc_library( ":ast", ":basic", ":config", + ":driver", ":driver_options_inc_gen", ":edit", ":lex", From ba98668dcacc6d6b223f8a53b3c52a7cea2063e8 Mon Sep 17 00:00:00 2001 From: Tarun Prabhu Date: Mon, 24 Nov 2025 14:58:41 -0700 Subject: [PATCH 21/50] [flang][NFC] Strip trailing whitespace from tests (8 of N) Only some fortran source files in flang/test/Lower have been modified. The other files in the directory will be cleaned up in subsequent commits --- .../Lower/identical-block-merge-disable.f90 | 4 +-- flang/test/Lower/implicit-interface.f90 | 2 +- flang/test/Lower/inline_directive.f90 | 2 +- flang/test/Lower/io-statement-1.f90 | 2 +- flang/test/Lower/io-write.f90 | 2 +- flang/test/Lower/location.f90 | 2 +- flang/test/Lower/module_definition.f90 | 2 +- flang/test/Lower/module_use.f90 | 2 +- flang/test/Lower/module_use_in_same_file.f90 | 4 +-- flang/test/Lower/namelist-common-block.f90 | 2 +- flang/test/Lower/nested-where.f90 | 2 +- flang/test/Lower/nullify-polymorphic.f90 | 8 +++--- .../Lower/pointer-association-polymorphic.f90 | 10 +++---- flang/test/Lower/pointer-disassociate.f90 | 4 +-- flang/test/Lower/polymorphic-temp.f90 | 4 +-- flang/test/Lower/polymorphic-types.f90 | 2 +- flang/test/Lower/polymorphic.f90 | 12 ++++----- flang/test/Lower/pre-fir-tree02.f90 | 2 +- flang/test/Lower/procedure-declarations.f90 | 20 +++++++------- flang/test/Lower/read-write-buffer.f90 | 4 +-- flang/test/Lower/select-type.f90 | 16 ++++++------ flang/test/Lower/statement-function.f90 | 2 +- flang/test/Lower/variable.f90 | 2 +- flang/test/Lower/volatile-allocatable.f90 | 26 +++++++++---------- flang/test/Lower/volatile-openmp1.f90 | 2 +- 25 files changed, 70 insertions(+), 70 deletions(-) diff --git a/flang/test/Lower/identical-block-merge-disable.f90 b/flang/test/Lower/identical-block-merge-disable.f90 index cc3120a3b6f67..ff3ff67b7b213 100644 --- a/flang/test/Lower/identical-block-merge-disable.f90 +++ b/flang/test/Lower/identical-block-merge-disable.f90 @@ -6,7 +6,7 @@ MODULE DMUMPS_SOL_LR IMPLICIT NONE TYPE BLR_STRUC_T - INTEGER, DIMENSION(:), POINTER :: PANELS_L + INTEGER, DIMENSION(:), POINTER :: PANELS_L INTEGER, DIMENSION(:), POINTER :: PANELS_U INTEGER, DIMENSION(:), POINTER :: BEGS_BLR_STATIC END TYPE BLR_STRUC_T @@ -32,7 +32,7 @@ SUBROUTINE DMUMPS_SOL_FWD_LR_SU( IWHDLR, MTYPE ) ENDIF ENDIF -END SUBROUTINE DMUMPS_SOL_FWD_LR_SU +END SUBROUTINE DMUMPS_SOL_FWD_LR_SU END MODULE DMUMPS_SOL_LR diff --git a/flang/test/Lower/implicit-interface.f90 b/flang/test/Lower/implicit-interface.f90 index f924a3f5d3e9e..0be50203b2c01 100644 --- a/flang/test/Lower/implicit-interface.f90 +++ b/flang/test/Lower/implicit-interface.f90 @@ -22,7 +22,7 @@ subroutine test_passing_char_array ! CHECK-DAG: %[[c3:.*]] = arith.constant 3 : index ! CHECK-DAG: %[[xbuff:.*]] = fir.convert %[[xarray]] : (!fir.ref>>) -> !fir.ref> ! CHECK: %[[boxchar:.*]] = fir.emboxchar %[[xbuff]], %[[c3]] : (!fir.ref>, index) -> !fir.boxchar<1> - ! CHECK: fir.call @_QPsub_taking_a_char_array(%[[boxchar]]) {{.*}}: (!fir.boxchar<1>) -> () + ! CHECK: fir.call @_QPsub_taking_a_char_array(%[[boxchar]]) {{.*}}: (!fir.boxchar<1>) -> () end subroutine ! TODO more implicit interface cases with/without explicit interface diff --git a/flang/test/Lower/inline_directive.f90 b/flang/test/Lower/inline_directive.f90 index 347df85f05dda..5748690d5914d 100644 --- a/flang/test/Lower/inline_directive.f90 +++ b/flang/test/Lower/inline_directive.f90 @@ -11,7 +11,7 @@ subroutine test_inline() y = g(x) !CHECK: %[[VAL_4:.*]] = fir.call @_QFtest_inlinePg(%[[VAL_1]]) fastmath {inline_attr = #fir.inline_attrs} : (!fir.ref) -> i32 !CHECK: fir.store %[[VAL_4]] to %[[VAL_3]] : !fir.ref - + !dir$ forceinline call f(x, y) !CHECK: fir.call @_QFtest_inlinePf(%[[VAL_1]], %[[VAL_3]]) fastmath {inline_attr = #fir.inline_attrs} : (!fir.ref, !fir.ref) -> () diff --git a/flang/test/Lower/io-statement-1.f90 b/flang/test/Lower/io-statement-1.f90 index ac7874594d2fc..ecf2e2d287774 100644 --- a/flang/test/Lower/io-statement-1.f90 +++ b/flang/test/Lower/io-statement-1.f90 @@ -19,7 +19,7 @@ ! CHECK: call {{.*}}BeginFlush ! CHECK: call {{.*}}EndIoStatement flush(8) - + ! CHECK: call {{.*}}BeginRewind ! CHECK: call {{.*}}EndIoStatement rewind(8) diff --git a/flang/test/Lower/io-write.f90 b/flang/test/Lower/io-write.f90 index 234fcdabeaac8..3159dcf771bb7 100644 --- a/flang/test/Lower/io-write.f90 +++ b/flang/test/Lower/io-write.f90 @@ -1,6 +1,6 @@ ! RUN: bbc -emit-fir -hlfir=false %s -o - | FileCheck %s -! Test that IO item calls stackrestore in the right place +! Test that IO item calls stackrestore in the right place ! CHECK-LABEL: func.func @_QQmain() { character(3) string diff --git a/flang/test/Lower/location.f90 b/flang/test/Lower/location.f90 index 95bf2260fc107..cdde1cc4cb40a 100644 --- a/flang/test/Lower/location.f90 +++ b/flang/test/Lower/location.f90 @@ -3,7 +3,7 @@ program test include 'location0.inc' -end +end ! CHECK-LABEL: func.func @_QQmain() attributes {fir.bindc_name = "TEST"} { ! CHECK: fir.call @_FortranAioOutputAscii(%{{.*}}, %{{.*}}, %{{.*}}) fastmath : (!fir.ref, !fir.ref, i64) -> i1 loc(fused<#fir>["{{.*}}location1.inc":1:10, "{{.*}}location0.inc":1:1, "{{.*}}location.f90":4:1]) diff --git a/flang/test/Lower/module_definition.f90 b/flang/test/Lower/module_definition.f90 index 0a05364ca473c..a96bc919c6730 100644 --- a/flang/test/Lower/module_definition.f90 +++ b/flang/test/Lower/module_definition.f90 @@ -36,7 +36,7 @@ module m1 ! file. module modEq1 ! Equivalence, no initialization - real :: x1(10), x2(10), x3(10) + real :: x1(10), x2(10), x3(10) ! Equivalence with initialization real :: y1 = 42. real :: y2(10) diff --git a/flang/test/Lower/module_use.f90 b/flang/test/Lower/module_use.f90 index 92acbfbee0b9e..e7f56f57b2c7e 100644 --- a/flang/test/Lower/module_use.f90 +++ b/flang/test/Lower/module_use.f90 @@ -36,7 +36,7 @@ real function modCommon1Use() ! CHECK-DAG: fir.address_of(@named2_) : !fir.ref> ! CHECK-DAG: fir.address_of(@__BLNK__) : !fir.ref> ! CHECK-DAG: fir.address_of(@named1_) : !fir.ref> - modCommon1Use = x_blank + x_named1 + i_named2 + modCommon1Use = x_blank + x_named1 + i_named2 end function diff --git a/flang/test/Lower/module_use_in_same_file.f90 b/flang/test/Lower/module_use_in_same_file.f90 index 9e51bee14fd7a..7ef64f0bc160e 100644 --- a/flang/test/Lower/module_use_in_same_file.f90 +++ b/flang/test/Lower/module_use_in_same_file.f90 @@ -35,7 +35,7 @@ real function m2use_rename() ! Module modEq2 defines data that is equivalenced module modEq2 ! Equivalence, no initialization - real :: x1(10), x2(10), x3(10) + real :: x1(10), x2(10), x3(10) ! Equivalence with initialization real :: y1 = 42. real :: y2(10) @@ -109,7 +109,7 @@ real function test_no_equiv_conflicts() use modEq2 ! Same equivalences as in modEq2. Test that lowering does not mixes ! up the equivalence based on the similar offset inside the scope. - real :: x1l(10), x2l(10), x3l(10) + real :: x1l(10), x2l(10), x3l(10) real :: y1l = 42. real :: y2l(10) save :: x1l, x2l, x3l, y1l, y2l diff --git a/flang/test/Lower/namelist-common-block.f90 b/flang/test/Lower/namelist-common-block.f90 index d16f886dadb5b..54d4b9e552510 100644 --- a/flang/test/Lower/namelist-common-block.f90 +++ b/flang/test/Lower/namelist-common-block.f90 @@ -8,7 +8,7 @@ program nml_common real, pointer :: p(:) namelist /t/i,p common /c/i,p - + allocate(p(2)) call print_t() contains diff --git a/flang/test/Lower/nested-where.f90 b/flang/test/Lower/nested-where.f90 index 28aced2325813..1e379667b7b03 100644 --- a/flang/test/Lower/nested-where.f90 +++ b/flang/test/Lower/nested-where.f90 @@ -313,7 +313,7 @@ program nested_where ! CHECK: fir.call @_FortranARaggedArrayDeallocate(%[[VAL_278]]) {{.*}}: (!fir.llvm_ptr) -> () ! CHECK: %[[VAL_280:.*]] = fir.convert %[[VAL_4]] : (!fir.ref>, !fir.heap>>>) -> !fir.llvm_ptr ! CHECK: fir.call @_FortranARaggedArrayDeallocate(%[[VAL_280]]) {{.*}}: (!fir.llvm_ptr) -> () - + integer :: a(3) = 0 logical :: mask1(3) = (/ .true.,.false.,.true. /) logical :: mask2(3) = (/ .true.,.true.,.false. /) diff --git a/flang/test/Lower/nullify-polymorphic.f90 b/flang/test/Lower/nullify-polymorphic.f90 index 58eaa11f29f64..9a6a2795d3057 100644 --- a/flang/test/Lower/nullify-polymorphic.f90 +++ b/flang/test/Lower/nullify-polymorphic.f90 @@ -13,7 +13,7 @@ module poly contains procedure, nopass :: proc1 => proc1_p2 end type - + contains subroutine proc1_p1() @@ -23,7 +23,7 @@ subroutine proc1_p1() subroutine proc1_p2() print*, 'call proc1_p2' end subroutine - + subroutine test_nullify() class(p1), pointer :: c @@ -31,7 +31,7 @@ subroutine test_nullify() call c%proc1() nullify(c) ! c dynamic type must be reset to p1 - + call c%proc1() end subroutine end module @@ -45,7 +45,7 @@ program test ! CHECK: %[[C_DESC:.*]] = fir.alloca !fir.class>> {bindc_name = "c", uniq_name = "_QMpolyFtest_nullifyEc"} ! CHECK: %[[C_DESC_DECL:.*]]:2 = hlfir.declare %[[C_DESC]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QMpolyFtest_nullifyEc"} : (!fir.ref>>>) -> (!fir.ref>>>, !fir.ref>>>) ! CHECK: %{{.*}} = fir.call @_FortranAPointerAllocate(%{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}) {{.*}}: (!fir.ref>, i1, !fir.box, !fir.ref, i32) -> i32 -! CHECK: %[[DECLARED_TYPE_DESC:.*]] = fir.type_desc !fir.type<_QMpolyTp1{a:i32,b:i32}> +! CHECK: %[[DECLARED_TYPE_DESC:.*]] = fir.type_desc !fir.type<_QMpolyTp1{a:i32,b:i32}> ! CHECK: %[[C_DESC_CAST:.*]] = fir.convert %[[C_DESC_DECL]]#0 : (!fir.ref>>>) -> !fir.ref> ! CHECK: %[[TYPE_DESC_CAST:.*]] = fir.convert %[[DECLARED_TYPE_DESC]] : (!fir.tdesc>) -> !fir.ref ! CHECK: %[[RANK:.*]] = arith.constant 0 : i32 diff --git a/flang/test/Lower/pointer-association-polymorphic.f90 b/flang/test/Lower/pointer-association-polymorphic.f90 index 7d166e1423cfa..a82eebb1c5958 100644 --- a/flang/test/Lower/pointer-association-polymorphic.f90 +++ b/flang/test/Lower/pointer-association-polymorphic.f90 @@ -143,9 +143,9 @@ subroutine test_pointer() ! CHECK: %[[C4_LOAD:.*]] = fir.load %[[C4_DESC]] : !fir.ref>>>> ! CHECK: %[[C4_REBOX:.*]] = fir.rebox %[[C4_LOAD]](%{{.*}}) : (!fir.class>>>, !fir.shift<1>) -> !fir.class>> -! CHECK: %[[PA_CONV:.*]] = fir.convert %[[PA_DESC]] : (!fir.ref>>>>) -> !fir.ref> -! CHECK: %[[C4_REBOX_CONV:.*]] = fir.convert %[[C4_REBOX]] : (!fir.class>>) -> !fir.box -! CHECK: fir.call @_FortranAPointerAssociate(%[[PA_CONV]], %[[C4_REBOX_CONV]]) {{.*}} : (!fir.ref>, !fir.box) -> () +! CHECK: %[[PA_CONV:.*]] = fir.convert %[[PA_DESC]] : (!fir.ref>>>>) -> !fir.ref> +! CHECK: %[[C4_REBOX_CONV:.*]] = fir.convert %[[C4_REBOX]] : (!fir.class>>) -> !fir.box +! CHECK: fir.call @_FortranAPointerAssociate(%[[PA_CONV]], %[[C4_REBOX_CONV]]) {{.*}} : (!fir.ref>, !fir.box) -> () ! CHECK-LABEL: fir.do_loop ! CHECK: %[[PA_LOAD:.*]] = fir.load %[[PA_DESC]] : !fir.ref>>>> ! CHECK: %[[PA_COORD:.*]] = fir.coordinate_of %[[PA_LOAD]], %{{.*}} : (!fir.class>>>, i64) -> !fir.ref> @@ -165,8 +165,8 @@ subroutine test_pointer() ! CHECK: %[[SLICE:.*]] = fir.slice %[[C2_INDEX]], %[[C4_INDEX]], %[[C1_INDEX]] : (index, index, index) -> !fir.slice<1> ! CHECK: %[[SLICE_REBOX:.*]] = fir.rebox %[[C4_LOAD]](%[[SHIFT]]) [%[[SLICE]]] : (!fir.class>>>, !fir.shift<1>, !fir.slice<1>) -> !fir.class>> ! CHECK: %[[PA_CONV:.*]] = fir.convert %[[PA_DESC]] : (!fir.ref>>>>) -> !fir.ref> -! CHECK: %[[SLICE_REBOX_CONV:.*]] = fir.convert %[[SLICE_REBOX]] : (!fir.class>>) -> !fir.box -! CHECK: fir.call @_FortranAPointerAssociate(%[[PA_CONV]], %[[SLICE_REBOX_CONV]]) {{.*}} : (!fir.ref>, !fir.box) -> () +! CHECK: %[[SLICE_REBOX_CONV:.*]] = fir.convert %[[SLICE_REBOX]] : (!fir.class>>) -> !fir.box +! CHECK: fir.call @_FortranAPointerAssociate(%[[PA_CONV]], %[[SLICE_REBOX_CONV]]) {{.*}} : (!fir.ref>, !fir.box) -> () ! CHECK-LABEL: fir.do_loop ! CHECK: %[[PA_LOAD:.*]] = fir.load %[[PA_DESC]] : !fir.ref>>>> ! CHECK: %[[PA_COORD:.*]] = fir.coordinate_of %[[PA_LOAD]], %{{.*}} : (!fir.class>>>, i64) -> !fir.ref> diff --git a/flang/test/Lower/pointer-disassociate.f90 b/flang/test/Lower/pointer-disassociate.f90 index fb70fd7795b2e..6dfabddb83291 100644 --- a/flang/test/Lower/pointer-disassociate.f90 +++ b/flang/test/Lower/pointer-disassociate.f90 @@ -113,9 +113,9 @@ subroutine test_polymorphic_null(p) end subroutine ! CHECK-LABEL: func.func @_QPtest_polymorphic_null( ! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref>>>> -! CHECK: %[[VAL_1:.*]] = fir.type_desc !fir.type<_QFtest_polymorphic_nullTt> +! CHECK: %[[VAL_1:.*]] = fir.type_desc !fir.type<_QFtest_polymorphic_nullTt> ! CHECK: %[[VAL_2:.*]] = fir.convert %[[VAL_0]] : (!fir.ref>>>>) -> !fir.ref> -! CHECK: %[[VAL_3:.*]] = fir.convert %[[VAL_1]] : (!fir.tdesc>) -> !fir.ref +! CHECK: %[[VAL_3:.*]] = fir.convert %[[VAL_1]] : (!fir.tdesc>) -> !fir.ref ! CHECK: %[[VAL_4:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_5:.*]] = arith.constant 0 : i32 ! CHECK: fir.call @_FortranAPointerNullifyDerived(%[[VAL_2]], %[[VAL_3]], %[[VAL_4]], %[[VAL_5]]) {{.*}}: (!fir.ref>, !fir.ref, i32, i32) -> () diff --git a/flang/test/Lower/polymorphic-temp.f90 b/flang/test/Lower/polymorphic-temp.f90 index ac3cbdba6646d..391ec2b48a1be 100644 --- a/flang/test/Lower/polymorphic-temp.f90 +++ b/flang/test/Lower/polymorphic-temp.f90 @@ -24,7 +24,7 @@ subroutine test_temp_from_intrinsic_spread() call pass_unlimited_poly_1d(spread(p, dim=1, ncopies=2)) call pass_unlimited_poly_1d(spread(pa(1), dim=1, ncopies=2)) - + end subroutine ! CHECK-LABEL: func.func @_QMpoly_tmpPtest_temp_from_intrinsic_spread() { @@ -220,7 +220,7 @@ subroutine test_merge_intrinsic2(a, b, i) ! CHECK: %[[LOAD_I:.*]] = fir.load %[[I]] : !fir.ref ! CHECK: %[[C1:.*]] = arith.constant 1 : i32 ! CHECK: %[[CMPI:.*]] = arith.cmpi eq, %[[LOAD_I]], %[[C1]] : i32 -! CHECK: %[[A_REBOX:.*]] = fir.rebox %[[LOAD_A]] : (!fir.class>>) -> !fir.box>> +! CHECK: %[[A_REBOX:.*]] = fir.rebox %[[LOAD_A]] : (!fir.class>>) -> !fir.box>> ! CHECK: %{{.*}} = arith.select %[[CMPI]], %[[A_REBOX]], %[[LOAD_B]] : !fir.box>> subroutine check_unlimited_poly(a) diff --git a/flang/test/Lower/polymorphic-types.f90 b/flang/test/Lower/polymorphic-types.f90 index a06e0a29b6ae8..93d08a4aee380 100644 --- a/flang/test/Lower/polymorphic-types.f90 +++ b/flang/test/Lower/polymorphic-types.f90 @@ -1,6 +1,6 @@ ! RUN: bbc -emit-fir -hlfir=false %s -o - | FileCheck %s -! Tests the different possible type involving polymorphic entities. +! Tests the different possible type involving polymorphic entities. module polymorphic_types type p1 diff --git a/flang/test/Lower/polymorphic.f90 b/flang/test/Lower/polymorphic.f90 index bc4eed54282df..689e2233dcf10 100644 --- a/flang/test/Lower/polymorphic.f90 +++ b/flang/test/Lower/polymorphic.f90 @@ -126,7 +126,7 @@ subroutine check() ! CHECK: %[[CLASS1:.*]] = fir.embox %[[DT1]] : (!fir.ref>) -> !fir.class> ! CHECK: fir.call @_QMpolymorphic_testPprint(%[[CLASS1]]) {{.*}}: (!fir.class>) -> () ! CHECK: %[[BOX2:.*]] = fir.embox %[[DT2]] : (!fir.ref>) -> !fir.class> -! CHECK: %[[CLASS2:.*]] = fir.convert %[[BOX2]] : (!fir.class>) -> !fir.class> +! CHECK: %[[CLASS2:.*]] = fir.convert %[[BOX2]] : (!fir.class>) -> !fir.class> ! CHECK: fir.call @_QMpolymorphic_testPprint(%[[CLASS2]]) {{.*}}: (!fir.class>) -> () subroutine test_allocate_unlimited_polymorphic_non_derived() @@ -316,7 +316,7 @@ subroutine nullify_pointer_array(a) ! CHECK-LABEL: func.func @_QMpolymorphic_testPnullify_pointer_array( ! CHECK-SAME: %[[ARG0:.*]]: !fir.ref>>>}>> {fir.bindc_name = "a"}) { ! CHECK: %[[COORD_P:.*]] = fir.coordinate_of %[[ARG0]], p : (!fir.ref>>>}>>) -> !fir.ref>>>}>>>>> -! CHECK: %[[TYPE_DESC:.*]] = fir.type_desc !fir.type<_QMpolymorphic_testTp3{p:!fir.class>>>}> +! CHECK: %[[TYPE_DESC:.*]] = fir.type_desc !fir.type<_QMpolymorphic_testTp3{p:!fir.class>>>}> ! CHECK: %[[CONV_P:.*]] = fir.convert %[[COORD_P]] : (!fir.ref>>>}>>>>>) -> !fir.ref> ! CHECK: %[[CONV_TDESC:.*]] = fir.convert %[[TYPE_DESC]] : (!fir.tdesc>>>}>>) -> !fir.ref ! CHECK: %[[C1:.*]] = arith.constant 1 : i32 @@ -517,7 +517,7 @@ subroutine test_elemental_assign() subroutine host_assoc(this) class(p1) :: this - + call internal contains subroutine internal @@ -779,7 +779,7 @@ function unlimited_polymorphic_alloc_array_ret() subroutine test_unlimited_polymorphic_alloc_array_ret() select type (a => unlimited_polymorphic_alloc_array_ret()) type is (real) - print*, 'type is real' + print*, 'type is real' end select end subroutine @@ -795,7 +795,7 @@ subroutine test_unlimited_polymorphic_intentout(a) ! CHECK-LABEL: func.func @_QMpolymorphic_testPtest_unlimited_polymorphic_intentout( ! CHECK-SAME: %[[ARG0:.*]]: !fir.class {fir.bindc_name = "a"}) { ! CHECK: %[[BOX_NONE:.*]] = fir.convert %[[ARG0]] : (!fir.class) -> !fir.box -! CHECK: fir.call @_FortranADestroy(%[[BOX_NONE]]) {{.*}} : (!fir.box) -> () +! CHECK: fir.call @_FortranADestroy(%[[BOX_NONE]]) {{.*}} : (!fir.box) -> () ! CHECK: %[[BOX_NONE:.*]] = fir.convert %[[ARG0]] : (!fir.class) -> !fir.box ! CHECK: fir.call @_FortranAInitialize(%[[BOX_NONE]], %{{.*}}, %{{.*}}) {{.*}} : (!fir.box, !fir.ref, i32) -> () @@ -806,7 +806,7 @@ subroutine test_polymorphic_intentout(a) ! CHECK-LABEL: func.func @_QMpolymorphic_testPtest_polymorphic_intentout( ! CHECK-SAME: %[[ARG0:.*]]: !fir.class> {fir.bindc_name = "a"}) { ! CHECK: %[[BOX_NONE:.*]] = fir.convert %[[ARG0]] : (!fir.class>) -> !fir.box -! CHECK: fir.call @_FortranADestroy(%[[BOX_NONE]]) {{.*}} : (!fir.box) -> () +! CHECK: fir.call @_FortranADestroy(%[[BOX_NONE]]) {{.*}} : (!fir.box) -> () ! CHECK: %[[BOX_NONE:.*]] = fir.convert %[[ARG0]] : (!fir.class>) -> !fir.box ! CHECK: fir.call @_FortranAInitialize(%[[BOX_NONE]], %{{.*}}, %{{.*}}) {{.*}} : (!fir.box, !fir.ref, i32) -> () diff --git a/flang/test/Lower/pre-fir-tree02.f90 b/flang/test/Lower/pre-fir-tree02.f90 index 65c33e9b364fe..d61dc801eea60 100644 --- a/flang/test/Lower/pre-fir-tree02.f90 +++ b/flang/test/Lower/pre-fir-tree02.f90 @@ -148,7 +148,7 @@ subroutine incr(i) module test !! When derived type processing is implemented, remove all instances of: !! - !![disable] - !! - COM: + !! - COM: !![disable]type :: a_type !![disable] integer :: x !![disable]end type diff --git a/flang/test/Lower/procedure-declarations.f90 b/flang/test/Lower/procedure-declarations.f90 index b0dee600f563d..95c8607a97e59 100644 --- a/flang/test/Lower/procedure-declarations.f90 +++ b/flang/test/Lower/procedure-declarations.f90 @@ -4,7 +4,7 @@ ! (passing a procedure and calling it), with and without definitions. ! Check that the definition type prevail if available and that casts are inserted to ! accommodate for the signature mismatch in the different location due to implicit -! typing rules and Fortran loose interface compatibility rule history. +! typing rules and Fortran loose interface compatibility rule history. ! Note: all the cases where their is a definition are exactly the same, @@ -25,7 +25,7 @@ subroutine call_foo(i) ! %[[argconvert:*]] = fir.convert %arg0 : ! fir.call @_QPfoo(%[[argconvert]]) {{.*}}: (!fir.ref>) -> () call foo(i) -end subroutine +end subroutine ! CHECK-LABEL: func @_QPfoo( ! CHECK-SAME: %{{.*}}: !fir.ref>{{.*}}) { subroutine foo(i) @@ -41,7 +41,7 @@ subroutine call_foo2(i) ! %[[argconvert:*]] = fir.convert %arg0 : ! fir.call @_QPfoo2(%[[argconvert]]) {{.*}}: (!fir.ref>) -> () call foo2(i) -end subroutine +end subroutine ! CHECK-LABEL: func @_QPpass_foo2() { subroutine pass_foo2() external :: foo2 @@ -64,7 +64,7 @@ subroutine call_foo3(i) ! %[[argconvert:*]] = fir.convert %arg0 : ! fir.call @_QPfoo3(%[[argconvert]]) {{.*}}: (!fir.ref>) -> () call foo3(i) -end subroutine +end subroutine ! CHECK-LABEL: func @_QPfoo3( ! CHECK-SAME: %{{.*}}: !fir.ref>{{.*}}) { subroutine foo3(i) @@ -93,7 +93,7 @@ subroutine call_foo4(i) ! %[[argconvert:*]] = fir.convert %arg0 : ! fir.call @_QPfoo4(%[[argconvert]]) {{.*}}: (!fir.ref>) -> () call foo4(i) -end subroutine +end subroutine ! CHECK-LABEL: func @_QPpass_foo4() { subroutine pass_foo4() external :: foo4 @@ -123,7 +123,7 @@ subroutine call_foo5(i) ! %[[argconvert:*]] = fir.convert %arg0 : ! fir.call @_QPfoo5(%[[argconvert]]) {{.*}}: (!fir.ref>) -> () call foo5(i) -end subroutine +end subroutine ! Test when there is no definition (declaration at the end of the mlir module) @@ -136,7 +136,7 @@ subroutine call_foo6(i) integer :: i(10) ! CHECK-NOT: convert call foo6(i) -end subroutine +end subroutine ! CHECK-LABEL: func @_QPpass_foo6() { subroutine pass_foo6() external :: foo6 @@ -160,7 +160,7 @@ function call_foo7(i) ! CHECK: %[[funccast:.*]] = fir.convert %[[f]] : (() -> ()) -> ((!fir.ref>) -> f32) ! CHECK: fir.call %[[funccast]](%arg0) {{.*}}: (!fir.ref>) -> f32 call_foo7 = foo7(i) -end function +end function ! call, call with different type @@ -170,14 +170,14 @@ subroutine call_foo8(i) integer :: i(10) ! CHECK-NOT: convert call foo8(i) -end subroutine +end subroutine ! CHECK-LABEL: func @_QPcall_foo8_2( ! CHECK-SAME: %{{.*}}: !fir.ref>{{.*}}) { subroutine call_foo8_2(i) integer :: i(2, 5) ! %[[argconvert:*]] = fir.convert %arg0 : call foo8(i) -end subroutine +end subroutine ! Test that target attribute is lowered in declaration of functions that are ! not defined in this file. diff --git a/flang/test/Lower/read-write-buffer.f90 b/flang/test/Lower/read-write-buffer.f90 index cfa25c8a0ad6e..ff4fabca2869c 100644 --- a/flang/test/Lower/read-write-buffer.f90 +++ b/flang/test/Lower/read-write-buffer.f90 @@ -15,8 +15,8 @@ subroutine test_array_format ! CHECK: %[[fmtArg:.*]] = fir.zero_bits !fir.ref ! CHECK: %[[fmtLenArg:.*]] = fir.zero_bits i64 ! CHECK: %[[fmtDesc:.*]] = fir.convert %[[fmtBox]] : (!fir.box>>) -> !fir.box - ! CHECK: fir.call @_FortranAioBeginExternalFormattedOutput(%[[fmtArg]], %[[fmtLenArg]], %[[fmtDesc]], {{.*}}) - write(*, array) + ! CHECK: fir.call @_FortranAioBeginExternalFormattedOutput(%[[fmtArg]], %[[fmtLenArg]], %[[fmtDesc]], {{.*}}) + write(*, array) end subroutine ! A test to check the buffer and it's length. diff --git a/flang/test/Lower/select-type.f90 b/flang/test/Lower/select-type.f90 index e2ca87ad447c9..246b653390b59 100644 --- a/flang/test/Lower/select-type.f90 +++ b/flang/test/Lower/select-type.f90 @@ -38,7 +38,7 @@ function negate(this) allocate(negate, source=this) negate%a = -this%a end function - + subroutine select_type1(a) class(p1), intent(in) :: a @@ -275,7 +275,7 @@ subroutine select_type5(a) ! CHECK-LABEL: func.func @_QMselect_type_lower_testPselect_type5( ! CHECK-SAME: %[[ARG0:.*]]: !fir.class {fir.bindc_name = "a"}) ! CHECK: fir.select_type %[[ARG0]] : !fir.class -! CHECK-SAME: [#fir.type_is, ^[[I8_BLK:.*]], #fir.type_is, ^[[I32_BLK:.*]], #fir.type_is, ^[[F32_BLK:.*]], #fir.type_is>, ^[[LOG_BLK:.*]], #fir.type_is>, ^[[CHAR_BLK:.*]], unit, ^[[DEFAULT:.*]]] +! CHECK-SAME: [#fir.type_is, ^[[I8_BLK:.*]], #fir.type_is, ^[[I32_BLK:.*]], #fir.type_is, ^[[F32_BLK:.*]], #fir.type_is>, ^[[LOG_BLK:.*]], #fir.type_is>, ^[[CHAR_BLK:.*]], unit, ^[[DEFAULT:.*]]] ! CHECK: ^[[I8_BLK]] ! CHECK: ^[[I32_BLK]] ! CHECK: ^[[F32_BLK]] @@ -467,7 +467,7 @@ subroutine select_type8(a) ! CHECK: %[[SELECTOR:.*]] = fir.rebox %[[ARG0]] : (!fir.class>) -> !fir.class> ! CHECK: fir.select_type %[[SELECTOR]] : !fir.class> [#fir.type_is, ^{{.*}}, #fir.type_is, ^{{.*}}, #fir.type_is>, ^bb{{.*}}, unit, ^{{.*}}] ! CHECK: ^bb{{.*}}: -! CHECK: %[[BOX:.*]] = fir.convert %[[SELECTOR]] : (!fir.class>) -> !fir.box> +! CHECK: %[[BOX:.*]] = fir.convert %[[SELECTOR]] : (!fir.class>) -> !fir.box> ! CHECK: %[[C0:.*]] = arith.constant 0 : index ! CHECK: %[[SELECTOR_DIMS:.*]]:3 = fir.box_dims %[[BOX]], %[[C0]] : (!fir.box>, index) -> (index, index, index) ! CHECK: %[[ARRAY_LOAD:.*]] = fir.array_load %[[BOX]] : (!fir.box>) -> !fir.array @@ -482,7 +482,7 @@ subroutine select_type8(a) ! CHECK: fir.array_merge_store %[[ARRAY_LOAD]], %[[LOOP_RES]] to %[[BOX]] : !fir.array, !fir.array, !fir.box> ! CHECK: cf.br ^{{.*}} ! CHECK: ^bb{{.*}}: -! CHECK: %[[BOX:.*]] = fir.convert %[[SELECTOR]] : (!fir.class>) -> !fir.box> +! CHECK: %[[BOX:.*]] = fir.convert %[[SELECTOR]] : (!fir.class>) -> !fir.box> ! CHECK: %[[C0:.*]] = arith.constant 0 : index ! CHECK: %[[SELECTOR_DIMS:.*]]:3 = fir.box_dims %[[BOX]], %[[C0]] : (!fir.box>, index) -> (index, index, index) ! CHECK: %[[ARRAY_LOAD:.*]] = fir.array_load %[[BOX]] : (!fir.box>) -> !fir.array @@ -497,7 +497,7 @@ subroutine select_type8(a) ! CHECK: fir.array_merge_store %[[ARRAY_LOAD]], %[[LOOP_RES]] to %[[BOX]] : !fir.array, !fir.array, !fir.box> ! CHECK: cf.br ^{{.*}} ! CHECK: ^bb{{.*}}: -! CHECK: %[[BOX:.*]] = fir.convert %{{[0-9]+}} : (!fir.class>) -> !fir.box>> +! CHECK: %[[BOX:.*]] = fir.convert %{{[0-9]+}} : (!fir.class>) -> !fir.box>> ! CHECK: cf.br ^bb{{.*}} ! CHECK: ^bb{{.*}}: ! CHECK: %[[EXACT_BOX:.*]] = fir.convert %[[SELECTOR]] : (!fir.class>) -> !fir.box>> @@ -517,7 +517,7 @@ subroutine select_type8(a) ! CHECK: %[[BOX_DIMS:.*]]:3 = fir.box_dims %[[EXACT_BOX]], %[[C0]] : (!fir.box>>, index) -> (index, index, index) ! CHECK: %[[C1:.*]] = arith.constant 1 : index ! CHECK: %[[SLICE:.*]] = fir.slice %[[C1]], %[[BOX_DIMS]]#1, %[[C1]] path %[[FIELD_B]] : (index, index, index, !fir.field) -> !fir.slice<1> -! CHECK: %[[ARRAY_LOAD:.*]] = fir.array_load %[[EXACT_BOX]] [%[[SLICE]]] : (!fir.box>>, !fir.slice<1>) -> !fir.array +! CHECK: %[[ARRAY_LOAD:.*]] = fir.array_load %[[EXACT_BOX]] [%[[SLICE]]] : (!fir.box>>, !fir.slice<1>) -> !fir.array ! CHECK: %[[DO_RES:.*]] = fir.do_loop %[[IND:.*]] = %{{.*}} to %{{.*}} step %c{{.*}} unordered iter_args(%[[ARG:.*]] = %[[ARRAY_LOAD]]) -> (!fir.array) { ! CHECK: %[[ARR_UP:.*]] = fir.array_update %[[ARG]], %{{.*}}, %[[IND]] : (!fir.array, i32, index) -> !fir.array ! CHECK: fir.result %[[ARR_UP]] : !fir.array @@ -599,7 +599,7 @@ subroutine select_type9(a) ! CHECK: %[[BOX_DIMS:.*]]:3 = fir.box_dims %[[EXACT_BOX]], %[[C0]] : (!fir.box>>, index) -> (index, index, index) ! CHECK: %[[C1:.*]] = arith.constant 1 : index ! CHECK: %[[SLICE:.*]] = fir.slice %[[C1]], %[[BOX_DIMS]]#1, %[[C1]] path %[[FIELD_B]] : (index, index, index, !fir.field) -> !fir.slice<1> -! CHECK: %[[ARRAY_LOAD:.*]] = fir.array_load %[[EXACT_BOX]] [%[[SLICE]]] : (!fir.box>>, !fir.slice<1>) -> !fir.array +! CHECK: %[[ARRAY_LOAD:.*]] = fir.array_load %[[EXACT_BOX]] [%[[SLICE]]] : (!fir.box>>, !fir.slice<1>) -> !fir.array ! CHECK: %[[DO_RES:.*]] = fir.do_loop %[[IND:.*]] = %{{.*}} to %{{.*}} step %c{{.*}} unordered iter_args(%[[ARG:.*]] = %[[ARRAY_LOAD]]) -> (!fir.array) { ! CHECK: %[[ARR_UP:.*]] = fir.array_update %[[ARG]], %{{.*}}, %[[IND]] : (!fir.array, i32, index) -> !fir.array ! CHECK: fir.result %[[ARR_UP]] : !fir.array @@ -607,7 +607,7 @@ subroutine select_type9(a) ! CHECK: fir.array_merge_store %[[ARRAY_LOAD]], %[[DO_RES]] to %[[EXACT_BOX]][%[[SLICE]]] : !fir.array, !fir.array, !fir.box>>, !fir.slice<1> ! CHECK: cf.br ^bb{{.*}} ! CHECK: ^bb{{.*}}: -! CHECK: %[[EXACT_BOX:.*]] = fir.convert %[[SELECTOR]] : (!fir.class>>) -> !fir.box>> +! CHECK: %[[EXACT_BOX:.*]] = fir.convert %[[SELECTOR]] : (!fir.class>>) -> !fir.box>> ! CHECK: %[[FIELD_A:.*]] = fir.field_index a, !fir.type<_QMselect_type_lower_testTp2{a:i32,b:i32,c:i32}> ! CHECK: %[[C0:.*]] = arith.constant 0 : index ! CHECK: %[[BOX_DIMS:.*]]:3 = fir.box_dims %[[EXACT_BOX]], %[[C0]] : (!fir.box>>, index) -> (index, index, index) diff --git a/flang/test/Lower/statement-function.f90 b/flang/test/Lower/statement-function.f90 index fe07649e669af..9dd26d4f58273 100644 --- a/flang/test/Lower/statement-function.f90 +++ b/flang/test/Lower/statement-function.f90 @@ -21,7 +21,7 @@ real function test_stmt_0(x) ! Check this is not lowered as a simple macro: e.g. argument is only ! evaluated once even if it appears in several placed inside the -! statement function expression +! statement function expression ! CHECK-LABEL: func @_QPtest_stmt_only_eval_arg_once() -> f32 real(4) function test_stmt_only_eval_arg_once() real(4) :: only_once, x1 diff --git a/flang/test/Lower/variable.f90 b/flang/test/Lower/variable.f90 index 76d4a26838bf7..52cdb96d89c63 100644 --- a/flang/test/Lower/variable.f90 +++ b/flang/test/Lower/variable.f90 @@ -4,7 +4,7 @@ subroutine s ! CHECK-DAG: fir.alloca !fir.box> {{{.*}}uniq_name = "{{.*}}Eally"} integer, allocatable :: ally - ! CHECK-DAG: fir.alloca !fir.box> {{{.*}}uniq_name = "{{.*}}Epointy"} + ! CHECK-DAG: fir.alloca !fir.box> {{{.*}}uniq_name = "{{.*}}Epointy"} integer, pointer :: pointy ! CHECK-DAG: fir.alloca i32 {{{.*}}fir.target{{.*}}uniq_name = "{{.*}}Ebullseye"} integer, target :: bullseye diff --git a/flang/test/Lower/volatile-allocatable.f90 b/flang/test/Lower/volatile-allocatable.f90 index c33d368c5858f..3147698114115 100644 --- a/flang/test/Lower/volatile-allocatable.f90 +++ b/flang/test/Lower/volatile-allocatable.f90 @@ -42,7 +42,7 @@ subroutine test_scalar_volatile() ! Deferred-length characters allocate(character(20) :: c1) c1 = "volatile character" - + ! Allocation with components allocate(v3) deallocate(v1, v2, v3, c1) @@ -53,24 +53,24 @@ subroutine test_volatile_asynchronous() use derived_types class(base_type), allocatable, volatile, asynchronous :: v1(:) integer, allocatable, volatile, asynchronous :: i1(:) - + allocate(v1(4)) allocate(i1(4), source=[1, 2, 3, 4]) - + deallocate(v1, i1) end subroutine subroutine test_select_base_type_volatile() use derived_types class(base_type), allocatable, volatile :: v(:) - + allocate(v(2)) - + select type(v) class is (base_type) v(1)%i = 100 end select - + deallocate(v) end subroutine @@ -79,12 +79,12 @@ subroutine test_mold_allocation() use derived_types type(comp_type) :: template type(comp_type), allocatable, volatile :: v(:) - + template%str = "mold test" template%arr = [5, 6] - + allocate(v(3), mold=template) - + deallocate(v) end subroutine @@ -93,28 +93,28 @@ subroutine test_unlimited_polymorphic() use derived_types class(*), allocatable, volatile :: up class(*), allocatable, volatile :: upa(:) - + ! Scalar allocation allocate(integer :: up) select type(up) type is (integer) up = 123 end select - + ! Array allocation with source allocate(character(10) :: up) select type(up) type is (character(*)) up = "class(*)" end select - + ! Array allocation allocate(real :: upa(3)) select type(upa) type is (real) upa = [1.1, 2.2, 3.3] end select - + deallocate(up, upa) end subroutine diff --git a/flang/test/Lower/volatile-openmp1.f90 b/flang/test/Lower/volatile-openmp1.f90 index 07d81a1aeb240..74ab3858c8958 100644 --- a/flang/test/Lower/volatile-openmp1.f90 +++ b/flang/test/Lower/volatile-openmp1.f90 @@ -5,7 +5,7 @@ program main integer::n,i a=0 n=1000 -!$omp parallel +!$omp parallel !$omp do reduction(+:a) do i=1,n a=a+1 From 4650f8521d85a4dea310b47bd7edce9e0b73ecf0 Mon Sep 17 00:00:00 2001 From: Benjamin Kramer Date: Mon, 24 Nov 2025 23:03:24 +0100 Subject: [PATCH 22/50] [MemRef] Remove memref.dim OffsetSizeAndStrideOpInterface folding (#169327) OffsetSizeAndStrideOpInterface does not specify whether it's operating on the input or output shape and in fact different ops implement this in different ways, which is also why SubviewOp is special cased here. This "marked as dynamic but not really dynamic" folding is better handled by shape inference, so just remove the bad fold. --- mlir/lib/Dialect/MemRef/IR/MemRefOps.cpp | 7 ------- mlir/test/Dialect/MemRef/canonicalize.mlir | 13 ------------- 2 files changed, 20 deletions(-) diff --git a/mlir/lib/Dialect/MemRef/IR/MemRefOps.cpp b/mlir/lib/Dialect/MemRef/IR/MemRefOps.cpp index 1c21a2f270da6..1035d7cb46e6e 100644 --- a/mlir/lib/Dialect/MemRef/IR/MemRefOps.cpp +++ b/mlir/lib/Dialect/MemRef/IR/MemRefOps.cpp @@ -1074,13 +1074,6 @@ OpFoldResult DimOp::fold(FoldAdaptor adaptor) { return subview.getDynamicSize(sourceIndex); } - if (auto sizeInterface = - dyn_cast_or_null(definingOp)) { - assert(sizeInterface.isDynamicSize(unsignedIndex) && - "Expected dynamic subview size"); - return sizeInterface.getDynamicSize(unsignedIndex); - } - // dim(memrefcast) -> dim if (succeeded(foldMemRefCast(*this))) return getResult(); diff --git a/mlir/test/Dialect/MemRef/canonicalize.mlir b/mlir/test/Dialect/MemRef/canonicalize.mlir index 313090272ef90..e02717a2f5689 100644 --- a/mlir/test/Dialect/MemRef/canonicalize.mlir +++ b/mlir/test/Dialect/MemRef/canonicalize.mlir @@ -208,19 +208,6 @@ func.func @subview_negative_stride2(%arg0 : memref<7xf32>) -> memref -// CHECK-SAME: %[[SIZE:.[a-z0-9A-Z_]+]]: index -// CHECK: return %[[SIZE]] : index -func.func @dim_of_sized_view(%arg : memref, %size: index) -> index { - %c0 = arith.constant 0 : index - %0 = memref.reinterpret_cast %arg to offset: [0], sizes: [%size], strides: [1] : memref to memref - %1 = memref.dim %0, %c0 : memref - return %1 : index -} - -// ----- - // CHECK-LABEL: func @no_fold_subview_negative_size // CHECK: %[[SUBVIEW:.+]] = memref.subview // CHECK: return %[[SUBVIEW]] From 590bb3e8e63af0fb46eadf510761bd00e264c018 Mon Sep 17 00:00:00 2001 From: Eli Friedman Date: Mon, 24 Nov 2025 14:08:50 -0800 Subject: [PATCH 23/50] [AArch64] Improve host feature detection. (#160410) SVE depends on a combination of host support and operating system support. Sometimes those don't line up with detected host CPU name; make sure SVE is disabled when it isn't available. Implement this for both Windows and Linux. (We don't have a codepath for other operating systems. If someone wants to implement this, it should be possible to adapt fmv code from compiler-rt.) While I'm here, also add support for detecting other Windows CPU features. For Windows, declare constants ourselves so the code builds on older SDKs; we also do this in compiler-rt. --- llvm/lib/TargetParser/Host.cpp | 65 ++++++++++++++++++++++++++++++++-- 1 file changed, 63 insertions(+), 2 deletions(-) diff --git a/llvm/lib/TargetParser/Host.cpp b/llvm/lib/TargetParser/Host.cpp index 3f9f69549f2db..cb793d60a286f 100644 --- a/llvm/lib/TargetParser/Host.cpp +++ b/llvm/lib/TargetParser/Host.cpp @@ -2277,20 +2277,81 @@ StringMap sys::getHostCPUFeatures() { uint32_t Sha2 = CAP_SHA1 | CAP_SHA2; Features["aes"] = (crypto & Aes) == Aes; Features["sha2"] = (crypto & Sha2) == Sha2; + + // Even if an underlying core supports SVE, it might not be available if + // it's disabled by the OS, or some other layer. Disable SVE if we don't + // detect support at runtime. + if (!Features.contains("sve")) + Features["sve"] = false; #endif return Features; } #elif defined(_WIN32) && (defined(__aarch64__) || defined(_M_ARM64) || \ defined(__arm64ec__) || defined(_M_ARM64EC)) +#ifndef PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE +#define PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE 43 +#endif +#ifndef PF_ARM_V83_JSCVT_INSTRUCTIONS_AVAILABLE +#define PF_ARM_V83_JSCVT_INSTRUCTIONS_AVAILABLE 44 +#endif +#ifndef PF_ARM_V83_LRCPC_INSTRUCTIONS_AVAILABLE +#define PF_ARM_V83_LRCPC_INSTRUCTIONS_AVAILABLE 45 +#endif +#ifndef PF_ARM_SVE_INSTRUCTIONS_AVAILABLE +#define PF_ARM_SVE_INSTRUCTIONS_AVAILABLE 46 +#endif +#ifndef PF_ARM_SVE2_INSTRUCTIONS_AVAILABLE +#define PF_ARM_SVE2_INSTRUCTIONS_AVAILABLE 47 +#endif +#ifndef PF_ARM_SVE_PMULL128_INSTRUCTIONS_AVAILABLE +#define PF_ARM_SVE_PMULL128_INSTRUCTIONS_AVAILABLE 50 +#endif +#ifndef PF_ARM_SVE_SHA3_INSTRUCTIONS_AVAILABLE +#define PF_ARM_SVE_SHA3_INSTRUCTIONS_AVAILABLE 55 +#endif +#ifndef PF_ARM_SVE_SM4_INSTRUCTIONS_AVAILABLE +#define PF_ARM_SVE_SM4_INSTRUCTIONS_AVAILABLE 56 +#endif +#ifndef PF_ARM_SVE_I8MM_INSTRUCTIONS_AVAILABLE +#define PF_ARM_SVE_I8MM_INSTRUCTIONS_AVAILABLE 57 +#endif +#ifndef PF_ARM_SVE_F32MM_INSTRUCTIONS_AVAILABLE +#define PF_ARM_SVE_F32MM_INSTRUCTIONS_AVAILABLE 58 +#endif +#ifndef PF_ARM_SVE_F64MM_INSTRUCTIONS_AVAILABLE +#define PF_ARM_SVE_F64MM_INSTRUCTIONS_AVAILABLE 59 +#endif StringMap sys::getHostCPUFeatures() { StringMap Features; // If we're asking the OS at runtime, believe what the OS says - Features["neon"] = - IsProcessorFeaturePresent(PF_ARM_NEON_INSTRUCTIONS_AVAILABLE); Features["crc"] = IsProcessorFeaturePresent(PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE); + Features["lse"] = + IsProcessorFeaturePresent(PF_ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE); + Features["dotprod"] = + IsProcessorFeaturePresent(PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE); + Features["jsconv"] = + IsProcessorFeaturePresent(PF_ARM_V83_JSCVT_INSTRUCTIONS_AVAILABLE); + Features["rcpc"] = + IsProcessorFeaturePresent(PF_ARM_V83_LRCPC_INSTRUCTIONS_AVAILABLE); + Features["sve"] = + IsProcessorFeaturePresent(PF_ARM_SVE_INSTRUCTIONS_AVAILABLE); + Features["sve2"] = + IsProcessorFeaturePresent(PF_ARM_SVE2_INSTRUCTIONS_AVAILABLE); + Features["sve-aes"] = + IsProcessorFeaturePresent(PF_ARM_SVE_PMULL128_INSTRUCTIONS_AVAILABLE); + Features["sve-sha3"] = + IsProcessorFeaturePresent(PF_ARM_SVE_SHA3_INSTRUCTIONS_AVAILABLE); + Features["sve-sm4"] = + IsProcessorFeaturePresent(PF_ARM_SVE_SM4_INSTRUCTIONS_AVAILABLE); + Features["f32mm"] = + IsProcessorFeaturePresent(PF_ARM_SVE_F32MM_INSTRUCTIONS_AVAILABLE); + Features["f64mm"] = + IsProcessorFeaturePresent(PF_ARM_SVE_F64MM_INSTRUCTIONS_AVAILABLE); + Features["i8mm"] = + IsProcessorFeaturePresent(PF_ARM_SVE_I8MM_INSTRUCTIONS_AVAILABLE); // Avoid inferring "crypto" means more than the traditional AES + SHA2 bool TradCrypto = From a50824926c07bc42e3d9a9e39de19cc7c71714a5 Mon Sep 17 00:00:00 2001 From: Florian Mayer Date: Mon, 24 Nov 2025 14:20:36 -0800 Subject: [PATCH 24/50] [UBsan] add -fsanitize-handler-preserve-all-regs flag (#168644) This is currently a no op. This will be supported for the minimal runtime in a follow up. This allows to improve codegen for fsanitize-recover by compiling the handlers with [[clang::preserve_all]]. This makes sure that the caller does not need to spill any registers. We do not expect this function to be called frequently, so this is beneficial for code size. --- clang/include/clang/Basic/CodeGenOptions.def | 2 ++ clang/include/clang/Driver/SanitizerArgs.h | 1 + clang/include/clang/Options/Options.td | 9 +++++++++ clang/lib/Driver/SanitizerArgs.cpp | 7 +++++++ clang/test/Driver/fsanitize.c | 5 +++++ 5 files changed, 24 insertions(+) diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def index 52360b67b306c..76a6463881c6f 100644 --- a/clang/include/clang/Basic/CodeGenOptions.def +++ b/clang/include/clang/Basic/CodeGenOptions.def @@ -270,6 +270,8 @@ CODEGENOPT(SanitizeMemoryUseAfterDtor, 1, 0, Benign) ///< Enable use-after-delet CODEGENOPT(SanitizeCfiCrossDso, 1, 0, Benign) ///< Enable cross-dso support in CFI. CODEGENOPT(SanitizeMinimalRuntime, 1, 0, Benign) ///< Use "_minimal" sanitizer runtime for ///< diagnostics. +CODEGENOPT(SanitizeHandlerPreserveAllRegs, 1, 0, Benign) ///< Use "_preserve" sanitizer runtime for + ///< diagnostics. CODEGENOPT(SanitizeCfiICallGeneralizePointers, 1, 0, Benign) ///< Generalize pointer types in ///< CFI icall function signatures CODEGENOPT(SanitizeCfiICallNormalizeIntegers, 1, 0, Benign) ///< Normalize integer types in diff --git a/clang/include/clang/Driver/SanitizerArgs.h b/clang/include/clang/Driver/SanitizerArgs.h index 08e3c147d0557..84fb66e16bee3 100644 --- a/clang/include/clang/Driver/SanitizerArgs.h +++ b/clang/include/clang/Driver/SanitizerArgs.h @@ -68,6 +68,7 @@ class SanitizerArgs { bool TsanAtomics = true; bool MinimalRuntime = false; bool TysanOutlineInstrumentation = true; + bool HandlerPreserveAllRegs = false; // True if cross-dso CFI support if provided by the system (i.e. Android). bool ImplicitCfiRuntime = false; bool NeedsMemProfRt = false; diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td index 34a6651d2445c..a8fc1c4326cc5 100644 --- a/clang/include/clang/Options/Options.td +++ b/clang/include/clang/Options/Options.td @@ -2666,6 +2666,15 @@ defm sanitize_minimal_runtime : BoolOption<"f", "sanitize-minimal-runtime", PosFlag, NegFlag>, Group; +defm sanitize_handler_preserve_all_regs + : BoolOption< + "f", "sanitize-handler-preserve-all-regs", + CodeGenOpts<"SanitizeHandlerPreserveAllRegs">, DefaultFalse, + PosFlag, + NegFlag>, + Group; def fsanitize_link_runtime : Flag<["-"], "fsanitize-link-runtime">, Group; def fno_sanitize_link_runtime : Flag<["-"], "fno-sanitize-link-runtime">, diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp index 225153587664e..9902cbbf99436 100644 --- a/clang/lib/Driver/SanitizerArgs.cpp +++ b/clang/lib/Driver/SanitizerArgs.cpp @@ -423,6 +423,10 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, MinimalRuntime = Args.hasFlag(options::OPT_fsanitize_minimal_runtime, options::OPT_fno_sanitize_minimal_runtime, MinimalRuntime); + HandlerPreserveAllRegs = + Args.hasFlag(options::OPT_fsanitize_handler_preserve_all_regs, + options::OPT_fno_sanitize_handler_preserve_all_regs, + HandlerPreserveAllRegs); // The object size sanitizer should not be enabled at -O0. Arg *OptLevel = Args.getLastArg(options::OPT_O_Group); @@ -1476,6 +1480,9 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args, if (MinimalRuntime) CmdArgs.push_back("-fsanitize-minimal-runtime"); + if (HandlerPreserveAllRegs) + CmdArgs.push_back("-fsanitize-handler-preserve-all-regs"); + if (AsanFieldPadding) CmdArgs.push_back(Args.MakeArgString("-fsanitize-address-field-padding=" + Twine(AsanFieldPadding))); diff --git a/clang/test/Driver/fsanitize.c b/clang/test/Driver/fsanitize.c index 263301ad4466a..f2a4d8c50ec23 100644 --- a/clang/test/Driver/fsanitize.c +++ b/clang/test/Driver/fsanitize.c @@ -984,6 +984,11 @@ // CHECK-UBSAN-MINIMAL: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute|function),?){18}"}} // CHECK-UBSAN-MINIMAL: "-fsanitize-minimal-runtime" +// RUN: %clang --target=x86_64-linux-gnu -fsanitize=undefined -fsanitize-minimal-runtime -fsanitize-handler-preserve-all-regs %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-UBSAN-MINIMAL-PRESERVE +// CHECK-UBSAN-MINIMAL-PRESERVE: "-fsanitize={{((signed-integer-overflow|integer-divide-by-zero|shift-base|shift-exponent|unreachable|return|vla-bound|alignment|null|pointer-overflow|float-cast-overflow|array-bounds|enum|bool|builtin|returns-nonnull-attribute|nonnull-attribute|function),?){18}"}} +// CHECK-UBSAN-MINIMAL-PRESERVE: "-fsanitize-minimal-runtime" +// CHECK-UBSAN-MINIMAL-PRESERVE: "-fsanitize-handler-preserve-all-regs + // RUN: %clang --target=x86_64-linux-gnu -fsanitize=integer -fsanitize-trap=integer %s -### 2>&1 | FileCheck %s --check-prefix=CHECK-INTSAN-TRAP // CHECK-INTSAN-TRAP: "-fsanitize-trap=integer-divide-by-zero,shift-base,shift-exponent,signed-integer-overflow,unsigned-integer-overflow,unsigned-shift-base,implicit-unsigned-integer-truncation,implicit-signed-integer-truncation,implicit-integer-sign-change" From ab5ae9a61febab0c76430acc061336b3b8fffe52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Valentin=20Clement=20=28=E3=83=90=E3=83=AC=E3=83=B3?= =?UTF-8?q?=E3=82=BF=E3=82=A4=E3=83=B3=20=E3=82=AF=E3=83=AC=E3=83=A1?= =?UTF-8?q?=E3=83=B3=29?= Date: Mon, 24 Nov 2025 14:28:16 -0800 Subject: [PATCH 25/50] [flang][cuda] Implement this_cluster for cooperative groups (#169414) Implement `this_cluster` like `this_group` by lowering it directly like an intrinsic function. Use the NVVM operation to get the rank and size information and populate the derived type. --- .../Optimizer/Builder/CUDAIntrinsicCall.h | 1 + .../Optimizer/Builder/CUDAIntrinsicCall.cpp | 42 +++++++++++++++++++ flang/module/cooperative_groups.f90 | 13 ++++++ 3 files changed, 56 insertions(+) diff --git a/flang/include/flang/Optimizer/Builder/CUDAIntrinsicCall.h b/flang/include/flang/Optimizer/Builder/CUDAIntrinsicCall.h index ae7d566920656..027bd3b79a1df 100644 --- a/flang/include/flang/Optimizer/Builder/CUDAIntrinsicCall.h +++ b/flang/include/flang/Optimizer/Builder/CUDAIntrinsicCall.h @@ -60,6 +60,7 @@ struct CUDAIntrinsicLibrary : IntrinsicLibrary { mlir::Value genSyncThreadsCount(mlir::Type, llvm::ArrayRef); mlir::Value genSyncThreadsOr(mlir::Type, llvm::ArrayRef); void genSyncWarp(llvm::ArrayRef); + mlir::Value genThisCluster(mlir::Type, llvm::ArrayRef); mlir::Value genThisGrid(mlir::Type, llvm::ArrayRef); mlir::Value genThisThreadBlock(mlir::Type, llvm::ArrayRef); mlir::Value genThisWarp(mlir::Type, llvm::ArrayRef); diff --git a/flang/lib/Optimizer/Builder/CUDAIntrinsicCall.cpp b/flang/lib/Optimizer/Builder/CUDAIntrinsicCall.cpp index f67129dfa6730..c560c53033780 100644 --- a/flang/lib/Optimizer/Builder/CUDAIntrinsicCall.cpp +++ b/flang/lib/Optimizer/Builder/CUDAIntrinsicCall.cpp @@ -457,6 +457,10 @@ static constexpr IntrinsicHandler cudaHandlers[]{ static_cast(&CI::genSyncWarp), {}, /*isElemental=*/false}, + {"this_cluster", + static_cast(&CI::genThisCluster), + {}, + /*isElemental=*/false}, {"this_grid", static_cast(&CI::genThisGrid), {}, @@ -1122,6 +1126,44 @@ void CUDAIntrinsicLibrary::genSyncWarp( mlir::NVVM::SyncWarpOp::create(builder, loc, fir::getBase(args[0])); } +// THIS_CLUSTER +mlir::Value +CUDAIntrinsicLibrary::genThisCluster(mlir::Type resultType, + llvm::ArrayRef args) { + assert(args.size() == 0); + auto recTy = mlir::cast(resultType); + assert(recTy && "RecordType expepected"); + mlir::Value res = fir::AllocaOp::create(builder, loc, resultType); + mlir::Type i32Ty = builder.getI32Type(); + + // SIZE + mlir::Value size = mlir::NVVM::ClusterDim::create(builder, loc, i32Ty); + auto sizeFieldName = recTy.getTypeList()[1].first; + mlir::Type sizeFieldTy = recTy.getTypeList()[1].second; + mlir::Type fieldIndexType = fir::FieldType::get(resultType.getContext()); + mlir::Value sizeFieldIndex = fir::FieldIndexOp::create( + builder, loc, fieldIndexType, sizeFieldName, recTy, + /*typeParams=*/mlir::ValueRange{}); + mlir::Value sizeCoord = fir::CoordinateOp::create( + builder, loc, builder.getRefType(sizeFieldTy), res, sizeFieldIndex); + fir::StoreOp::create(builder, loc, size, sizeCoord); + + // RANK + mlir::Value rank = mlir::NVVM::ClusterId::create(builder, loc, i32Ty); + mlir::Value one = builder.createIntegerConstant(loc, i32Ty, 1); + rank = mlir::arith::AddIOp::create(builder, loc, rank, one); + auto rankFieldName = recTy.getTypeList()[2].first; + mlir::Type rankFieldTy = recTy.getTypeList()[2].second; + mlir::Value rankFieldIndex = fir::FieldIndexOp::create( + builder, loc, fieldIndexType, rankFieldName, recTy, + /*typeParams=*/mlir::ValueRange{}); + mlir::Value rankCoord = fir::CoordinateOp::create( + builder, loc, builder.getRefType(rankFieldTy), res, rankFieldIndex); + fir::StoreOp::create(builder, loc, rank, rankCoord); + + return res; +} + // THIS_GRID mlir::Value CUDAIntrinsicLibrary::genThisGrid(mlir::Type resultType, diff --git a/flang/module/cooperative_groups.f90 b/flang/module/cooperative_groups.f90 index b8875f72f8079..1c89866f9c84a 100644 --- a/flang/module/cooperative_groups.f90 +++ b/flang/module/cooperative_groups.f90 @@ -14,6 +14,12 @@ module cooperative_groups implicit none +type :: cluster_group + type(c_devptr), private :: handle + integer(4) :: size + integer(4) :: rank +end type cluster_group + type :: grid_group type(c_devptr), private :: handle integer(4) :: size @@ -32,6 +38,13 @@ module cooperative_groups integer(4) :: rank end type thread_group +interface + attributes(device) function this_cluster() + import + type(cluster_group) :: this_cluster + end function +end interface + interface attributes(device) function this_grid() import From 4e7ce57e0e2ea04ab04c45127e6862a710460ebd Mon Sep 17 00:00:00 2001 From: Yury Plyakhin Date: Mon, 24 Nov 2025 14:29:50 -0800 Subject: [PATCH 26/50] [Offload][NFC] Offload wrapper cleanup/refactoring (#169411) Addresses feedback from https://github.com/llvm/llvm-project/pull/147508#pullrequestreview-3272708203 : - Update access modifiers for SYCLWrapper members. - Update comments. - Update types. --- .../llvm/Frontend/Offloading/OffloadWrapper.h | 10 +- .../Frontend/Offloading/OffloadWrapper.cpp | 315 +++++++++--------- 2 files changed, 167 insertions(+), 158 deletions(-) diff --git a/llvm/include/llvm/Frontend/Offloading/OffloadWrapper.h b/llvm/include/llvm/Frontend/Offloading/OffloadWrapper.h index 24017492e30b2..dc99e29964afc 100644 --- a/llvm/include/llvm/Frontend/Offloading/OffloadWrapper.h +++ b/llvm/include/llvm/Frontend/Offloading/OffloadWrapper.h @@ -56,18 +56,18 @@ LLVM_ABI llvm::Error wrapHIPBinary(llvm::Module &M, llvm::ArrayRef Images, bool EmitSurfacesAndTextures = true); struct SYCLJITOptions { - // Target/compiler specific options that are suggested to use to "compile" - // program at runtime. + // Target/compiler specific options that are passed to the device compiler at + // runtime. std::string CompileOptions; - // Target/compiler specific options that are suggested to use to "link" - // program at runtime. + // Target/compiler specific options that are passed to the device linker at + // runtime. std::string LinkOptions; }; /// Wraps OffloadBinaries in the given \p Buffers into the module \p M /// as global symbols and registers the images with the SYCL Runtime. /// \param Options Compiler and linker options to be encoded for the later -/// use by a runtime for JIT compilation. +/// use by a runtime for JIT compilation. Not used for AOT. LLVM_ABI llvm::Error wrapSYCLBinaries(llvm::Module &M, llvm::ArrayRef Buffer, SYCLJITOptions Options = SYCLJITOptions()); diff --git a/llvm/lib/Frontend/Offloading/OffloadWrapper.cpp b/llvm/lib/Frontend/Offloading/OffloadWrapper.cpp index 86060d1d2b0b3..288fa10fc04bb 100644 --- a/llvm/lib/Frontend/Offloading/OffloadWrapper.cpp +++ b/llvm/lib/Frontend/Offloading/OffloadWrapper.cpp @@ -640,15 +640,8 @@ void createRegisterFatbinFunction(Module &M, GlobalVariable *FatbinDesc, } /// SYCLWrapper helper class that creates all LLVM IRs wrapping given images. -struct SYCLWrapper { - Module &M; - LLVMContext &C; - SYCLJITOptions Options; - - StructType *EntryTy = nullptr; - StructType *SyclDeviceImageTy = nullptr; - StructType *SyclBinDescTy = nullptr; - +class SYCLWrapper { +public: SYCLWrapper(Module &M, const SYCLJITOptions &Options) : M(M), C(M.getContext()), Options(Options) { EntryTy = offloading::getEntryTy(M); @@ -656,6 +649,115 @@ struct SYCLWrapper { SyclBinDescTy = getSyclBinDescTy(); } + /// Creates binary descriptor for the given device images. Binary descriptor + /// is an object that is passed to the offloading runtime at program startup + /// and it describes all device images available in the executable or shared + /// library. It is defined as follows: + /// + /// \code + /// __attribute__((visibility("hidden"))) + /// __tgt_offload_entry *__sycl_offload_entries_arr0[]; + /// ... + /// __attribute__((visibility("hidden"))) + /// __tgt_offload_entry *__sycl_offload_entries_arrN[]; + /// + /// __attribute__((visibility("hidden"))) + /// extern const char *CompileOptions = "..."; + /// ... + /// __attribute__((visibility("hidden"))) + /// extern const char *LinkOptions = "..."; + /// ... + /// + /// static const char Image0[] = { ... }; + /// ... + /// static const char ImageN[] = { ... }; + /// + /// static const __sycl.tgt_device_image Images[] = { + /// { + /// Version, // Version + /// OffloadKind, // OffloadKind + /// Format, // Format of the image. + // TripleString, // Arch + /// CompileOptions, // CompileOptions + /// LinkOptions, // LinkOptions + /// Image0, // ImageStart + /// Image0 + IMAGE0_SIZE, // ImageEnd + /// __sycl_offload_entries_arr0, // EntriesBegin + /// __sycl_offload_entries_arr0 + ENTRIES0_SIZE, // EntriesEnd + /// NULL, // PropertiesBegin + /// NULL, // PropertiesEnd + /// }, + /// ... + /// }; + /// + /// static const __sycl.tgt_bin_desc FatbinDesc = { + /// Version, //Version + /// sizeof(Images) / sizeof(Images[0]), //NumDeviceImages + /// Images, //DeviceImages + /// NULL, //HostEntriesBegin + /// NULL //HostEntriesEnd + /// }; + /// \endcode + /// + /// \returns Global variable that represents FatbinDesc. + GlobalVariable *createFatbinDesc(ArrayRef OffloadFiles) { + StringRef OffloadKindTag = ".sycl_offloading."; + SmallVector WrappedImages; + WrappedImages.reserve(OffloadFiles.size()); + for (size_t I = 0, E = OffloadFiles.size(); I != E; ++I) + WrappedImages.push_back( + wrapImage(*OffloadFiles[I].getBinary(), Twine(I), OffloadKindTag)); + + return combineWrappedImages(WrappedImages, OffloadKindTag); + } + + void createRegisterFatbinFunction(GlobalVariable *FatbinDesc) { + FunctionType *FuncTy = + FunctionType::get(Type::getVoidTy(C), /*isVarArg*/ false); + Function *Func = Function::Create(FuncTy, GlobalValue::InternalLinkage, + Twine("sycl") + ".descriptor_reg", &M); + Func->setSection(".text.startup"); + + // Get RegFuncName function declaration. + FunctionType *RegFuncTy = + FunctionType::get(Type::getVoidTy(C), PointerType::getUnqual(C), + /*isVarArg=*/false); + FunctionCallee RegFuncC = + M.getOrInsertFunction("__sycl_register_lib", RegFuncTy); + + // Construct function body. + IRBuilder Builder(BasicBlock::Create(C, "entry", Func)); + Builder.CreateCall(RegFuncC, FatbinDesc); + Builder.CreateRetVoid(); + + // Add this function to constructors. + appendToGlobalCtors(M, Func, /*Priority*/ 1); + } + + void createUnregisterFunction(GlobalVariable *FatbinDesc) { + FunctionType *FuncTy = + FunctionType::get(Type::getVoidTy(C), /*isVarArg*/ false); + Function *Func = Function::Create(FuncTy, GlobalValue::InternalLinkage, + "sycl.descriptor_unreg", &M); + Func->setSection(".text.startup"); + + // Get UnregFuncName function declaration. + FunctionType *UnRegFuncTy = + FunctionType::get(Type::getVoidTy(C), PointerType::getUnqual(C), + /*isVarArg=*/false); + FunctionCallee UnRegFuncC = + M.getOrInsertFunction("__sycl_unregister_lib", UnRegFuncTy); + + // Construct function body + IRBuilder<> Builder(BasicBlock::Create(C, "entry", Func)); + Builder.CreateCall(UnRegFuncC, FatbinDesc); + Builder.CreateRetVoid(); + + // Add this function to global destructors. + appendToGlobalDtors(M, Func, /*Priority*/ 1); + } + +private: IntegerType *getSizeTTy() { switch (M.getDataLayout().getPointerSize()) { case 4: @@ -678,28 +780,28 @@ struct SYCLWrapper { /// SYCL specific image descriptor type. /// \code /// struct __sycl.tgt_device_image { - /// // version of this structure - for backward compatibility; + /// // Version of this structure - for backward compatibility; /// // all modifications which change order/type/offsets of existing fields /// // should increment the version. /// uint16_t Version; - /// // the kind of offload model the image employs. + /// // The kind of offload model the image employs. /// uint8_t OffloadKind; - /// // format of the image data - SPIRV, LLVMIR bitcode, etc + /// // Format of the image data - SPIRV, LLVMIR bitcode, etc. /// uint8_t Format; - /// // null-terminated string representation of the device's target - /// // architecture + /// // Null-terminated string representation of the device's target + /// // architecture. /// const char *Arch; - /// // a null-terminated string; target- and compiler-specific options - /// // which are suggested to use to "compile" program at runtime + /// // A null-terminated string; target- and compiler-specific options + /// // which are passed to the device compiler at runtime. /// const char *CompileOptions; - /// // a null-terminated string; target- and compiler-specific options - /// // which are suggested to use to "link" program at runtime + /// // A null-terminated string; target- and compiler-specific options + /// // which are passed to the device linker at runtime. /// const char *LinkOptions; - /// // Pointer to the device binary image start + /// // Pointer to the device binary image start. /// void *ImageStart; - /// // Pointer to the device binary image end + /// // Pointer to the device binary image end. /// void *ImageEnd; - /// // the entry table + /// // The entry table. /// __tgt_offload_entry *EntriesBegin; /// __tgt_offload_entry *EntriesEnd; /// const char *PropertiesBegin; @@ -753,13 +855,14 @@ struct SYCLWrapper { GlobalVariable *addGlobalArrayVariable(const Twine &Name, ArrayRef Initializer, const Twine &Section = "") { - auto *Arr = ConstantDataArray::get(M.getContext(), Initializer); - auto *Var = new GlobalVariable(M, Arr->getType(), /*isConstant*/ true, - GlobalVariable::InternalLinkage, Arr, Name); + Constant *Arr = ConstantDataArray::get(M.getContext(), Initializer); + GlobalVariable *Var = + new GlobalVariable(M, Arr->getType(), /*isConstant*/ true, + GlobalVariable::InternalLinkage, Arr, Name); Var->setUnnamedAddr(GlobalValue::UnnamedAddr::Global); SmallVector NameBuf; - auto SectionName = Section.toStringRef(NameBuf); + StringRef SectionName = Section.toStringRef(NameBuf); if (!SectionName.empty()) Var->setSection(SectionName); return Var; @@ -771,10 +874,10 @@ struct SYCLWrapper { std::pair addArrayToModule(ArrayRef Buf, const Twine &Name, const Twine &Section = "") { - auto *Var = addGlobalArrayVariable(Name, Buf, Section); - auto *ImageB = ConstantExpr::getGetElementPtr(Var->getValueType(), Var, - getSizetConstPair(0, 0)); - auto *ImageE = ConstantExpr::getGetElementPtr( + GlobalVariable *Var = addGlobalArrayVariable(Name, Buf, Section); + Constant *ImageB = ConstantExpr::getGetElementPtr(Var->getValueType(), Var, + getSizetConstPair(0, 0)); + Constant *ImageE = ConstantExpr::getGetElementPtr( Var->getValueType(), Var, getSizetConstPair(0, Buf.size())); return std::make_pair(ImageB, ImageE); } @@ -783,9 +886,9 @@ struct SYCLWrapper { /// \returns Constant pointer to the added data. The pointer type does not /// carry size information. Constant *addRawDataToModule(ArrayRef Data, const Twine &Name) { - auto *Var = addGlobalArrayVariable(Name, Data); - auto *DataPtr = ConstantExpr::getGetElementPtr(Var->getValueType(), Var, - getSizetConstPair(0, 0)); + GlobalVariable *Var = addGlobalArrayVariable(Name, Data); + Constant *DataPtr = ConstantExpr::getGetElementPtr(Var->getValueType(), Var, + getSizetConstPair(0, 0)); return DataPtr; } @@ -795,11 +898,12 @@ struct SYCLWrapper { /// \returns Link-time constant pointer (constant expr) to that /// variable. Constant *addStringToModule(StringRef Str, const Twine &Name) { - auto *Arr = ConstantDataArray::getString(C, Str); - auto *Var = new GlobalVariable(M, Arr->getType(), /*isConstant*/ true, - GlobalVariable::InternalLinkage, Arr, Name); + Constant *Arr = ConstantDataArray::getString(C, Str); + GlobalVariable *Var = + new GlobalVariable(M, Arr->getType(), /*isConstant*/ true, + GlobalVariable::InternalLinkage, Arr, Name); Var->setUnnamedAddr(GlobalValue::UnnamedAddr::Global); - auto *Zero = ConstantInt::get(getSizeTTy(), 0); + ConstantInt *Zero = ConstantInt::get(getSizeTTy(), 0); Constant *ZeroZero[] = {Zero, Zero}; return ConstantExpr::getGetElementPtr(Var->getValueType(), Var, ZeroZero); } @@ -823,15 +927,15 @@ struct SYCLWrapper { EntriesInits.push_back(GV->getInitializer()); } - auto *Arr = ConstantArray::get(ArrayType::get(EntryTy, EntriesInits.size()), - EntriesInits); - auto *EntriesGV = new GlobalVariable(M, Arr->getType(), /*isConstant*/ true, - GlobalVariable::InternalLinkage, Arr, - OffloadKindTag + "entries_arr"); + Constant *Arr = ConstantArray::get( + ArrayType::get(EntryTy, EntriesInits.size()), EntriesInits); + GlobalVariable *EntriesGV = new GlobalVariable( + M, Arr->getType(), /*isConstant*/ true, GlobalVariable::InternalLinkage, + Arr, OffloadKindTag + "entries_arr"); - auto *EntriesB = ConstantExpr::getGetElementPtr( + Constant *EntriesB = ConstantExpr::getGetElementPtr( EntriesGV->getValueType(), EntriesGV, getSizetConstPair(0, 0)); - auto *EntriesE = ConstantExpr::getGetElementPtr( + Constant *EntriesE = ConstantExpr::getGetElementPtr( EntriesGV->getValueType(), EntriesGV, getSizetConstPair(0, EntriesInits.size())); return std::make_pair(EntriesB, EntriesE); @@ -871,6 +975,9 @@ struct SYCLWrapper { // For SYCL images offload entries are defined here per image. std::pair ImageEntriesPtrs = initOffloadEntriesPerImage(OB.getString("symbols"), OffloadKindTag); + + // .first and .second arguments below correspond to start and end pointers + // respectively. Constant *WrappedBinary = ConstantStruct::get( SyclDeviceImageTy, Version, OffloadKindConstant, ImageKindConstant, TripleConstant, CompileOptions, LinkOptions, Binary.first, @@ -882,23 +989,23 @@ struct SYCLWrapper { GlobalVariable *combineWrappedImages(ArrayRef WrappedImages, StringRef OffloadKindTag) { - auto *ImagesData = ConstantArray::get( + Constant *ImagesData = ConstantArray::get( ArrayType::get(SyclDeviceImageTy, WrappedImages.size()), WrappedImages); - auto *ImagesGV = + GlobalVariable *ImagesGV = new GlobalVariable(M, ImagesData->getType(), /*isConstant*/ true, GlobalValue::InternalLinkage, ImagesData, Twine(OffloadKindTag) + "device_images"); ImagesGV->setUnnamedAddr(GlobalValue::UnnamedAddr::Global); - auto *Zero = ConstantInt::get(getSizeTTy(), 0); + ConstantInt *Zero = ConstantInt::get(getSizeTTy(), 0); Constant *ZeroZero[] = {Zero, Zero}; - auto *ImagesB = ConstantExpr::getGetElementPtr(ImagesGV->getValueType(), - ImagesGV, ZeroZero); + Constant *ImagesB = ConstantExpr::getGetElementPtr(ImagesGV->getValueType(), + ImagesGV, ZeroZero); Constant *EntriesB = Constant::getNullValue(PointerType::getUnqual(C)); Constant *EntriesE = Constant::getNullValue(PointerType::getUnqual(C)); static constexpr uint16_t BinDescStructVersion = 1; - auto *DescInit = ConstantStruct::get( + Constant *DescInit = ConstantStruct::get( SyclBinDescTy, ConstantInt::get(Type::getInt16Ty(C), BinDescStructVersion), ConstantInt::get(Type::getInt16Ty(C), WrappedImages.size()), ImagesB, @@ -909,111 +1016,13 @@ struct SYCLWrapper { Twine(OffloadKindTag) + "descriptor"); } - /// Creates binary descriptor for the given device images. Binary descriptor - /// is an object that is passed to the offloading runtime at program startup - /// and it describes all device images available in the executable or shared - /// library. It is defined as follows: - /// - /// \code - /// __attribute__((visibility("hidden"))) - /// __tgt_offload_entry *__sycl_offload_entries_arr0[]; - /// ... - /// __attribute__((visibility("hidden"))) - /// __tgt_offload_entry *__sycl_offload_entries_arrN[]; - /// - /// __attribute__((visibility("hidden"))) - /// extern const char *CompileOptions = "..."; - /// ... - /// __attribute__((visibility("hidden"))) - /// extern const char *LinkOptions = "..."; - /// ... - /// - /// static const char Image0[] = { ... }; - /// ... - /// static const char ImageN[] = { ... }; - /// - /// static const __sycl.tgt_device_image Images[] = { - /// { - /// Version, // Version - /// OffloadKind, // OffloadKind - /// Format, // Format of the image. - // TripleString, // Arch - /// CompileOptions, // CompileOptions - /// LinkOptions, // LinkOptions - /// Image0, // ImageStart - /// Image0 + IMAGE0_SIZE, // ImageEnd - /// __sycl_offload_entries_arr0, // EntriesBegin - /// __sycl_offload_entries_arr0 + ENTRIES0_SIZE, // EntriesEnd - /// NULL, // PropertiesBegin - /// NULL, // PropertiesEnd - /// }, - /// ... - /// }; - /// - /// static const __sycl.tgt_bin_desc FatbinDesc = { - /// Version, //Version - /// sizeof(Images) / sizeof(Images[0]), //NumDeviceImages - /// Images, //DeviceImages - /// NULL, //HostEntriesBegin - /// NULL //HostEntriesEnd - /// }; - /// \endcode - /// - /// \returns Global variable that represents FatbinDesc. - GlobalVariable *createFatbinDesc(ArrayRef OffloadFiles) { - StringRef OffloadKindTag = ".sycl_offloading."; - SmallVector WrappedImages; - WrappedImages.reserve(OffloadFiles.size()); - for (size_t I = 0, E = OffloadFiles.size(); I != E; ++I) - WrappedImages.push_back( - wrapImage(*OffloadFiles[I].getBinary(), Twine(I), OffloadKindTag)); - - return combineWrappedImages(WrappedImages, OffloadKindTag); - } - - void createRegisterFatbinFunction(GlobalVariable *FatbinDesc) { - auto *FuncTy = FunctionType::get(Type::getVoidTy(C), /*isVarArg*/ false); - auto *Func = Function::Create(FuncTy, GlobalValue::InternalLinkage, - Twine("sycl") + ".descriptor_reg", &M); - Func->setSection(".text.startup"); - - // Get RegFuncName function declaration. - auto *RegFuncTy = - FunctionType::get(Type::getVoidTy(C), PointerType::getUnqual(C), - /*isVarArg=*/false); - FunctionCallee RegFuncC = - M.getOrInsertFunction("__sycl_register_lib", RegFuncTy); - - // Construct function body - IRBuilder Builder(BasicBlock::Create(C, "entry", Func)); - Builder.CreateCall(RegFuncC, FatbinDesc); - Builder.CreateRetVoid(); - - // Add this function to constructors. - appendToGlobalCtors(M, Func, /*Priority*/ 1); - } - - void createUnregisterFunction(GlobalVariable *FatbinDesc) { - auto *FuncTy = FunctionType::get(Type::getVoidTy(C), /*isVarArg*/ false); - auto *Func = Function::Create(FuncTy, GlobalValue::InternalLinkage, - "sycl.descriptor_unreg", &M); - Func->setSection(".text.startup"); - - // Get UnregFuncName function declaration. - auto *UnRegFuncTy = - FunctionType::get(Type::getVoidTy(C), PointerType::getUnqual(C), - /*isVarArg=*/false); - FunctionCallee UnRegFuncC = - M.getOrInsertFunction("__sycl_unregister_lib", UnRegFuncTy); - - // Construct function body - IRBuilder<> Builder(BasicBlock::Create(C, "entry", Func)); - Builder.CreateCall(UnRegFuncC, FatbinDesc); - Builder.CreateRetVoid(); + Module &M; + LLVMContext &C; + SYCLJITOptions Options; - // Add this function to global destructors. - appendToGlobalDtors(M, Func, /*Priority*/ 1); - } + StructType *EntryTy = nullptr; + StructType *SyclDeviceImageTy = nullptr; + StructType *SyclBinDescTy = nullptr; }; // end of SYCLWrapper } // namespace From 9cff3f51d35c4273a48b987bdeddd10248ecb5e4 Mon Sep 17 00:00:00 2001 From: Krzysztof Parzyszek Date: Mon, 24 Nov 2025 16:48:27 -0600 Subject: [PATCH 27/50] [flang][OpenMP] Tolerate compiler directives in loop constructs (#169346) PR168884 flagged compiler directives (!dir$ ...) inside OpenMP loop constructs as errors. This caused some customer applications to fail to compile (issue 169229). Downgrade the error to a warning, and gracefully ignore compiler directives when lowering loop constructs to MLIR. Fixes https://github.com/llvm/llvm-project/issues/169229 --- flang/lib/Lower/OpenMP/Utils.cpp | 31 ++++++++++++++++--- flang/lib/Semantics/check-omp-loop.cpp | 2 +- flang/lib/Semantics/resolve-directives.cpp | 7 ----- .../OpenMP/compiler-directives-loop.f90 | 21 +++++++++++++ .../Semantics/OpenMP/loop-association.f90 | 3 +- 5 files changed, 49 insertions(+), 15 deletions(-) create mode 100644 flang/test/Semantics/OpenMP/compiler-directives-loop.f90 diff --git a/flang/lib/Lower/OpenMP/Utils.cpp b/flang/lib/Lower/OpenMP/Utils.cpp index 7d7a4869ab3a6..fed84eb4df071 100644 --- a/flang/lib/Lower/OpenMP/Utils.cpp +++ b/flang/lib/Lower/OpenMP/Utils.cpp @@ -796,6 +796,28 @@ static void processTileSizesFromOpenMPConstruct( } } +static pft::Evaluation *getNestedDoConstruct(pft::Evaluation &eval) { + for (pft::Evaluation &nested : eval.getNestedEvaluations()) { + // In an OpenMPConstruct there can be compiler directives: + // 1 <> + // 2 CompilerDirective: !unroll + // <> -> 8 + if (nested.getIf()) + continue; + // Within a DoConstruct, there can be compiler directives, plus + // there is a DoStmt before the body: + // <> -> 8 + // 3 NonLabelDoStmt -> 7: do i = 1, n + // <> -> 7 + if (nested.getIf()) + continue; + assert(nested.getIf() && + "Unexpected construct in the nested evaluations"); + return &nested; + } + llvm_unreachable("Expected do loop to be in the nested evaluations"); +} + /// Populates the sizes vector with values if the given OpenMPConstruct /// contains a loop construct with an inner tiling construct. void collectTileSizesFromOpenMPConstruct( @@ -818,7 +840,7 @@ int64_t collectLoopRelatedInfo( int64_t numCollapse = 1; // Collect the loops to collapse. - lower::pft::Evaluation *doConstructEval = &eval.getFirstNestedEvaluation(); + lower::pft::Evaluation *doConstructEval = getNestedDoConstruct(eval); if (doConstructEval->getIf()->IsDoConcurrent()) { TODO(currentLocation, "Do Concurrent in Worksharing loop construct"); } @@ -844,7 +866,7 @@ void collectLoopRelatedInfo( fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder(); // Collect the loops to collapse. - lower::pft::Evaluation *doConstructEval = &eval.getFirstNestedEvaluation(); + lower::pft::Evaluation *doConstructEval = getNestedDoConstruct(eval); if (doConstructEval->getIf()->IsDoConcurrent()) { TODO(currentLocation, "Do Concurrent in Worksharing loop construct"); } @@ -885,9 +907,8 @@ void collectLoopRelatedInfo( iv.push_back(bounds->name.thing.symbol); loopVarTypeSize = std::max(loopVarTypeSize, bounds->name.thing.symbol->GetUltimate().size()); - collapseValue--; - doConstructEval = - &*std::next(doConstructEval->getNestedEvaluations().begin()); + if (--collapseValue) + doConstructEval = getNestedDoConstruct(*doConstructEval); } while (collapseValue > 0); convertLoopBounds(converter, currentLocation, result, loopVarTypeSize); diff --git a/flang/lib/Semantics/check-omp-loop.cpp b/flang/lib/Semantics/check-omp-loop.cpp index 6d83ee62c3b73..ef237a01d0f7a 100644 --- a/flang/lib/Semantics/check-omp-loop.cpp +++ b/flang/lib/Semantics/check-omp-loop.cpp @@ -267,7 +267,7 @@ void OmpStructureChecker::CheckNestedBlock(const parser::OpenMPLoopConstruct &x, for (auto &stmt : body) { if (auto *dir{parser::Unwrap(stmt)}) { context_.Say(dir->source, - "Compiler directives are not allowed inside OpenMP loop constructs"_err_en_US); + "Compiler directives are not allowed inside OpenMP loop constructs"_warn_en_US); } else if (parser::Unwrap(stmt)) { ++nestedCount; } else if (auto *omp{parser::Unwrap(stmt)}) { diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp index 673ea4ef10e08..b992a4125ffcb 100644 --- a/flang/lib/Semantics/resolve-directives.cpp +++ b/flang/lib/Semantics/resolve-directives.cpp @@ -2419,13 +2419,6 @@ void OmpAttributeVisitor::PrivatizeAssociatedLoopIndexAndCheckLoopLevel( } } CheckAssocLoopLevel(level, GetAssociatedClause()); - } else { - unsigned version{context_.langOptions().OpenMPVersion}; - context_.Say(GetContext().directiveSource, - "A DO loop must follow the %s directive"_err_en_US, - parser::ToUpperCaseLetters( - llvm::omp::getOpenMPDirectiveName(GetContext().directive, version) - .str())); } } } diff --git a/flang/test/Semantics/OpenMP/compiler-directives-loop.f90 b/flang/test/Semantics/OpenMP/compiler-directives-loop.f90 new file mode 100644 index 0000000000000..48b9529c95dc2 --- /dev/null +++ b/flang/test/Semantics/OpenMP/compiler-directives-loop.f90 @@ -0,0 +1,21 @@ +!RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=60 %s -o - | FileCheck %s + +! Check that this compiles successfully, but not rely on any specific output. + +!CHECK: omp.parallel + +program omp_cdir_crash + implicit none + integer, parameter :: n = 10 + real :: a(n) + integer :: i + +!$omp parallel do +!dir$ unroll + do i = 1, n + a(i) = real(i) + end do +!$omp end parallel do + + print *, 'a(1)=', a(1), ' a(n)=', a(n) +end program omp_cdir_crash diff --git a/flang/test/Semantics/OpenMP/loop-association.f90 b/flang/test/Semantics/OpenMP/loop-association.f90 index 9c79a91429fdf..4e63cafb3fda1 100644 --- a/flang/test/Semantics/OpenMP/loop-association.f90 +++ b/flang/test/Semantics/OpenMP/loop-association.f90 @@ -33,10 +33,9 @@ END DO outer ! Accept directives between parallel do and actual loop. - !ERROR: A DO loop must follow the PARALLEL DO directive !$OMP PARALLEL DO !WARNING: Unrecognized compiler directive was ignored [-Wignored-directive] - !ERROR: Compiler directives are not allowed inside OpenMP loop constructs + !WARNING: Compiler directives are not allowed inside OpenMP loop constructs !DIR$ VECTOR ALIGNED DO 20 i=1,N a = a + 0.5 From 435dbbacad475b12b6cae0a8296e8a46ea684812 Mon Sep 17 00:00:00 2001 From: Andy Kaylor Date: Mon, 24 Nov 2025 14:48:55 -0800 Subject: [PATCH 28/50] [CIR] Fix a problem with global array dtor lowering (#169416) In the LoweringPrepare pass, the handling for global array destructor lowering was mishandling the insertion point, so that if this code needed to create a declaration for the __cxa_atexit function, that declaration was being created in the dtor region, rather than at module scope. This change fixes that. --- .../Dialect/Transforms/LoweringPrepare.cpp | 1 + clang/test/CIR/CodeGen/global-array-dtor.cpp | 113 ++++++++++++++++++ 2 files changed, 114 insertions(+) create mode 100644 clang/test/CIR/CodeGen/global-array-dtor.cpp diff --git a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp index f8f354c2d1072..cedc2a73b9260 100644 --- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp +++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp @@ -702,6 +702,7 @@ cir::FuncOp LoweringPreparePass::getOrCreateDtorFunc(CIRBaseBuilderTy &builder, cir::GlobalOp op, mlir::Region &dtorRegion, cir::CallOp &dtorCall) { + mlir::OpBuilder::InsertionGuard guard(builder); assert(!cir::MissingFeatures::astVarDeclInterface()); assert(!cir::MissingFeatures::opGlobalThreadLocal()); diff --git a/clang/test/CIR/CodeGen/global-array-dtor.cpp b/clang/test/CIR/CodeGen/global-array-dtor.cpp new file mode 100644 index 0000000000000..01277a3f34015 --- /dev/null +++ b/clang/test/CIR/CodeGen/global-array-dtor.cpp @@ -0,0 +1,113 @@ +// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir -mmlir --mlir-print-ir-before=cir-lowering-prepare %s -o %t.cir 2> %t-before.cir +// RUN: FileCheck --input-file=%t-before.cir %s --check-prefix=CIR-BEFORE-LPP +// RUN: FileCheck --input-file=%t.cir %s --check-prefix=CIR +// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefix=LLVM +// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s --check-prefix=OGCG + +// This duplicates a test case in global-init.cpp, but having it by itself +// forces the __cxa_atexit function to be emitted for this case, which was +// broken in the original implementation. + +struct ArrayDtor { + ~ArrayDtor(); +}; + +ArrayDtor arrDtor[16]; + +// CIR-BEFORE-LPP: cir.global external @arrDtor = #cir.zero : !cir.array +// CIR-BEFORE-LPP-SAME: dtor { +// CIR-BEFORE-LPP: %[[THIS:.*]] = cir.get_global @arrDtor : !cir.ptr> +// CIR-BEFORE-LPP: cir.array.dtor %[[THIS]] : !cir.ptr> { +// CIR-BEFORE-LPP: ^bb0(%[[ELEM:.*]]: !cir.ptr): +// CIR-BEFORE-LPP: cir.call @_ZN9ArrayDtorD1Ev(%[[ELEM]]) nothrow : (!cir.ptr) -> () +// CIR-BEFORE-LPP: cir.yield +// CIR-BEFORE-LPP: } +// CIR-BEFORE-LPP: } + +// CIR: cir.global external @arrDtor = #cir.zero : !cir.array {alignment = 16 : i64} +// CIR: cir.func internal private @__cxx_global_array_dtor(%[[ARR_ARG:.*]]: !cir.ptr {{.*}}) { +// CIR: %[[CONST15:.*]] = cir.const #cir.int<15> : !u64i +// CIR: %[[BEGIN:.*]] = cir.cast array_to_ptrdecay %[[ARR_ARG]] : !cir.ptr -> !cir.ptr +// CIR: %[[END:.*]] = cir.ptr_stride %[[BEGIN]], %[[CONST15]] : (!cir.ptr, !u64i) -> !cir.ptr +// CIR: %[[CUR_ADDR:.*]] = cir.alloca !cir.ptr, !cir.ptr>, ["__array_idx"] +// CIR: cir.store %[[END]], %[[CUR_ADDR]] : !cir.ptr, !cir.ptr> +// CIR: cir.do { +// CIR: %[[CUR:.*]] = cir.load %[[CUR_ADDR]] : !cir.ptr>, !cir.ptr +// CIR: cir.call @_ZN9ArrayDtorD1Ev(%[[CUR]]) nothrow : (!cir.ptr) -> () +// CIR: %[[NEG_ONE:.*]] = cir.const #cir.int<-1> : !s64i +// CIR: %[[NEXT:.*]] = cir.ptr_stride %[[CUR]], %[[NEG_ONE]] : (!cir.ptr, !s64i) -> !cir.ptr +// CIR: cir.store %[[NEXT]], %[[CUR_ADDR]] : !cir.ptr, !cir.ptr> +// CIR: cir.yield +// CIR: } while { +// CIR: %[[CUR:.*]] = cir.load %[[CUR_ADDR]] : !cir.ptr>, !cir.ptr +// CIR: %[[CMP:.*]] = cir.cmp(ne, %[[CUR]], %[[BEGIN]]) : !cir.ptr, !cir.bool +// CIR: cir.condition(%[[CMP]]) +// CIR: } +// CIR: cir.return +// CIR: } +// +// CIR: cir.func internal private @__cxx_global_var_init() { +// CIR: %[[ARR:.*]] = cir.get_global @arrDtor : !cir.ptr> +// CIR: %[[DTOR:.*]] = cir.get_global @__cxx_global_array_dtor : !cir.ptr)>> +// CIR: %[[DTOR_CAST:.*]] = cir.cast bitcast %[[DTOR]] : !cir.ptr)>> -> !cir.ptr)>> +// CIR: %[[ARR_CAST:.*]] = cir.cast bitcast %[[ARR]] : !cir.ptr> -> !cir.ptr +// CIR: %[[HANDLE:.*]] = cir.get_global @__dso_handle : !cir.ptr +// CIR: cir.call @__cxa_atexit(%[[DTOR_CAST]], %[[ARR_CAST]], %[[HANDLE]]) : (!cir.ptr)>>, !cir.ptr, !cir.ptr) -> () + +// LLVM: define internal void @__cxx_global_array_dtor(ptr %[[ARR_ARG:.*]]) { +// LLVM: %[[BEGIN:.*]] = getelementptr %struct.ArrayDtor, ptr %[[ARR_ARG]], i32 0 +// LLVM: %[[END:.*]] = getelementptr %struct.ArrayDtor, ptr %[[BEGIN]], i64 15 +// LLVM: %[[CUR_ADDR:.*]] = alloca ptr +// LLVM: store ptr %[[END]], ptr %[[CUR_ADDR]] +// LLVM: br label %[[LOOP_BODY:.*]] +// LLVM: [[LOOP_COND:.*]]: +// LLVM: %[[CUR:.*]] = load ptr, ptr %[[CUR_ADDR]] +// LLVM: %[[CMP:.*]] = icmp ne ptr %[[CUR]], %[[BEGIN]] +// LLVM: br i1 %[[CMP]], label %[[LOOP_BODY]], label %[[LOOP_END:.*]] +// LLVM: [[LOOP_BODY]]: +// LLVM: %[[CUR:.*]] = load ptr, ptr %[[CUR_ADDR]] +// LLVM: call void @_ZN9ArrayDtorD1Ev(ptr %[[CUR]]) #0 +// LLVM: %[[PREV:.*]] = getelementptr %struct.ArrayDtor, ptr %[[CUR]], i64 -1 +// LLVM: store ptr %[[PREV]], ptr %[[CUR_ADDR]] +// LLVM: br label %[[LOOP_COND]] +// LLVM: [[LOOP_END]]: +// LLVM: ret void +// LLVM: } +// +// LLVM: define internal void @__cxx_global_var_init() { +// LLVM: call void @__cxa_atexit(ptr @__cxx_global_array_dtor, ptr @arrDtor, ptr @__dso_handle) + +// Note: OGCG defines these functions in reverse order of CIR->LLVM. +// Note also: OGCG doesn't pass the address of the array to the destructor function. +// Instead, it uses the global directly in the helper function. + +// OGCG: define internal void @__cxx_global_var_init() {{.*}} section ".text.startup" { +// OGCG: call i32 @__cxa_atexit(ptr @__cxx_global_array_dtor, ptr null, ptr @__dso_handle) + +// OGCG: define internal void @__cxx_global_array_dtor(ptr noundef %[[ARG:.*]]) {{.*}} section ".text.startup" { +// OGCG: entry: +// OGCG: %[[UNUSED_ADDR:.*]] = alloca ptr +// OGCG: store ptr %[[ARG]], ptr %[[UNUSED_ADDR]] +// OGCG: br label %[[LOOP_BODY:.*]] +// OGCG: [[LOOP_BODY]]: +// OGCG: %[[PREV:.*]] = phi ptr [ getelementptr inbounds (%struct.ArrayDtor, ptr @arrDtor, i64 16), %entry ], [ %[[CUR:.*]], %[[LOOP_BODY]] ] +// OGCG: %[[CUR]] = getelementptr inbounds %struct.ArrayDtor, ptr %[[PREV]], i64 -1 +// OGCG: call void @_ZN9ArrayDtorD1Ev(ptr noundef nonnull align 1 dereferenceable(1) %[[CUR]]) +// OGCG: %[[DONE:.*]] = icmp eq ptr %[[CUR]], @arrDtor +// OGCG: br i1 %[[DONE]], label %[[LOOP_END:.*]], label %[[LOOP_BODY]] +// OGCG: [[LOOP_END]]: +// OGCG: ret void +// OGCG: } + +// Common init function for all globals with default priority + +// CIR: cir.func private @_GLOBAL__sub_I_[[FILENAME:.*]]() { +// CIR: cir.call @__cxx_global_var_init() : () -> () + +// LLVM: define void @_GLOBAL__sub_I_[[FILENAME:.*]]() +// LLVM: call void @__cxx_global_var_init() + +// OGCG: define internal void @_GLOBAL__sub_I_[[FILENAME:.*]]() {{.*}} section ".text.startup" { +// OGCG: call void @__cxx_global_var_init() From fd94b410ef60ca0a0494c2164d7897b698315443 Mon Sep 17 00:00:00 2001 From: Scott Linder Date: Mon, 24 Nov 2025 17:53:54 -0500 Subject: [PATCH 29/50] [MC] Use a variant to hold MCCFIInstruction state (NFC) (#164720) AMDGPU requires more complex CFI rules, normally these would be expressed with .cfi_escape, however this would make the CFI unreadable and makes it difficult to update registers in CFI instructions (also something AMDGPU requires). Authored-by: Emma Pilkington --- llvm/include/llvm/MC/MCDwarf.h | 137 +++++++++++++++------------------ 1 file changed, 60 insertions(+), 77 deletions(-) diff --git a/llvm/include/llvm/MC/MCDwarf.h b/llvm/include/llvm/MC/MCDwarf.h index 9944a9a92ab1f..640d2eeb68d61 100644 --- a/llvm/include/llvm/MC/MCDwarf.h +++ b/llvm/include/llvm/MC/MCDwarf.h @@ -29,6 +29,7 @@ #include #include #include +#include #include namespace llvm { @@ -531,67 +532,47 @@ class MCCFIInstruction { OpValOffset, }; + // Held in ExtraFields for most common OpTypes, exceptions follow. + struct CommonFields { + unsigned Register = std::numeric_limits::max(); + int64_t Offset = 0; + unsigned Register2 = std::numeric_limits::max(); + unsigned AddressSpace = 0; + }; + // Held in ExtraFields when OpEscape. + struct EscapeFields { + std::vector Values; + std::string Comment; + }; + // Held in ExtraFields when OpLabel. + struct LabelFields { + MCSymbol *CfiLabel = nullptr; + }; + private: MCSymbol *Label; - union { - struct { - unsigned Register; - int64_t Offset; - } RI; - struct { - unsigned Register; - int64_t Offset; - unsigned AddressSpace; - } RIA; - struct { - unsigned Register; - unsigned Register2; - } RR; - MCSymbol *CfiLabel; - } U; + std::variant ExtraFields; OpType Operation; SMLoc Loc; - std::vector Values; - std::string Comment; - MCCFIInstruction(OpType Op, MCSymbol *L, unsigned R, int64_t O, SMLoc Loc, - StringRef V = "", StringRef Comment = "") - : Label(L), Operation(Op), Loc(Loc), Values(V.begin(), V.end()), - Comment(Comment) { - assert(Op != OpRegister && Op != OpLLVMDefAspaceCfa); - U.RI = {R, O}; - } - MCCFIInstruction(OpType Op, MCSymbol *L, unsigned R1, unsigned R2, SMLoc Loc) - : Label(L), Operation(Op), Loc(Loc) { - assert(Op == OpRegister); - U.RR = {R1, R2}; - } - MCCFIInstruction(OpType Op, MCSymbol *L, unsigned R, int64_t O, unsigned AS, - SMLoc Loc) - : Label(L), Operation(Op), Loc(Loc) { - assert(Op == OpLLVMDefAspaceCfa); - U.RIA = {R, O, AS}; - } - - MCCFIInstruction(OpType Op, MCSymbol *L, MCSymbol *CfiLabel, SMLoc Loc) - : Label(L), Operation(Op), Loc(Loc) { - assert(Op == OpLabel); - U.CfiLabel = CfiLabel; - } + template + MCCFIInstruction(OpType Op, MCSymbol *L, FieldsType &&EF, SMLoc Loc) + : Label(L), ExtraFields(std::forward(EF)), Operation(Op), + Loc(Loc) {} public: /// .cfi_def_cfa defines a rule for computing CFA as: take address from /// Register and add Offset to it. static MCCFIInstruction cfiDefCfa(MCSymbol *L, unsigned Register, int64_t Offset, SMLoc Loc = {}) { - return MCCFIInstruction(OpDefCfa, L, Register, Offset, Loc); + return {OpDefCfa, L, CommonFields{Register, Offset}, Loc}; } /// .cfi_def_cfa_register modifies a rule for computing CFA. From now /// on Register will be used instead of the old one. Offset remains the same. static MCCFIInstruction createDefCfaRegister(MCSymbol *L, unsigned Register, SMLoc Loc = {}) { - return MCCFIInstruction(OpDefCfaRegister, L, Register, INT64_C(0), Loc); + return {OpDefCfaRegister, L, CommonFields{Register}, Loc}; } /// .cfi_def_cfa_offset modifies a rule for computing CFA. Register @@ -599,7 +580,7 @@ class MCCFIInstruction { /// that will be added to a defined register to the compute CFA address. static MCCFIInstruction cfiDefCfaOffset(MCSymbol *L, int64_t Offset, SMLoc Loc = {}) { - return MCCFIInstruction(OpDefCfaOffset, L, 0, Offset, Loc); + return {OpDefCfaOffset, L, CommonFields{0, Offset}, Loc}; } /// .cfi_adjust_cfa_offset Same as .cfi_def_cfa_offset, but @@ -607,7 +588,7 @@ class MCCFIInstruction { /// offset. static MCCFIInstruction createAdjustCfaOffset(MCSymbol *L, int64_t Adjustment, SMLoc Loc = {}) { - return MCCFIInstruction(OpAdjustCfaOffset, L, 0, Adjustment, Loc); + return {OpAdjustCfaOffset, L, CommonFields{0, Adjustment}, Loc}; } // FIXME: Update the remaining docs to use the new proposal wording. @@ -618,15 +599,15 @@ class MCCFIInstruction { int64_t Offset, unsigned AddressSpace, SMLoc Loc) { - return MCCFIInstruction(OpLLVMDefAspaceCfa, L, Register, Offset, - AddressSpace, Loc); + return {OpLLVMDefAspaceCfa, L, + CommonFields{Register, Offset, 0, AddressSpace}, Loc}; } /// .cfi_offset Previous value of Register is saved at offset Offset /// from CFA. static MCCFIInstruction createOffset(MCSymbol *L, unsigned Register, int64_t Offset, SMLoc Loc = {}) { - return MCCFIInstruction(OpOffset, L, Register, Offset, Loc); + return {OpOffset, L, CommonFields{Register, Offset}, Loc}; } /// .cfi_rel_offset Previous value of Register is saved at offset @@ -634,30 +615,30 @@ class MCCFIInstruction { /// using the known displacement of the CFA register from the CFA. static MCCFIInstruction createRelOffset(MCSymbol *L, unsigned Register, int64_t Offset, SMLoc Loc = {}) { - return MCCFIInstruction(OpRelOffset, L, Register, Offset, Loc); + return {OpRelOffset, L, CommonFields{Register, Offset}, Loc}; } /// .cfi_register Previous value of Register1 is saved in /// register Register2. static MCCFIInstruction createRegister(MCSymbol *L, unsigned Register1, unsigned Register2, SMLoc Loc = {}) { - return MCCFIInstruction(OpRegister, L, Register1, Register2, Loc); + return {OpRegister, L, CommonFields{Register1, 0, Register2}, Loc}; } /// .cfi_window_save SPARC register window is saved. static MCCFIInstruction createWindowSave(MCSymbol *L, SMLoc Loc = {}) { - return MCCFIInstruction(OpWindowSave, L, 0, INT64_C(0), Loc); + return {OpWindowSave, L, CommonFields{}, Loc}; } /// .cfi_negate_ra_state AArch64 negate RA state. static MCCFIInstruction createNegateRAState(MCSymbol *L, SMLoc Loc = {}) { - return MCCFIInstruction(OpNegateRAState, L, 0, INT64_C(0), Loc); + return {OpNegateRAState, L, CommonFields{}, Loc}; } /// .cfi_negate_ra_state_with_pc AArch64 negate RA state with PC. static MCCFIInstruction createNegateRAStateWithPC(MCSymbol *L, SMLoc Loc = {}) { - return MCCFIInstruction(OpNegateRAStateWithPC, L, 0, INT64_C(0), Loc); + return {OpNegateRAStateWithPC, L, CommonFields{}, Loc}; } /// .cfi_restore says that the rule for Register is now the same as it @@ -665,104 +646,106 @@ class MCCFIInstruction { /// by .cfi_startproc were executed. static MCCFIInstruction createRestore(MCSymbol *L, unsigned Register, SMLoc Loc = {}) { - return MCCFIInstruction(OpRestore, L, Register, INT64_C(0), Loc); + return {OpRestore, L, CommonFields{Register}, Loc}; } /// .cfi_undefined From now on the previous value of Register can't be /// restored anymore. static MCCFIInstruction createUndefined(MCSymbol *L, unsigned Register, SMLoc Loc = {}) { - return MCCFIInstruction(OpUndefined, L, Register, INT64_C(0), Loc); + return {OpUndefined, L, CommonFields{Register}, Loc}; } /// .cfi_same_value Current value of Register is the same as in the /// previous frame. I.e., no restoration is needed. static MCCFIInstruction createSameValue(MCSymbol *L, unsigned Register, SMLoc Loc = {}) { - return MCCFIInstruction(OpSameValue, L, Register, INT64_C(0), Loc); + return {OpSameValue, L, CommonFields{Register}, Loc}; } /// .cfi_remember_state Save all current rules for all registers. static MCCFIInstruction createRememberState(MCSymbol *L, SMLoc Loc = {}) { - return MCCFIInstruction(OpRememberState, L, 0, INT64_C(0), Loc); + return {OpRememberState, L, CommonFields{}, Loc}; } /// .cfi_restore_state Restore the previously saved state. static MCCFIInstruction createRestoreState(MCSymbol *L, SMLoc Loc = {}) { - return MCCFIInstruction(OpRestoreState, L, 0, INT64_C(0), Loc); + return {OpRestoreState, L, CommonFields{}, Loc}; } /// .cfi_escape Allows the user to add arbitrary bytes to the unwind /// info. static MCCFIInstruction createEscape(MCSymbol *L, StringRef Vals, SMLoc Loc = {}, StringRef Comment = "") { - return MCCFIInstruction(OpEscape, L, 0, 0, Loc, Vals, Comment); + return {OpEscape, L, + EscapeFields{std::vector(Vals.begin(), Vals.end()), + Comment.str()}, + Loc}; } /// A special wrapper for .cfi_escape that indicates GNU_ARGS_SIZE static MCCFIInstruction createGnuArgsSize(MCSymbol *L, int64_t Size, SMLoc Loc = {}) { - return MCCFIInstruction(OpGnuArgsSize, L, 0, Size, Loc); + return {OpGnuArgsSize, L, CommonFields{0, Size}, Loc}; } static MCCFIInstruction createLabel(MCSymbol *L, MCSymbol *CfiLabel, SMLoc Loc) { - return MCCFIInstruction(OpLabel, L, CfiLabel, Loc); + return {OpLabel, L, LabelFields{CfiLabel}, Loc}; } /// .cfi_val_offset Previous value of Register is offset Offset from the /// current CFA register. static MCCFIInstruction createValOffset(MCSymbol *L, unsigned Register, int64_t Offset, SMLoc Loc = {}) { - return MCCFIInstruction(OpValOffset, L, Register, Offset, Loc); + return {OpValOffset, L, CommonFields{Register, Offset}, Loc}; } OpType getOperation() const { return Operation; } MCSymbol *getLabel() const { return Label; } unsigned getRegister() const { - if (Operation == OpRegister) - return U.RR.Register; - if (Operation == OpLLVMDefAspaceCfa) - return U.RIA.Register; assert(Operation == OpDefCfa || Operation == OpOffset || Operation == OpRestore || Operation == OpUndefined || Operation == OpSameValue || Operation == OpDefCfaRegister || - Operation == OpRelOffset || Operation == OpValOffset); - return U.RI.Register; + Operation == OpRelOffset || Operation == OpValOffset || + Operation == OpRegister || Operation == OpLLVMDefAspaceCfa); + return std::get(ExtraFields).Register; } unsigned getRegister2() const { assert(Operation == OpRegister); - return U.RR.Register2; + return std::get(ExtraFields).Register2; } unsigned getAddressSpace() const { assert(Operation == OpLLVMDefAspaceCfa); - return U.RIA.AddressSpace; + return std::get(ExtraFields).AddressSpace; } int64_t getOffset() const { - if (Operation == OpLLVMDefAspaceCfa) - return U.RIA.Offset; assert(Operation == OpDefCfa || Operation == OpOffset || Operation == OpRelOffset || Operation == OpDefCfaOffset || Operation == OpAdjustCfaOffset || Operation == OpGnuArgsSize || - Operation == OpValOffset); - return U.RI.Offset; + Operation == OpValOffset || Operation == OpLLVMDefAspaceCfa); + return std::get(ExtraFields).Offset; } MCSymbol *getCfiLabel() const { assert(Operation == OpLabel); - return U.CfiLabel; + return std::get(ExtraFields).CfiLabel; } StringRef getValues() const { assert(Operation == OpEscape); + auto &Values = std::get(ExtraFields).Values; return StringRef(&Values[0], Values.size()); } - StringRef getComment() const { return Comment; } + StringRef getComment() const { + assert(Operation == OpEscape); + return std::get(ExtraFields).Comment; + } SMLoc getLoc() const { return Loc; } }; From ab2a302f0ee8b31404aa4cc454caee40f46602bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Valentin=20Clement=20=28=E3=83=90=E3=83=AC=E3=83=B3?= =?UTF-8?q?=E3=82=BF=E3=82=A4=E3=83=B3=20=E3=82=AF=E3=83=AC=E3=83=A1?= =?UTF-8?q?=E3=83=B3=29?= Date: Mon, 24 Nov 2025 14:55:02 -0800 Subject: [PATCH 30/50] [flang][cuda] Add support for cluster_dim_blocks in cooperative_groups (#169417) --- .../Optimizer/Builder/CUDAIntrinsicCall.h | 1 + .../Optimizer/Builder/CUDAIntrinsicCall.cpp | 37 +++++++++++++++++++ flang/module/cooperative_groups.f90 | 7 ++++ flang/test/Lower/CUDA/cuda-cluster.cuf | 34 +++++++++++++++++ 4 files changed, 79 insertions(+) create mode 100644 flang/test/Lower/CUDA/cuda-cluster.cuf diff --git a/flang/include/flang/Optimizer/Builder/CUDAIntrinsicCall.h b/flang/include/flang/Optimizer/Builder/CUDAIntrinsicCall.h index 027bd3b79a1df..cedc7a9437eb5 100644 --- a/flang/include/flang/Optimizer/Builder/CUDAIntrinsicCall.h +++ b/flang/include/flang/Optimizer/Builder/CUDAIntrinsicCall.h @@ -47,6 +47,7 @@ struct CUDAIntrinsicLibrary : IntrinsicLibrary { void genBarrierInit(llvm::ArrayRef); mlir::Value genBarrierTryWait(mlir::Type, llvm::ArrayRef); mlir::Value genBarrierTryWaitSleep(mlir::Type, llvm::ArrayRef); + mlir::Value genClusterDimBlocks(mlir::Type, llvm::ArrayRef); void genFenceProxyAsync(llvm::ArrayRef); template fir::ExtendedValue genLDXXFunc(mlir::Type, diff --git a/flang/lib/Optimizer/Builder/CUDAIntrinsicCall.cpp b/flang/lib/Optimizer/Builder/CUDAIntrinsicCall.cpp index c560c53033780..a770e2d9cdeff 100644 --- a/flang/lib/Optimizer/Builder/CUDAIntrinsicCall.cpp +++ b/flang/lib/Optimizer/Builder/CUDAIntrinsicCall.cpp @@ -368,6 +368,11 @@ static constexpr IntrinsicHandler cudaHandlers[]{ &CI::genNVVMTime), {}, /*isElemental=*/false}, + {"cluster_dim_blocks", + static_cast( + &CI::genClusterDimBlocks), + {}, + /*isElemental=*/false}, {"fence_proxy_async", static_cast( &CI::genFenceProxyAsync), @@ -985,6 +990,38 @@ CUDAIntrinsicLibrary::genBarrierTryWaitSleep(mlir::Type resultType, .getResult(0); } +// CLUSTER_DIM_BLOCKS +mlir::Value +CUDAIntrinsicLibrary::genClusterDimBlocks(mlir::Type resultType, + llvm::ArrayRef args) { + assert(args.size() == 0); + auto recTy = mlir::cast(resultType); + assert(recTy && "RecordType expepected"); + mlir::Value res = fir::AllocaOp::create(builder, loc, resultType); + + auto insertDim = [&](mlir::Value dim, unsigned fieldPos) { + auto fieldName = recTy.getTypeList()[fieldPos].first; + mlir::Type fieldTy = recTy.getTypeList()[fieldPos].second; + mlir::Type fieldIndexType = fir::FieldType::get(resultType.getContext()); + mlir::Value fieldIndex = fir::FieldIndexOp::create( + builder, loc, fieldIndexType, fieldName, recTy, + /*typeParams=*/mlir::ValueRange{}); + mlir::Value coord = fir::CoordinateOp::create( + builder, loc, builder.getRefType(fieldTy), res, fieldIndex); + fir::StoreOp::create(builder, loc, dim, coord); + }; + + mlir::Type i32Ty = builder.getI32Type(); + mlir::Value x = mlir::NVVM::ClusterDimBlocksXOp::create(builder, loc, i32Ty); + insertDim(x, 0); + mlir::Value y = mlir::NVVM::ClusterDimBlocksYOp::create(builder, loc, i32Ty); + insertDim(y, 1); + mlir::Value z = mlir::NVVM::ClusterDimBlocksZOp::create(builder, loc, i32Ty); + insertDim(z, 2); + + return res; +} + // FENCE_PROXY_ASYNC void CUDAIntrinsicLibrary::genFenceProxyAsync( llvm::ArrayRef args) { diff --git a/flang/module/cooperative_groups.f90 b/flang/module/cooperative_groups.f90 index 1c89866f9c84a..2631975837a5b 100644 --- a/flang/module/cooperative_groups.f90 +++ b/flang/module/cooperative_groups.f90 @@ -38,6 +38,13 @@ module cooperative_groups integer(4) :: rank end type thread_group +interface + attributes(device) function cluster_dim_blocks() + import + type(dim3) :: cluster_dim_blocks + end function +end interface + interface attributes(device) function this_cluster() import diff --git a/flang/test/Lower/CUDA/cuda-cluster.cuf b/flang/test/Lower/CUDA/cuda-cluster.cuf new file mode 100644 index 0000000000000..51cc4208a35de --- /dev/null +++ b/flang/test/Lower/CUDA/cuda-cluster.cuf @@ -0,0 +1,34 @@ +! RUN: bbc -emit-hlfir -fcuda %s -o - | FileCheck %s + +attributes(global) subroutine test_this_cluster() + use cooperative_groups + type(cluster_group) :: cluster + + cluster = this_cluster() +end subroutine + +! CHECK-LABEL: func.func @_QPtest_this_cluster() attributes {cuf.proc_attr = #cuf.cuda_proc} +! CHECK: %{{.*}} = fir.alloca !fir.type<_QMcooperative_groupsTcluster_group +! CHECK: %[[RES:.*]] = fir.alloca !fir.type<_QMcooperative_groupsTcluster_group{_QMcooperative_groupsTcluster_group.handle:!fir.type<_QM__fortran_builtinsT__builtin_c_devptr{cptr:!fir.type<_QM__fortran_builtinsT__builtin_c_ptr{__address:i64}>}>,size:i32,rank:i32}> +! CHECK: %[[RANK:.*]] = nvvm.read.ptx.sreg.cluster.ctarank : i32 +! CHECK: %[[RANK_1:.*]] = arith.addi %[[RANK]], %c1{{.*}} : i32 +! CHECK: %[[RANK_COORD:.*]] = fir.coordinate_of %[[RES]], rank : (!fir.ref}>,size:i32,rank:i32}>>) -> !fir.ref +! CHECK: fir.store %[[RANK_1]] to %[[RANK_COORD]] : !fir.ref + +attributes(global) subroutine test_cluster_dim_blocks() + use cooperative_groups + type(dim3) :: clusterDim + + clusterDim = cluster_dim_blocks() +end subroutine + +! CHECK-LABEL: func.func @_QPtest_cluster_dim_blocks() attributes {cuf.proc_attr = #cuf.cuda_proc} +! CHECK: %[[X:.*]] = nvvm.read.ptx.sreg.cluster.nctaid.x : i32 +! CHECK: %[[COORD_X:.*]] = fir.coordinate_of %{{.*}}, x : (!fir.ref>) -> !fir.ref +! CHECK: fir.store %[[X]] to %[[COORD_X]] : !fir.ref +! CHECK: %[[Y:.*]] = nvvm.read.ptx.sreg.cluster.nctaid.y : i32 +! CHECK: %[[COORD_Y:.*]] = fir.coordinate_of %{{.*}}, y : (!fir.ref>) -> !fir.ref +! CHECK: fir.store %[[Y]] to %[[COORD_Y]] : !fir.ref +! CHECK: %[[Z:.*]] = nvvm.read.ptx.sreg.cluster.nctaid.z : i32 +! CHECK: %[[COORD_Z:.*]] = fir.coordinate_of %{{.*}}, z : (!fir.ref>) -> !fir.ref +! CHECK: fir.store %[[Z]] to %[[COORD_Z]] : !fir.ref From 420f62e05cc8c54253f52bb99f9b44ad5b9c4f89 Mon Sep 17 00:00:00 2001 From: Christopher Ferris Date: Mon, 24 Nov 2025 15:03:08 -0800 Subject: [PATCH 31/50] [scudo] Only print stats when the test fails. (#168000) When running the tests on other platforms, printing the stats on all of the passing tests makes it hard to see failure output. Therefore, this change only prints the stats if the test actually fails. --- .../scudo/standalone/tests/combined_test.cpp | 6 ++-- .../scudo/standalone/tests/primary_test.cpp | 36 +++++++++++-------- .../standalone/tests/quarantine_test.cpp | 16 +++++---- .../standalone/tests/size_class_map_test.cpp | 4 ++- 4 files changed, 39 insertions(+), 23 deletions(-) diff --git a/compiler-rt/lib/scudo/standalone/tests/combined_test.cpp b/compiler-rt/lib/scudo/standalone/tests/combined_test.cpp index 4837ac96b9b26..1d4208b6a2aa0 100644 --- a/compiler-rt/lib/scudo/standalone/tests/combined_test.cpp +++ b/compiler-rt/lib/scudo/standalone/tests/combined_test.cpp @@ -326,8 +326,10 @@ void ScudoCombinedTest::BasicTest(scudo::uptr SizeLog) { } } - Allocator->printStats(); - Allocator->printFragmentationInfo(); + if (TEST_HAS_FAILURE) { + Allocator->printStats(); + Allocator->printFragmentationInfo(); + } } #define SCUDO_MAKE_BASIC_TEST(SizeLog) \ diff --git a/compiler-rt/lib/scudo/standalone/tests/primary_test.cpp b/compiler-rt/lib/scudo/standalone/tests/primary_test.cpp index 1f5df28fd7771..3a087c497b1a9 100644 --- a/compiler-rt/lib/scudo/standalone/tests/primary_test.cpp +++ b/compiler-rt/lib/scudo/standalone/tests/primary_test.cpp @@ -230,9 +230,11 @@ SCUDO_TYPED_TEST(ScudoPrimaryTest, BasicPrimary) { } SizeClassAllocator.destroy(nullptr); Allocator->releaseToOS(scudo::ReleaseToOS::Force); - scudo::ScopedString Str; - Allocator->getStats(&Str); - Str.output(); + if (TEST_HAS_FAILURE) { + scudo::ScopedString Str; + Allocator->getStats(&Str); + Str.output(); + } } struct SmallRegionsConfig { @@ -289,10 +291,12 @@ TEST(ScudoPrimaryTest, Primary64OOM) { SizeClassAllocator.destroy(nullptr); Allocator.releaseToOS(scudo::ReleaseToOS::Force); - scudo::ScopedString Str; - Allocator.getStats(&Str); - Str.output(); EXPECT_EQ(AllocationFailed, true); + if (TEST_HAS_FAILURE) { + scudo::ScopedString Str; + Allocator.getStats(&Str); + Str.output(); + } Allocator.unmapTestOnly(); } @@ -328,9 +332,11 @@ SCUDO_TYPED_TEST(ScudoPrimaryTest, PrimaryIterate) { } SizeClassAllocator.destroy(nullptr); Allocator->releaseToOS(scudo::ReleaseToOS::Force); - scudo::ScopedString Str; - Allocator->getStats(&Str); - Str.output(); + if (TEST_HAS_FAILURE) { + scudo::ScopedString Str; + Allocator->getStats(&Str); + Str.output(); + } } SCUDO_TYPED_TEST(ScudoPrimaryTest, PrimaryThreaded) { @@ -385,11 +391,13 @@ SCUDO_TYPED_TEST(ScudoPrimaryTest, PrimaryThreaded) { for (auto &T : Threads) T.join(); Allocator->releaseToOS(scudo::ReleaseToOS::Force); - scudo::ScopedString Str; - Allocator->getStats(&Str); - Allocator->getFragmentationInfo(&Str); - Allocator->getMemoryGroupFragmentationInfo(&Str); - Str.output(); + if (TEST_HAS_FAILURE) { + scudo::ScopedString Str; + Allocator->getStats(&Str); + Allocator->getFragmentationInfo(&Str); + Allocator->getMemoryGroupFragmentationInfo(&Str); + Str.output(); + } } // Through a simple allocation that spans two pages, verify that releaseToOS diff --git a/compiler-rt/lib/scudo/standalone/tests/quarantine_test.cpp b/compiler-rt/lib/scudo/standalone/tests/quarantine_test.cpp index 54d42edc374e5..e3e983be54574 100644 --- a/compiler-rt/lib/scudo/standalone/tests/quarantine_test.cpp +++ b/compiler-rt/lib/scudo/standalone/tests/quarantine_test.cpp @@ -216,9 +216,11 @@ TEST(ScudoQuarantineTest, GlobalQuarantine) { Quarantine.drainAndRecycle(&Cache, Cb); EXPECT_EQ(Cache.getSize(), 0UL); - scudo::ScopedString Str; - Quarantine.getStats(&Str); - Str.output(); + if (TEST_HAS_FAILURE) { + scudo::ScopedString Str; + Quarantine.getStats(&Str); + Str.output(); + } } struct PopulateQuarantineThread { @@ -248,9 +250,11 @@ TEST(ScudoQuarantineTest, ThreadedGlobalQuarantine) { for (scudo::uptr I = 0; I < NumberOfThreads; I++) pthread_join(T[I].Thread, 0); - scudo::ScopedString Str; - Quarantine.getStats(&Str); - Str.output(); + if (TEST_HAS_FAILURE) { + scudo::ScopedString Str; + Quarantine.getStats(&Str); + Str.output(); + } for (scudo::uptr I = 0; I < NumberOfThreads; I++) Quarantine.drainAndRecycle(&T[I].Cache, Cb); diff --git a/compiler-rt/lib/scudo/standalone/tests/size_class_map_test.cpp b/compiler-rt/lib/scudo/standalone/tests/size_class_map_test.cpp index 05b5835ff0bb6..73b2823e4c9d1 100644 --- a/compiler-rt/lib/scudo/standalone/tests/size_class_map_test.cpp +++ b/compiler-rt/lib/scudo/standalone/tests/size_class_map_test.cpp @@ -12,8 +12,10 @@ template void testSizeClassMap() { typedef SizeClassMap SCMap; - scudo::printMap(); scudo::validateMap(); + if (TEST_HAS_FAILURE) { + scudo::printMap(); + } } TEST(ScudoSizeClassMapTest, DefaultSizeClassMap) { From d9cf0db2a26245394a1722f688f520e745358373 Mon Sep 17 00:00:00 2001 From: Walter Lee <49250218+googlewalt@users.noreply.github.com> Date: Mon, 24 Nov 2025 23:15:57 +0000 Subject: [PATCH 32/50] Fix path to aligned_alloc.h in #include statement (#169418) This fixes #166172. --- libcxx/src/new.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcxx/src/new.cpp b/libcxx/src/new.cpp index ce6b63775ce9c..70cdab683a861 100644 --- a/libcxx/src/new.cpp +++ b/libcxx/src/new.cpp @@ -6,9 +6,9 @@ // //===----------------------------------------------------------------------===// +#include "include/aligned_alloc.h" #include "include/overridable_function.h" #include <__assert> -#include <__memory/aligned_alloc.h> #include #include #include From 73de1e26b4500f4ffd97c52922b0d45308d54f6d Mon Sep 17 00:00:00 2001 From: Lang Hames Date: Tue, 25 Nov 2025 10:46:55 +1100 Subject: [PATCH 33/50] Orc fix waitingongraph coalescer remove (#169287) --- .../llvm/ExecutionEngine/Orc/WaitingOnGraph.h | 27 ++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/llvm/include/llvm/ExecutionEngine/Orc/WaitingOnGraph.h b/llvm/include/llvm/ExecutionEngine/Orc/WaitingOnGraph.h index 9f14c8b2efd5f..a7ba79164c471 100644 --- a/llvm/include/llvm/ExecutionEngine/Orc/WaitingOnGraph.h +++ b/llvm/include/llvm/ExecutionEngine/Orc/WaitingOnGraph.h @@ -155,22 +155,20 @@ template class WaitingOnGraph { } template void remove(Pred &&Remove) { + std::vector HashesToErase; for (auto &[Hash, SNs] : CanonicalSNs) { - bool Found = false; - for (size_t I = 0; I != SNs.size(); ++I) { + for (size_t I = 0; I != SNs.size();) { if (Remove(SNs[I])) { std::swap(SNs[I], SNs.back()); SNs.pop_back(); - Found = true; - break; - } - } - if (Found) { - if (SNs.empty()) - CanonicalSNs.erase(Hash); - break; + } else + ++I; } + if (SNs.empty()) + HashesToErase.push_back(Hash); } + for (auto Hash : HashesToErase) + CanonicalSNs.erase(Hash); } private: @@ -396,9 +394,14 @@ template class WaitingOnGraph { ++I; } + CoalesceToPendingSNs.remove([&](SuperNode *SN) { + for (auto &E : FailedSNs) + if (E.get() == SN) + return true; + return false; + }); + for (auto &SN : FailedSNs) { - CoalesceToPendingSNs.remove( - [&](SuperNode *SNC) { return SNC == SN.get(); }); for (auto &[Container, Elems] : SN->Defs) { assert(ElemToPendingSN.count(Container)); auto &CElems = ElemToPendingSN[Container]; From a8a504a08d14b7e855af7616a2663f25508cc184 Mon Sep 17 00:00:00 2001 From: Matt Arsenault Date: Mon, 24 Nov 2025 18:57:46 -0500 Subject: [PATCH 34/50] RuntimeLibcalls: Add definitions for vector math functions (#167026) This is mostly the output of a vibe coded script running on VecFuncs.def, with a lot of manual cleanups and fixing where the vibes were off. This is not yet wired up to anything (except for the handful of calls which are already manually enabled). In the future the SystemLibrary mechanism needs to be generalized to allow plugging these sets in based on the flag. One annoying piece is there are some name conflicts across the libraries. Some of the libmvec functions have name collisions with some sleef functions. I solved this by just adding a prefix to the libmvec functions. It would probably be a good idea to add a prefix to every group. It gets ugly, particularly since some of the sleef functions started to use a Sleef_ prefix, but mostly do not. --- llvm/include/llvm/IR/RuntimeLibcalls.td | 1028 +++++++++++++++++++++-- 1 file changed, 980 insertions(+), 48 deletions(-) diff --git a/llvm/include/llvm/IR/RuntimeLibcalls.td b/llvm/include/llvm/IR/RuntimeLibcalls.td index ce7e836f66446..b40b7f199f9e5 100644 --- a/llvm/include/llvm/IR/RuntimeLibcalls.td +++ b/llvm/include/llvm/IR/RuntimeLibcalls.td @@ -182,10 +182,63 @@ foreach FPTy = ["F32", "F64", "F80", "F128", "PPCF128"] in { def MODF_#FPTy : RuntimeLibcall; } -foreach VecTy = ["V4F32", "V2F64", "NXV4F32", "NXV2F64"] in { - def MODF_#VecTy : RuntimeLibcall; - def SINCOS_#VecTy : RuntimeLibcall; - def SINCOSPI_#VecTy : RuntimeLibcall; +defvar F32VectorSuffixes = ["V2F32", "V4F32", "V8F32", "V16F32", "NXV4F32"]; +defvar F64VectorSuffixes = ["V2F64", "V4F64", "V8F64", "NXV2F64"]; + +foreach S = !listconcat(F32VectorSuffixes, F64VectorSuffixes) in { + def ACOS_#S : RuntimeLibcall; + def ACOSH_#S : RuntimeLibcall; + def ASIN_#S : RuntimeLibcall; + def ASINH_#S : RuntimeLibcall; + def ATAN_#S : RuntimeLibcall; + def ATAN2_#S : RuntimeLibcall; + def ATANH_#S : RuntimeLibcall; + def CBRT_#S : RuntimeLibcall; + def CEIL_#S : RuntimeLibcall; + def COPYSIGN_#S : RuntimeLibcall; + def COS_#S : RuntimeLibcall; + def COSH_#S : RuntimeLibcall; + def COSPI_#S : RuntimeLibcall; + def ERFC_#S : RuntimeLibcall; + def ERF_#S : RuntimeLibcall; + def EXP_#S : RuntimeLibcall; + def EXP_FINITE_#S : RuntimeLibcall; + def EXP10_#S : RuntimeLibcall; + def EXP2_#S : RuntimeLibcall; + def EXPM1_#S : RuntimeLibcall; + def FABS_#S : RuntimeLibcall; + def FDIM_#S : RuntimeLibcall; + def FLOOR_#S : RuntimeLibcall; + def FMA_#S : RuntimeLibcall; + def FMAX_#S : RuntimeLibcall; + def FMIN_#S : RuntimeLibcall; + def FMOD_#S : RuntimeLibcall; + def HYPOT_#S : RuntimeLibcall; + def ILOGB_#S : RuntimeLibcall; + def LDEXP_#S : RuntimeLibcall; + def LGAMMA_#S : RuntimeLibcall; + def LOG_#S : RuntimeLibcall; + def LOG10_#S : RuntimeLibcall; + def LOG1P_#S : RuntimeLibcall; + def LOG2_#S : RuntimeLibcall; + def LOGB_#S : RuntimeLibcall; + def MODF_#S : RuntimeLibcall; + def NEXTAFTER_#S : RuntimeLibcall; + def POW_#S : RuntimeLibcall; + def SINCOS_#S : RuntimeLibcall; + def SINCOSPI_#S : RuntimeLibcall; + def SIN_#S : RuntimeLibcall; + def SINH_#S : RuntimeLibcall; + def SINPI_#S : RuntimeLibcall; + def SQRT_#S : RuntimeLibcall; + def TAN_#S : RuntimeLibcall; + def TANH_#S : RuntimeLibcall; + def TGAMMA_#S : RuntimeLibcall; +} + +foreach S = F64VectorSuffixes in { + def LOG_FINITE_#S : RuntimeLibcall; + def POW_FINITE_#S : RuntimeLibcall; } def FEGETENV : RuntimeLibcall; @@ -1089,50 +1142,6 @@ def __security_check_cookie : RuntimeLibcallImpl; def __security_check_cookie_arm64ec : RuntimeLibcallImpl; -//===----------------------------------------------------------------------===// -// sleef calls -//===----------------------------------------------------------------------===// - -defset list SleefLibcalls = { - def _ZGVnN2vl8_modf : RuntimeLibcallImpl; - def _ZGVnN4vl4_modff : RuntimeLibcallImpl; - def _ZGVsNxvl8_modf : RuntimeLibcallImpl; - def _ZGVsNxvl4_modff : RuntimeLibcallImpl; - - def _ZGVnN2vl8l8_sincos : RuntimeLibcallImpl; - def _ZGVnN4vl4l4_sincosf : RuntimeLibcallImpl; - def _ZGVsNxvl8l8_sincos : RuntimeLibcallImpl; - def _ZGVsNxvl4l4_sincosf : RuntimeLibcallImpl; - - def _ZGVnN4vl4l4_sincospif : RuntimeLibcallImpl; - def _ZGVnN2vl8l8_sincospi : RuntimeLibcallImpl; - def _ZGVsNxvl4l4_sincospif : RuntimeLibcallImpl; - def _ZGVsNxvl8l8_sincospi : RuntimeLibcallImpl; -} - -//===----------------------------------------------------------------------===// -// ARMPL calls -//===----------------------------------------------------------------------===// - -defset list ARMPLLibcalls = { - def armpl_vmodfq_f64 : RuntimeLibcallImpl; // CallingConv::AArch64_VectorCall - def armpl_vmodfq_f32 : RuntimeLibcallImpl; // CallingConv::AArch64_VectorCall - def armpl_svmodf_f64_x : RuntimeLibcallImpl; - def armpl_svmodf_f32_x : RuntimeLibcallImpl; - - def armpl_vsincosq_f64 - : RuntimeLibcallImpl; // CallingConv::AArch64_VectorCall - def armpl_vsincosq_f32 - : RuntimeLibcallImpl; // CallingConv::AArch64_VectorCall - def armpl_svsincos_f64_x : RuntimeLibcallImpl; - def armpl_svsincos_f32_x : RuntimeLibcallImpl; - - def armpl_vsincospiq_f32 : RuntimeLibcallImpl; - def armpl_vsincospiq_f64 : RuntimeLibcallImpl; - def armpl_svsincospi_f32_x : RuntimeLibcallImpl; - def armpl_svsincospi_f64_x : RuntimeLibcallImpl; -} - //===----------------------------------------------------------------------===// // F128 libm Runtime Libcalls //===----------------------------------------------------------------------===// @@ -2769,3 +2778,926 @@ def LegacyDefaultSystemLibrary LibcallImpls<(add Int128RTLibcalls), isArch64Bit>, DefaultStackProtector )>; + +//===----------------------------------------------------------------------===// +// Vector math libraries +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Accelerate framework functions +//===----------------------------------------------------------------------===// + +defset list ACCELERATE_VECFUNCS = { + def vacosf : RuntimeLibcallImpl; + def vacoshf : RuntimeLibcallImpl; + def vasinf : RuntimeLibcallImpl; + def vasinhf : RuntimeLibcallImpl; + def vatan2f : RuntimeLibcallImpl; + def vatanf : RuntimeLibcallImpl; + def vatanhf : RuntimeLibcallImpl; + def vceilf : RuntimeLibcallImpl; + def vcosf : RuntimeLibcallImpl; + def vcoshf : RuntimeLibcallImpl; + def vexpf : RuntimeLibcallImpl; + def vexpm1f : RuntimeLibcallImpl; + def vfabsf : RuntimeLibcallImpl; + def vfloorf : RuntimeLibcallImpl; + def vlog10f : RuntimeLibcallImpl; + def vlog1pf : RuntimeLibcallImpl; + def vlogbf : RuntimeLibcallImpl; + def vlogf : RuntimeLibcallImpl; + def vsinf : RuntimeLibcallImpl; + def vsinhf : RuntimeLibcallImpl; + def vsqrtf : RuntimeLibcallImpl; + def vtanf : RuntimeLibcallImpl; + def vtanhf : RuntimeLibcallImpl; +} + +//===----------------------------------------------------------------------===// +// Darwin_libsystem_m vector functions +//===----------------------------------------------------------------------===// + +defset list DARWIN_LIBSYSTEM_M_VECFUNCS = { + def _simd_acos_d2 : RuntimeLibcallImpl; + def _simd_acos_f4 : RuntimeLibcallImpl; + def _simd_acosh_d2 : RuntimeLibcallImpl; + def _simd_acosh_f4 : RuntimeLibcallImpl; + def _simd_asin_d2 : RuntimeLibcallImpl; + def _simd_asin_f4 : RuntimeLibcallImpl; + def _simd_asinh_d2 : RuntimeLibcallImpl; + def _simd_asinh_f4 : RuntimeLibcallImpl; + def _simd_atan2_d2 : RuntimeLibcallImpl; + def _simd_atan2_f4 : RuntimeLibcallImpl; + def _simd_atan_d2 : RuntimeLibcallImpl; + def _simd_atan_f4 : RuntimeLibcallImpl; + def _simd_atanh_d2 : RuntimeLibcallImpl; + def _simd_atanh_f4 : RuntimeLibcallImpl; + def _simd_cbrt_d2 : RuntimeLibcallImpl; + def _simd_cbrt_f4 : RuntimeLibcallImpl; + def _simd_cos_d2 : RuntimeLibcallImpl; + def _simd_cos_f4 : RuntimeLibcallImpl; + def _simd_cosh_d2 : RuntimeLibcallImpl; + def _simd_cosh_f4 : RuntimeLibcallImpl; + def _simd_erf_d2 : RuntimeLibcallImpl; + def _simd_erf_f4 : RuntimeLibcallImpl; + def _simd_exp_d2 : RuntimeLibcallImpl; + def _simd_exp_f4 : RuntimeLibcallImpl; + def _simd_pow_d2 : RuntimeLibcallImpl; + def _simd_pow_f4 : RuntimeLibcallImpl; + def _simd_sin_d2 : RuntimeLibcallImpl; + def _simd_sin_f4 : RuntimeLibcallImpl; + def _simd_sinh_d2 : RuntimeLibcallImpl; + def _simd_sinh_f4 : RuntimeLibcallImpl; + def _simd_tan_d2 : RuntimeLibcallImpl; + def _simd_tan_f4 : RuntimeLibcallImpl; + def _simd_tanh_d2 : RuntimeLibcallImpl; + def _simd_tanh_f4 : RuntimeLibcallImpl; +} + +//===----------------------------------------------------------------------===// +// GLIBC Vector Math library LIBMVEC functions +//===----------------------------------------------------------------------===// + +defvar LIBMVECPrefix = "LIBMVEC_"; + +class LibmvecLibcall + : RuntimeLibcallImpl; + +defset list LIBMVEC_X86_VECFUNCS = { + def LIBMVEC__ZGVbN2v___exp_finite : LibmvecLibcall; + def LIBMVEC__ZGVbN2v___log_finite : LibmvecLibcall; + def LIBMVEC__ZGVbN2v_cos : LibmvecLibcall; + def LIBMVEC__ZGVbN2v_exp : LibmvecLibcall; + def LIBMVEC__ZGVbN2v_log : LibmvecLibcall; + def LIBMVEC__ZGVbN2v_sin : LibmvecLibcall; + def LIBMVEC__ZGVbN2v_tan : LibmvecLibcall; + def LIBMVEC__ZGVbN2vv___pow_finite : LibmvecLibcall; + def LIBMVEC__ZGVbN2vv_pow : LibmvecLibcall; + def LIBMVEC__ZGVbN4v___expf_finite : LibmvecLibcall; + def LIBMVEC__ZGVbN4v___logf_finite : LibmvecLibcall; + def LIBMVEC__ZGVbN4v_cosf : LibmvecLibcall; + def LIBMVEC__ZGVbN4v_expf : LibmvecLibcall; + def LIBMVEC__ZGVbN4v_logf : LibmvecLibcall; + def LIBMVEC__ZGVbN4v_sinf : LibmvecLibcall; + def LIBMVEC__ZGVbN4v_tanf : LibmvecLibcall; + def LIBMVEC__ZGVbN4vv___powf_finite : LibmvecLibcall; + def LIBMVEC__ZGVbN4vv_powf : LibmvecLibcall; + def LIBMVEC__ZGVdN4v___exp_finite : LibmvecLibcall; + def LIBMVEC__ZGVdN4v___log_finite : LibmvecLibcall; + def LIBMVEC__ZGVdN4v_cos : LibmvecLibcall; + def LIBMVEC__ZGVdN4v_exp : LibmvecLibcall; + def LIBMVEC__ZGVdN4v_log : LibmvecLibcall; + def LIBMVEC__ZGVdN4v_sin : LibmvecLibcall; + def LIBMVEC__ZGVdN4v_tan : LibmvecLibcall; + def LIBMVEC__ZGVdN4vv___pow_finite : LibmvecLibcall; + def LIBMVEC__ZGVdN4vv_pow : LibmvecLibcall; + def LIBMVEC__ZGVdN8v___expf_finite : LibmvecLibcall; + def LIBMVEC__ZGVdN8v___logf_finite : LibmvecLibcall; + def LIBMVEC__ZGVdN8v_cosf : LibmvecLibcall; + def LIBMVEC__ZGVdN8v_expf : LibmvecLibcall; + def LIBMVEC__ZGVdN8v_logf : LibmvecLibcall; + def LIBMVEC__ZGVdN8v_sinf : LibmvecLibcall; + def LIBMVEC__ZGVdN8v_tanf : LibmvecLibcall; + def LIBMVEC__ZGVdN8vv___powf_finite : LibmvecLibcall; + def LIBMVEC__ZGVdN8vv_powf : LibmvecLibcall; +} + +defset list LIBMVEC_AARCH64_VECFUNCS = { + def LIBMVEC__ZGVnN2v_acos : LibmvecLibcall; + def LIBMVEC__ZGVnN2v_acosf : LibmvecLibcall; + def LIBMVEC__ZGVnN2v_acosh : LibmvecLibcall; + def LIBMVEC__ZGVnN2v_acoshf : LibmvecLibcall; + def LIBMVEC__ZGVnN2v_asin : LibmvecLibcall; + def LIBMVEC__ZGVnN2v_asinf : LibmvecLibcall; + def LIBMVEC__ZGVnN2v_asinh : LibmvecLibcall; + def LIBMVEC__ZGVnN2v_asinhf : LibmvecLibcall; + def LIBMVEC__ZGVnN2v_atan : LibmvecLibcall; + def LIBMVEC__ZGVnN2v_atanf : LibmvecLibcall; + def LIBMVEC__ZGVnN2v_atanh : LibmvecLibcall; + def LIBMVEC__ZGVnN2v_atanhf : LibmvecLibcall; + def LIBMVEC__ZGVnN2v_cbrt : LibmvecLibcall; + def LIBMVEC__ZGVnN2v_cbrtf : LibmvecLibcall; + def LIBMVEC__ZGVnN2v_cos : LibmvecLibcall; + def LIBMVEC__ZGVnN2v_cosf : LibmvecLibcall; + def LIBMVEC__ZGVnN2v_cosh : LibmvecLibcall; + def LIBMVEC__ZGVnN2v_coshf : LibmvecLibcall; + def LIBMVEC__ZGVnN2v_erf : LibmvecLibcall; + def LIBMVEC__ZGVnN2v_erfc : LibmvecLibcall; + def LIBMVEC__ZGVnN2v_erfcf : LibmvecLibcall; + def LIBMVEC__ZGVnN2v_erff : LibmvecLibcall; + def LIBMVEC__ZGVnN2v_exp : LibmvecLibcall; + def LIBMVEC__ZGVnN2v_exp10 : LibmvecLibcall; + def LIBMVEC__ZGVnN2v_exp10f : LibmvecLibcall; + def LIBMVEC__ZGVnN2v_exp2 : LibmvecLibcall; + def LIBMVEC__ZGVnN2v_exp2f : LibmvecLibcall; + def LIBMVEC__ZGVnN2v_expf : LibmvecLibcall; + def LIBMVEC__ZGVnN2v_expm1 : LibmvecLibcall; + def LIBMVEC__ZGVnN2v_expm1f : LibmvecLibcall; + def LIBMVEC__ZGVnN2v_log : LibmvecLibcall; + def LIBMVEC__ZGVnN2v_log10 : LibmvecLibcall; + def LIBMVEC__ZGVnN2v_log10f : LibmvecLibcall; + def LIBMVEC__ZGVnN2v_log1p : LibmvecLibcall; + def LIBMVEC__ZGVnN2v_log1pf : LibmvecLibcall; + def LIBMVEC__ZGVnN2v_log2 : LibmvecLibcall; + def LIBMVEC__ZGVnN2v_log2f : LibmvecLibcall; + def LIBMVEC__ZGVnN2v_logf : LibmvecLibcall; + def LIBMVEC__ZGVnN2v_sin : LibmvecLibcall; + def LIBMVEC__ZGVnN2v_sinf : LibmvecLibcall; + def LIBMVEC__ZGVnN2v_sinh : LibmvecLibcall; + def LIBMVEC__ZGVnN2v_sinhf : LibmvecLibcall; + def LIBMVEC__ZGVnN2v_tan : LibmvecLibcall; + def LIBMVEC__ZGVnN2v_tanf : LibmvecLibcall; + def LIBMVEC__ZGVnN2v_tanh : LibmvecLibcall; + def LIBMVEC__ZGVnN2v_tanhf : LibmvecLibcall; + def LIBMVEC__ZGVnN2vv_atan2 : LibmvecLibcall; + def LIBMVEC__ZGVnN2vv_atan2f : LibmvecLibcall; + def LIBMVEC__ZGVnN2vv_hypot : LibmvecLibcall; + def LIBMVEC__ZGVnN2vv_hypotf : LibmvecLibcall; + def LIBMVEC__ZGVnN2vv_pow : LibmvecLibcall; + def LIBMVEC__ZGVnN2vv_powf : LibmvecLibcall; + def LIBMVEC__ZGVnN4v_acosf : LibmvecLibcall; + def LIBMVEC__ZGVnN4v_acoshf : LibmvecLibcall; + def LIBMVEC__ZGVnN4v_asinf : LibmvecLibcall; + def LIBMVEC__ZGVnN4v_asinhf : LibmvecLibcall; + def LIBMVEC__ZGVnN4v_atanf : LibmvecLibcall; + def LIBMVEC__ZGVnN4v_atanhf : LibmvecLibcall; + def LIBMVEC__ZGVnN4v_cbrtf : LibmvecLibcall; + def LIBMVEC__ZGVnN4v_cosf : LibmvecLibcall; + def LIBMVEC__ZGVnN4v_coshf : LibmvecLibcall; + def LIBMVEC__ZGVnN4v_erfcf : LibmvecLibcall; + def LIBMVEC__ZGVnN4v_erff : LibmvecLibcall; + def LIBMVEC__ZGVnN4v_exp10f : LibmvecLibcall; + def LIBMVEC__ZGVnN4v_exp2f : LibmvecLibcall; + def LIBMVEC__ZGVnN4v_expf : LibmvecLibcall; + def LIBMVEC__ZGVnN4v_expm1f : LibmvecLibcall; + def LIBMVEC__ZGVnN4v_log10f : LibmvecLibcall; + def LIBMVEC__ZGVnN4v_log1pf : LibmvecLibcall; + def LIBMVEC__ZGVnN4v_log2f : LibmvecLibcall; + def LIBMVEC__ZGVnN4v_logf : LibmvecLibcall; + def LIBMVEC__ZGVnN4v_sinf : LibmvecLibcall; + def LIBMVEC__ZGVnN4v_sinhf : LibmvecLibcall; + def LIBMVEC__ZGVnN4v_tanf : LibmvecLibcall; + def LIBMVEC__ZGVnN4v_tanhf : LibmvecLibcall; + def LIBMVEC__ZGVnN4vv_atan2f : LibmvecLibcall; + def LIBMVEC__ZGVnN4vv_hypotf : LibmvecLibcall; + def LIBMVEC__ZGVnN4vv_powf : LibmvecLibcall; + def LIBMVEC__ZGVsMxv_acos : LibmvecLibcall; + def LIBMVEC__ZGVsMxv_acosf : LibmvecLibcall; + def LIBMVEC__ZGVsMxv_acosh : LibmvecLibcall; + def LIBMVEC__ZGVsMxv_acoshf : LibmvecLibcall; + def LIBMVEC__ZGVsMxv_asin : LibmvecLibcall; + def LIBMVEC__ZGVsMxv_asinf : LibmvecLibcall; + def LIBMVEC__ZGVsMxv_asinh : LibmvecLibcall; + def LIBMVEC__ZGVsMxv_asinhf : LibmvecLibcall; + def LIBMVEC__ZGVsMxv_atan : LibmvecLibcall; + def LIBMVEC__ZGVsMxv_atanf : LibmvecLibcall; + def LIBMVEC__ZGVsMxv_atanh : LibmvecLibcall; + def LIBMVEC__ZGVsMxv_atanhf : LibmvecLibcall; + def LIBMVEC__ZGVsMxv_cbrt : LibmvecLibcall; + def LIBMVEC__ZGVsMxv_cbrtf : LibmvecLibcall; + def LIBMVEC__ZGVsMxv_cos : LibmvecLibcall; + def LIBMVEC__ZGVsMxv_cosf : LibmvecLibcall; + def LIBMVEC__ZGVsMxv_cosh : LibmvecLibcall; + def LIBMVEC__ZGVsMxv_coshf : LibmvecLibcall; + def LIBMVEC__ZGVsMxv_erf : LibmvecLibcall; + def LIBMVEC__ZGVsMxv_erfc : LibmvecLibcall; + def LIBMVEC__ZGVsMxv_erfcf : LibmvecLibcall; + def LIBMVEC__ZGVsMxv_erff : LibmvecLibcall; + def LIBMVEC__ZGVsMxv_exp : LibmvecLibcall; + def LIBMVEC__ZGVsMxv_exp10 : LibmvecLibcall; + def LIBMVEC__ZGVsMxv_exp10f : LibmvecLibcall; + def LIBMVEC__ZGVsMxv_exp2 : LibmvecLibcall; + def LIBMVEC__ZGVsMxv_exp2f : LibmvecLibcall; + def LIBMVEC__ZGVsMxv_expf : LibmvecLibcall; + def LIBMVEC__ZGVsMxv_expm1 : LibmvecLibcall; + def LIBMVEC__ZGVsMxv_expm1f : LibmvecLibcall; + def LIBMVEC__ZGVsMxv_log : LibmvecLibcall; + def LIBMVEC__ZGVsMxv_log10 : LibmvecLibcall; + def LIBMVEC__ZGVsMxv_log10f : LibmvecLibcall; + def LIBMVEC__ZGVsMxv_log1p : LibmvecLibcall; + def LIBMVEC__ZGVsMxv_log1pf : LibmvecLibcall; + def LIBMVEC__ZGVsMxv_log2 : LibmvecLibcall; + def LIBMVEC__ZGVsMxv_log2f : LibmvecLibcall; + def LIBMVEC__ZGVsMxv_logf : LibmvecLibcall; + def LIBMVEC__ZGVsMxv_sin : LibmvecLibcall; + def LIBMVEC__ZGVsMxv_sinf : LibmvecLibcall; + def LIBMVEC__ZGVsMxv_sinh : LibmvecLibcall; + def LIBMVEC__ZGVsMxv_sinhf : LibmvecLibcall; + def LIBMVEC__ZGVsMxv_tan : LibmvecLibcall; + def LIBMVEC__ZGVsMxv_tanf : LibmvecLibcall; + def LIBMVEC__ZGVsMxv_tanh : LibmvecLibcall; + def LIBMVEC__ZGVsMxv_tanhf : LibmvecLibcall; + def LIBMVEC__ZGVsMxvv_atan2 : LibmvecLibcall; + def LIBMVEC__ZGVsMxvv_atan2f : LibmvecLibcall; + def LIBMVEC__ZGVsMxvv_hypot : LibmvecLibcall; + def LIBMVEC__ZGVsMxvv_hypotf : LibmvecLibcall; + def LIBMVEC__ZGVsMxvv_pow : LibmvecLibcall; + def LIBMVEC__ZGVsMxvv_powf : LibmvecLibcall; +} + +//===----------------------------------------------------------------------===// +// IBM MASS vector library (MASSV) functions +//===----------------------------------------------------------------------===// + +defset list MASSV_VECFUNCS = { + def __acosd2 : RuntimeLibcallImpl; + def __acosf4 : RuntimeLibcallImpl; + def __acoshd2 : RuntimeLibcallImpl; + def __acoshf4 : RuntimeLibcallImpl; + def __asind2 : RuntimeLibcallImpl; + def __asinf4 : RuntimeLibcallImpl; + def __asinhd2 : RuntimeLibcallImpl; + def __asinhf4 : RuntimeLibcallImpl; + def __atan2d2 : RuntimeLibcallImpl; + def __atan2f4 : RuntimeLibcallImpl; + def __atand2 : RuntimeLibcallImpl; + def __atanf4 : RuntimeLibcallImpl; + def __atanhd2 : RuntimeLibcallImpl; + def __atanhf4 : RuntimeLibcallImpl; + def __cbrtd2 : RuntimeLibcallImpl; + def __cbrtf4 : RuntimeLibcallImpl; + def __cosd2 : RuntimeLibcallImpl; + def __cosf4 : RuntimeLibcallImpl; + def __coshd2 : RuntimeLibcallImpl; + def __coshf4 : RuntimeLibcallImpl; + def __exp2d2 : RuntimeLibcallImpl; + def __exp2f4 : RuntimeLibcallImpl; + def __expd2 : RuntimeLibcallImpl; + def __expf4 : RuntimeLibcallImpl; + def __expm1d2 : RuntimeLibcallImpl; + def __expm1f4 : RuntimeLibcallImpl; + def __log10d2 : RuntimeLibcallImpl; + def __log10f4 : RuntimeLibcallImpl; + def __log1pd2 : RuntimeLibcallImpl; + def __log1pf4 : RuntimeLibcallImpl; + def __log2d2 : RuntimeLibcallImpl; + def __log2f4 : RuntimeLibcallImpl; + def __logd2 : RuntimeLibcallImpl; + def __logf4 : RuntimeLibcallImpl; + def __powd2 : RuntimeLibcallImpl; + def __powf4 : RuntimeLibcallImpl; + def __sind2 : RuntimeLibcallImpl; + def __sinf4 : RuntimeLibcallImpl; + def __sinhd2 : RuntimeLibcallImpl; + def __sinhf4 : RuntimeLibcallImpl; + def __tand2 : RuntimeLibcallImpl; + def __tanf4 : RuntimeLibcallImpl; + def __tanhd2 : RuntimeLibcallImpl; + def __tanhf4 : RuntimeLibcallImpl; +} + +//===----------------------------------------------------------------------===// +// Intel SVML library functions +//===----------------------------------------------------------------------===// + +defset list SVML_VECFUNCS = { + def __svml_cos2 : RuntimeLibcallImpl; + def __svml_cos4 : RuntimeLibcallImpl; + def __svml_cos8 : RuntimeLibcallImpl; + def __svml_cosf16 : RuntimeLibcallImpl; + def __svml_cosf4 : RuntimeLibcallImpl; + def __svml_cosf8 : RuntimeLibcallImpl; + def __svml_exp2 : RuntimeLibcallImpl; + def __svml_exp22 : RuntimeLibcallImpl; + def __svml_exp24 : RuntimeLibcallImpl; + def __svml_exp28 : RuntimeLibcallImpl; + def __svml_exp2f16 : RuntimeLibcallImpl; + def __svml_exp2f4 : RuntimeLibcallImpl; + def __svml_exp2f8 : RuntimeLibcallImpl; + def __svml_exp4 : RuntimeLibcallImpl; + def __svml_exp8 : RuntimeLibcallImpl; + def __svml_expf16 : RuntimeLibcallImpl; + def __svml_expf4 : RuntimeLibcallImpl; + def __svml_expf8 : RuntimeLibcallImpl; + def __svml_log102 : RuntimeLibcallImpl; + def __svml_log104 : RuntimeLibcallImpl; + def __svml_log108 : RuntimeLibcallImpl; + def __svml_log10f16 : RuntimeLibcallImpl; + def __svml_log10f4 : RuntimeLibcallImpl; + def __svml_log10f8 : RuntimeLibcallImpl; + def __svml_log2 : RuntimeLibcallImpl; + def __svml_log22 : RuntimeLibcallImpl; + def __svml_log24 : RuntimeLibcallImpl; + def __svml_log28 : RuntimeLibcallImpl; + def __svml_log2f16 : RuntimeLibcallImpl; + def __svml_log2f4 : RuntimeLibcallImpl; + def __svml_log2f8 : RuntimeLibcallImpl; + def __svml_log4 : RuntimeLibcallImpl; + def __svml_log8 : RuntimeLibcallImpl; + def __svml_logf16 : RuntimeLibcallImpl; + def __svml_logf4 : RuntimeLibcallImpl; + def __svml_logf8 : RuntimeLibcallImpl; + def __svml_pow2 : RuntimeLibcallImpl; + def __svml_pow4 : RuntimeLibcallImpl; + def __svml_pow8 : RuntimeLibcallImpl; + def __svml_powf16 : RuntimeLibcallImpl; + def __svml_powf4 : RuntimeLibcallImpl; + def __svml_powf8 : RuntimeLibcallImpl; + def __svml_sin2 : RuntimeLibcallImpl; + def __svml_sin4 : RuntimeLibcallImpl; + def __svml_sin8 : RuntimeLibcallImpl; + def __svml_sinf16 : RuntimeLibcallImpl; + def __svml_sinf4 : RuntimeLibcallImpl; + def __svml_sinf8 : RuntimeLibcallImpl; + def __svml_sqrt2 : RuntimeLibcallImpl; + def __svml_sqrt4 : RuntimeLibcallImpl; + def __svml_sqrt8 : RuntimeLibcallImpl; + def __svml_sqrtf16 : RuntimeLibcallImpl; + def __svml_sqrtf4 : RuntimeLibcallImpl; + def __svml_sqrtf8 : RuntimeLibcallImpl; + def __svml_tan2 : RuntimeLibcallImpl; + def __svml_tan4 : RuntimeLibcallImpl; + def __svml_tan8 : RuntimeLibcallImpl; + def __svml_tanf16 : RuntimeLibcallImpl; + def __svml_tanf4 : RuntimeLibcallImpl; + def __svml_tanf8 : RuntimeLibcallImpl; +} + +//===----------------------------------------------------------------------===// +// SIMD Library for Evaluating Elementary Functions +//===----------------------------------------------------------------------===// + +defset list SLEEFGNUABI_VF2_VECFUNCS = { + def _ZGVnN2v_acos : RuntimeLibcallImpl; + def _ZGVnN2v_acosh : RuntimeLibcallImpl; + def _ZGVnN2v_asin : RuntimeLibcallImpl; + def _ZGVnN2v_asinh : RuntimeLibcallImpl; + def _ZGVnN2v_atan : RuntimeLibcallImpl; + def _ZGVnN2v_atanh : RuntimeLibcallImpl; + def _ZGVnN2v_cbrt : RuntimeLibcallImpl; + def _ZGVnN2v_cos : RuntimeLibcallImpl; + def _ZGVnN2v_cosh : RuntimeLibcallImpl; + def _ZGVnN2v_cospi : RuntimeLibcallImpl; + def _ZGVnN2v_erf : RuntimeLibcallImpl; + def _ZGVnN2v_erfc : RuntimeLibcallImpl; + def _ZGVnN2v_exp : RuntimeLibcallImpl; + def _ZGVnN2v_exp10 : RuntimeLibcallImpl; + def _ZGVnN2v_exp2 : RuntimeLibcallImpl; + def _ZGVnN2v_expm1 : RuntimeLibcallImpl; + def _ZGVnN2v_ilogb : RuntimeLibcallImpl; + def _ZGVnN2v_lgamma : RuntimeLibcallImpl; + def _ZGVnN2v_log : RuntimeLibcallImpl; + def _ZGVnN2v_log10 : RuntimeLibcallImpl; + def _ZGVnN2v_log1p : RuntimeLibcallImpl; + def _ZGVnN2v_log2 : RuntimeLibcallImpl; + def _ZGVnN2v_sin : RuntimeLibcallImpl; + def _ZGVnN2v_sinh : RuntimeLibcallImpl; + def _ZGVnN2v_sinpi : RuntimeLibcallImpl; + def _ZGVnN2v_sqrt : RuntimeLibcallImpl; + def _ZGVnN2v_tan : RuntimeLibcallImpl; + def _ZGVnN2v_tanh : RuntimeLibcallImpl; + def _ZGVnN2v_tgamma : RuntimeLibcallImpl; + def _ZGVnN2vl8_modf : RuntimeLibcallImpl; + def _ZGVnN2vl8l8_sincos : RuntimeLibcallImpl; + def _ZGVnN2vl8l8_sincospi : RuntimeLibcallImpl; + def _ZGVnN2vv_atan2 : RuntimeLibcallImpl; + def _ZGVnN2vv_copysign : RuntimeLibcallImpl; + def _ZGVnN2vv_fdim : RuntimeLibcallImpl; + def _ZGVnN2vv_fmax : RuntimeLibcallImpl; + def _ZGVnN2vv_fmin : RuntimeLibcallImpl; + def _ZGVnN2vv_fmod : RuntimeLibcallImpl; + def _ZGVnN2vv_hypot : RuntimeLibcallImpl; + def _ZGVnN2vv_ldexp : RuntimeLibcallImpl; + def _ZGVnN2vv_nextafter : RuntimeLibcallImpl; + def _ZGVnN2vv_pow : RuntimeLibcallImpl; + def _ZGVnN2vvv_fma : RuntimeLibcallImpl; +} + +defset list SLEEFGNUABI_VF4_VECFUNCS = { + def _ZGVnN4v_acosf : RuntimeLibcallImpl; + def _ZGVnN4v_acoshf : RuntimeLibcallImpl; + def _ZGVnN4v_asinf : RuntimeLibcallImpl; + def _ZGVnN4v_asinhf : RuntimeLibcallImpl; + def _ZGVnN4v_atanf : RuntimeLibcallImpl; + def _ZGVnN4v_atanhf : RuntimeLibcallImpl; + def _ZGVnN4v_cbrtf : RuntimeLibcallImpl; + def _ZGVnN4v_cosf : RuntimeLibcallImpl; + def _ZGVnN4v_coshf : RuntimeLibcallImpl; + def _ZGVnN4v_cospif : RuntimeLibcallImpl; + def _ZGVnN4v_erfcf : RuntimeLibcallImpl; + def _ZGVnN4v_erff : RuntimeLibcallImpl; + def _ZGVnN4v_exp10f : RuntimeLibcallImpl; + def _ZGVnN4v_exp2f : RuntimeLibcallImpl; + def _ZGVnN4v_expf : RuntimeLibcallImpl; + def _ZGVnN4v_expm1f : RuntimeLibcallImpl; + def _ZGVnN4v_ilogbf : RuntimeLibcallImpl; + def _ZGVnN4v_lgammaf : RuntimeLibcallImpl; + def _ZGVnN4v_log10f : RuntimeLibcallImpl; + def _ZGVnN4v_log1pf : RuntimeLibcallImpl; + def _ZGVnN4v_log2f : RuntimeLibcallImpl; + def _ZGVnN4v_logf : RuntimeLibcallImpl; + def _ZGVnN4v_sinf : RuntimeLibcallImpl; + def _ZGVnN4v_sinhf : RuntimeLibcallImpl; + def _ZGVnN4v_sinpif : RuntimeLibcallImpl; + def _ZGVnN4v_sqrtf : RuntimeLibcallImpl; + def _ZGVnN4v_tanf : RuntimeLibcallImpl; + def _ZGVnN4v_tanhf : RuntimeLibcallImpl; + def _ZGVnN4v_tgammaf : RuntimeLibcallImpl; + def _ZGVnN4vl4_modff : RuntimeLibcallImpl; + def _ZGVnN4vl4l4_sincosf : RuntimeLibcallImpl; + def _ZGVnN4vl4l4_sincospif : RuntimeLibcallImpl; + def _ZGVnN4vv_atan2f : RuntimeLibcallImpl; + def _ZGVnN4vv_copysignf : RuntimeLibcallImpl; + def _ZGVnN4vv_fdimf : RuntimeLibcallImpl; + def _ZGVnN4vv_fmaxf : RuntimeLibcallImpl; + def _ZGVnN4vv_fminf : RuntimeLibcallImpl; + def _ZGVnN4vv_fmodf : RuntimeLibcallImpl; + def _ZGVnN4vv_hypotf : RuntimeLibcallImpl; + def _ZGVnN4vv_ldexpf : RuntimeLibcallImpl; + def _ZGVnN4vv_nextafterf : RuntimeLibcallImpl; + def _ZGVnN4vv_powf : RuntimeLibcallImpl; + def _ZGVnN4vvv_fmaf : RuntimeLibcallImpl; +} + +defset list SLEEFGNUABI_SCALABLE_VECFUNCS = { + def _ZGVsMxv_acos : RuntimeLibcallImpl; + def _ZGVsMxv_acosf : RuntimeLibcallImpl; + def _ZGVsMxv_acosh : RuntimeLibcallImpl; + def _ZGVsMxv_acoshf : RuntimeLibcallImpl; + def _ZGVsMxv_asin : RuntimeLibcallImpl; + def _ZGVsMxv_asinf : RuntimeLibcallImpl; + def _ZGVsMxv_asinh : RuntimeLibcallImpl; + def _ZGVsMxv_asinhf : RuntimeLibcallImpl; + def _ZGVsMxv_atan : RuntimeLibcallImpl; + def _ZGVsMxv_atanf : RuntimeLibcallImpl; + def _ZGVsMxv_atanh : RuntimeLibcallImpl; + def _ZGVsMxv_atanhf : RuntimeLibcallImpl; + def _ZGVsMxv_cbrt : RuntimeLibcallImpl; + def _ZGVsMxv_cbrtf : RuntimeLibcallImpl; + def _ZGVsMxv_cos : RuntimeLibcallImpl; + def _ZGVsMxv_cosf : RuntimeLibcallImpl; + def _ZGVsMxv_cosh : RuntimeLibcallImpl; + def _ZGVsMxv_coshf : RuntimeLibcallImpl; + def _ZGVsMxv_cospi : RuntimeLibcallImpl; + def _ZGVsMxv_cospif : RuntimeLibcallImpl; + def _ZGVsMxv_erf : RuntimeLibcallImpl; + def _ZGVsMxv_erfc : RuntimeLibcallImpl; + def _ZGVsMxv_erfcf : RuntimeLibcallImpl; + def _ZGVsMxv_erff : RuntimeLibcallImpl; + def _ZGVsMxv_exp : RuntimeLibcallImpl; + def _ZGVsMxv_exp10 : RuntimeLibcallImpl; + def _ZGVsMxv_exp10f : RuntimeLibcallImpl; + def _ZGVsMxv_exp2 : RuntimeLibcallImpl; + def _ZGVsMxv_exp2f : RuntimeLibcallImpl; + def _ZGVsMxv_expf : RuntimeLibcallImpl; + def _ZGVsMxv_expm1 : RuntimeLibcallImpl; + def _ZGVsMxv_expm1f : RuntimeLibcallImpl; + def _ZGVsMxv_ilogb : RuntimeLibcallImpl; + def _ZGVsMxv_ilogbf : RuntimeLibcallImpl; + def _ZGVsMxv_lgamma : RuntimeLibcallImpl; + def _ZGVsMxv_lgammaf : RuntimeLibcallImpl; + def _ZGVsMxv_log : RuntimeLibcallImpl; + def _ZGVsMxv_log10 : RuntimeLibcallImpl; + def _ZGVsMxv_log10f : RuntimeLibcallImpl; + def _ZGVsMxv_log1p : RuntimeLibcallImpl; + def _ZGVsMxv_log1pf : RuntimeLibcallImpl; + def _ZGVsMxv_log2 : RuntimeLibcallImpl; + def _ZGVsMxv_log2f : RuntimeLibcallImpl; + def _ZGVsMxv_logf : RuntimeLibcallImpl; + def _ZGVsMxv_sin : RuntimeLibcallImpl; + def _ZGVsMxv_sinf : RuntimeLibcallImpl; + def _ZGVsMxv_sinh : RuntimeLibcallImpl; + def _ZGVsMxv_sinhf : RuntimeLibcallImpl; + def _ZGVsMxv_sinpi : RuntimeLibcallImpl; + def _ZGVsMxv_sinpif : RuntimeLibcallImpl; + def _ZGVsMxv_sqrt : RuntimeLibcallImpl; + def _ZGVsMxv_sqrtf : RuntimeLibcallImpl; + def _ZGVsMxv_tan : RuntimeLibcallImpl; + def _ZGVsMxv_tanf : RuntimeLibcallImpl; + def _ZGVsMxv_tanh : RuntimeLibcallImpl; + def _ZGVsMxv_tanhf : RuntimeLibcallImpl; + def _ZGVsMxv_tgamma : RuntimeLibcallImpl; + def _ZGVsMxv_tgammaf : RuntimeLibcallImpl; + def _ZGVsMxvv_atan2 : RuntimeLibcallImpl; + def _ZGVsMxvv_atan2f : RuntimeLibcallImpl; + def _ZGVsMxvv_copysign : RuntimeLibcallImpl; + def _ZGVsMxvv_copysignf : RuntimeLibcallImpl; + def _ZGVsMxvv_fdim : RuntimeLibcallImpl; + def _ZGVsMxvv_fdimf : RuntimeLibcallImpl; + def _ZGVsMxvv_fmax : RuntimeLibcallImpl; + def _ZGVsMxvv_fmaxf : RuntimeLibcallImpl; + def _ZGVsMxvv_fmin : RuntimeLibcallImpl; + def _ZGVsMxvv_fminf : RuntimeLibcallImpl; + def _ZGVsMxvv_fmod : RuntimeLibcallImpl; + def _ZGVsMxvv_fmodf : RuntimeLibcallImpl; + def _ZGVsMxvv_hypot : RuntimeLibcallImpl; + def _ZGVsMxvv_hypotf : RuntimeLibcallImpl; + def _ZGVsMxvv_ldexp : RuntimeLibcallImpl; + def _ZGVsMxvv_ldexpf : RuntimeLibcallImpl; + def _ZGVsMxvv_nextafter : RuntimeLibcallImpl; + def _ZGVsMxvv_nextafterf : RuntimeLibcallImpl; + def _ZGVsMxvv_pow : RuntimeLibcallImpl; + def _ZGVsMxvv_powf : RuntimeLibcallImpl; + def _ZGVsMxvvv_fma : RuntimeLibcallImpl; + def _ZGVsMxvvv_fmaf : RuntimeLibcallImpl; + def _ZGVsNxvl8_modf : RuntimeLibcallImpl; + def _ZGVsNxvl4_modff : RuntimeLibcallImpl; + def _ZGVsNxvl4l4_sincosf : RuntimeLibcallImpl; + def _ZGVsNxvl4l4_sincospif : RuntimeLibcallImpl; + def _ZGVsNxvl8l8_sincos : RuntimeLibcallImpl; + def _ZGVsNxvl8l8_sincospi : RuntimeLibcallImpl; +} + +defset list SLEEFGNUABI_SCALABLE_VECFUNCS_RISCV = { + def Sleef_acosdx_u10rvvm2 : RuntimeLibcallImpl; + def Sleef_acosfx_u10rvvm2 : RuntimeLibcallImpl; + def Sleef_acoshdx_u10rvvm2 : RuntimeLibcallImpl; + def Sleef_acoshfx_u10rvvm2 : RuntimeLibcallImpl; + def Sleef_asindx_u10rvvm2 : RuntimeLibcallImpl; + def Sleef_asinfx_u10rvvm2 : RuntimeLibcallImpl; + def Sleef_asinhdx_u10rvvm2 : RuntimeLibcallImpl; + def Sleef_asinhfx_u10rvvm2 : RuntimeLibcallImpl; + def Sleef_atan2dx_u10rvvm2 : RuntimeLibcallImpl; + def Sleef_atan2fx_u10rvvm2 : RuntimeLibcallImpl; + def Sleef_atandx_u10rvvm2 : RuntimeLibcallImpl; + def Sleef_atanfx_u10rvvm2 : RuntimeLibcallImpl; + def Sleef_atanhdx_u10rvvm2 : RuntimeLibcallImpl; + def Sleef_atanhfx_u10rvvm2 : RuntimeLibcallImpl; + def Sleef_cbrtdx_u10rvvm2 : RuntimeLibcallImpl; + def Sleef_cbrtfx_u10rvvm2 : RuntimeLibcallImpl; + def Sleef_copysigndx_rvvm2 : RuntimeLibcallImpl; + def Sleef_copysignfx_rvvm2 : RuntimeLibcallImpl; + def Sleef_cosdx_u10rvvm2 : RuntimeLibcallImpl; + def Sleef_cosfx_u10rvvm2 : RuntimeLibcallImpl; + def Sleef_coshdx_u10rvvm2 : RuntimeLibcallImpl; + def Sleef_coshfx_u10rvvm2 : RuntimeLibcallImpl; + def Sleef_cospidx_u05rvvm2 : RuntimeLibcallImpl; + def Sleef_cospifx_u05rvvm2 : RuntimeLibcallImpl; + def Sleef_erfcdx_u15rvvm2 : RuntimeLibcallImpl; + def Sleef_erfcfx_u15rvvm2 : RuntimeLibcallImpl; + def Sleef_erfdx_u10rvvm2 : RuntimeLibcallImpl; + def Sleef_erffx_u10rvvm2 : RuntimeLibcallImpl; + def Sleef_exp10dx_u10rvvm2 : RuntimeLibcallImpl; + def Sleef_exp10fx_u10rvvm2 : RuntimeLibcallImpl; + def Sleef_exp2dx_u10rvvm2 : RuntimeLibcallImpl; + def Sleef_exp2fx_u10rvvm2 : RuntimeLibcallImpl; + def Sleef_expdx_u10rvvm2 : RuntimeLibcallImpl; + def Sleef_expfx_u10rvvm2 : RuntimeLibcallImpl; + def Sleef_expm1dx_u10rvvm2 : RuntimeLibcallImpl; + def Sleef_expm1fx_u10rvvm2 : RuntimeLibcallImpl; + def Sleef_fdimdx_rvvm2 : RuntimeLibcallImpl; + def Sleef_fdimfx_rvvm2 : RuntimeLibcallImpl; + def Sleef_fmadx_rvvm2 : RuntimeLibcallImpl; + def Sleef_fmafx_rvvm2 : RuntimeLibcallImpl; + def Sleef_fmaxdx_rvvm2 : RuntimeLibcallImpl; + def Sleef_fmaxfx_rvvm2 : RuntimeLibcallImpl; + def Sleef_fmindx_u10rvvm2 : RuntimeLibcallImpl; + def Sleef_fminfx_u10rvvm2 : RuntimeLibcallImpl; + def Sleef_fmoddx_rvvm2 : RuntimeLibcallImpl; + def Sleef_fmodfx_rvvm2 : RuntimeLibcallImpl; + def Sleef_hypotdx_u05rvvm2 : RuntimeLibcallImpl; + def Sleef_hypotfx_u05rvvm2 : RuntimeLibcallImpl; + def Sleef_ilogbdx_rvvm2 : RuntimeLibcallImpl; + def Sleef_ilogbfx_rvvm2 : RuntimeLibcallImpl; + def Sleef_ldexpdx_rvvm2 : RuntimeLibcallImpl; + def Sleef_ldexpfx_rvvm2 : RuntimeLibcallImpl; + def Sleef_lgammadx_u10rvvm2 : RuntimeLibcallImpl; + def Sleef_lgammafx_u10rvvm2 : RuntimeLibcallImpl; + def Sleef_log10dx_u10rvvm2 : RuntimeLibcallImpl; + def Sleef_log10fx_u10rvvm2 : RuntimeLibcallImpl; + def Sleef_log1pdx_u10rvvm2 : RuntimeLibcallImpl; + def Sleef_log1pfx_u10rvvm2 : RuntimeLibcallImpl; + def Sleef_log2dx_u10rvvm2 : RuntimeLibcallImpl; + def Sleef_log2fx_u10rvvm2 : RuntimeLibcallImpl; + def Sleef_logdx_u10rvvm2 : RuntimeLibcallImpl; + def Sleef_logfx_u10rvvm2 : RuntimeLibcallImpl; + def Sleef_modfdx_rvvm2 : RuntimeLibcallImpl; + def Sleef_modffx_rvvm2 : RuntimeLibcallImpl; + def Sleef_nextafterdx_rvvm2 : RuntimeLibcallImpl; + def Sleef_nextafterfx_rvvm2 : RuntimeLibcallImpl; + def Sleef_powdx_u10rvvm2 : RuntimeLibcallImpl; + def Sleef_powfx_u10rvvm2 : RuntimeLibcallImpl; + def Sleef_sincosdx_u10rvvm2 : RuntimeLibcallImpl; + def Sleef_sincosfx_u10rvvm2 : RuntimeLibcallImpl; + def Sleef_sincospidx_u10rvvm2 : RuntimeLibcallImpl; + def Sleef_sincospifx_u10rvvm2 : RuntimeLibcallImpl; + def Sleef_sindx_u10rvvm2 : RuntimeLibcallImpl; + def Sleef_sinfx_u10rvvm2 : RuntimeLibcallImpl; + def Sleef_sinhdx_u10rvvm2 : RuntimeLibcallImpl; + def Sleef_sinhfx_u10rvvm2 : RuntimeLibcallImpl; + def Sleef_sinpidx_u05rvvm2 : RuntimeLibcallImpl; + def Sleef_sinpifx_u05rvvm2 : RuntimeLibcallImpl; + def Sleef_sqrtdx_u05rvvm2 : RuntimeLibcallImpl; + def Sleef_sqrtfx_u05rvvm2 : RuntimeLibcallImpl; + def Sleef_tandx_u10rvvm2 : RuntimeLibcallImpl; + def Sleef_tanfx_u10rvvm2 : RuntimeLibcallImpl; + def Sleef_tanhdx_u10rvvm2 : RuntimeLibcallImpl; + def Sleef_tanhfx_u10rvvm2 : RuntimeLibcallImpl; + def Sleef_tgammadx_u10rvvm2 : RuntimeLibcallImpl; + def Sleef_tgammafx_u10rvvm2 : RuntimeLibcallImpl; +} + +//===----------------------------------------------------------------------===// +// Arm Performance Libraries (ARMPL) functions +//===----------------------------------------------------------------------===// + +defset list ARMPL_VECFUNCS = { + def armpl_svacos_f32_x : RuntimeLibcallImpl; + def armpl_svacos_f64_x : RuntimeLibcallImpl; + def armpl_svacosh_f32_x : RuntimeLibcallImpl; + def armpl_svacosh_f64_x : RuntimeLibcallImpl; + def armpl_svasin_f32_x : RuntimeLibcallImpl; + def armpl_svasin_f64_x : RuntimeLibcallImpl; + def armpl_svasinh_f32_x : RuntimeLibcallImpl; + def armpl_svasinh_f64_x : RuntimeLibcallImpl; + def armpl_svatan2_f32_x : RuntimeLibcallImpl; + def armpl_svatan2_f64_x : RuntimeLibcallImpl; + def armpl_svatan_f32_x : RuntimeLibcallImpl; + def armpl_svatan_f64_x : RuntimeLibcallImpl; + def armpl_svatanh_f32_x : RuntimeLibcallImpl; + def armpl_svatanh_f64_x : RuntimeLibcallImpl; + def armpl_svcbrt_f32_x : RuntimeLibcallImpl; + def armpl_svcbrt_f64_x : RuntimeLibcallImpl; + def armpl_svcopysign_f32_x : RuntimeLibcallImpl; + def armpl_svcopysign_f64_x : RuntimeLibcallImpl; + def armpl_svcos_f32_x : RuntimeLibcallImpl; + def armpl_svcos_f64_x : RuntimeLibcallImpl; + def armpl_svcosh_f32_x : RuntimeLibcallImpl; + def armpl_svcosh_f64_x : RuntimeLibcallImpl; + def armpl_svcospi_f32_x : RuntimeLibcallImpl; + def armpl_svcospi_f64_x : RuntimeLibcallImpl; + def armpl_sverf_f32_x : RuntimeLibcallImpl; + def armpl_sverf_f64_x : RuntimeLibcallImpl; + def armpl_sverfc_f32_x : RuntimeLibcallImpl; + def armpl_sverfc_f64_x : RuntimeLibcallImpl; + def armpl_svexp10_f32_x : RuntimeLibcallImpl; + def armpl_svexp10_f64_x : RuntimeLibcallImpl; + def armpl_svexp2_f32_x : RuntimeLibcallImpl; + def armpl_svexp2_f64_x : RuntimeLibcallImpl; + def armpl_svexp_f32_x : RuntimeLibcallImpl; + def armpl_svexp_f64_x : RuntimeLibcallImpl; + def armpl_svexpm1_f32_x : RuntimeLibcallImpl; + def armpl_svexpm1_f64_x : RuntimeLibcallImpl; + def armpl_svfdim_f32_x : RuntimeLibcallImpl; + def armpl_svfdim_f64_x : RuntimeLibcallImpl; + def armpl_svfma_f32_x : RuntimeLibcallImpl; + def armpl_svfma_f64_x : RuntimeLibcallImpl; + def armpl_svfmax_f32_x : RuntimeLibcallImpl; + def armpl_svfmax_f64_x : RuntimeLibcallImpl; + def armpl_svfmin_f32_x : RuntimeLibcallImpl; + def armpl_svfmin_f64_x : RuntimeLibcallImpl; + def armpl_svfmod_f32_x : RuntimeLibcallImpl; + def armpl_svfmod_f64_x : RuntimeLibcallImpl; + def armpl_svhypot_f32_x : RuntimeLibcallImpl; + def armpl_svhypot_f64_x : RuntimeLibcallImpl; + def armpl_svilogb_f32_x : RuntimeLibcallImpl; + def armpl_svilogb_f64_x : RuntimeLibcallImpl; + def armpl_svldexp_f32_x : RuntimeLibcallImpl; + def armpl_svldexp_f64_x : RuntimeLibcallImpl; + def armpl_svlgamma_f32_x : RuntimeLibcallImpl; + def armpl_svlgamma_f64_x : RuntimeLibcallImpl; + def armpl_svlog10_f32_x : RuntimeLibcallImpl; + def armpl_svlog10_f64_x : RuntimeLibcallImpl; + def armpl_svlog1p_f32_x : RuntimeLibcallImpl; + def armpl_svlog1p_f64_x : RuntimeLibcallImpl; + def armpl_svlog2_f32_x : RuntimeLibcallImpl; + def armpl_svlog2_f64_x : RuntimeLibcallImpl; + def armpl_svlog_f32_x : RuntimeLibcallImpl; + def armpl_svlog_f64_x : RuntimeLibcallImpl; + def armpl_svmodf_f32_x : RuntimeLibcallImpl; + def armpl_svmodf_f64_x : RuntimeLibcallImpl; + def armpl_svnextafter_f32_x : RuntimeLibcallImpl; + def armpl_svnextafter_f64_x : RuntimeLibcallImpl; + def armpl_svpow_f32_x : RuntimeLibcallImpl; + def armpl_svpow_f64_x : RuntimeLibcallImpl; + def armpl_svsin_f32_x : RuntimeLibcallImpl; + def armpl_svsin_f64_x : RuntimeLibcallImpl; + def armpl_svsincos_f32_x : RuntimeLibcallImpl; + def armpl_svsincos_f64_x : RuntimeLibcallImpl; + def armpl_svsincospi_f32_x : RuntimeLibcallImpl; + def armpl_svsincospi_f64_x : RuntimeLibcallImpl; + def armpl_svsinh_f32_x : RuntimeLibcallImpl; + def armpl_svsinh_f64_x : RuntimeLibcallImpl; + def armpl_svsinpi_f32_x : RuntimeLibcallImpl; + def armpl_svsinpi_f64_x : RuntimeLibcallImpl; + def armpl_svsqrt_f32_x : RuntimeLibcallImpl; + def armpl_svsqrt_f64_x : RuntimeLibcallImpl; + def armpl_svtan_f32_x : RuntimeLibcallImpl; + def armpl_svtan_f64_x : RuntimeLibcallImpl; + def armpl_svtanh_f32_x : RuntimeLibcallImpl; + def armpl_svtanh_f64_x : RuntimeLibcallImpl; + def armpl_svtgamma_f32_x : RuntimeLibcallImpl; + def armpl_svtgamma_f64_x : RuntimeLibcallImpl; + def armpl_vacoshq_f32 : RuntimeLibcallImpl; + def armpl_vacoshq_f64 : RuntimeLibcallImpl; + def armpl_vacosq_f32 : RuntimeLibcallImpl; + def armpl_vacosq_f64 : RuntimeLibcallImpl; + def armpl_vasinhq_f32 : RuntimeLibcallImpl; + def armpl_vasinhq_f64 : RuntimeLibcallImpl; + def armpl_vasinq_f32 : RuntimeLibcallImpl; + def armpl_vasinq_f64 : RuntimeLibcallImpl; + def armpl_vatan2q_f32 : RuntimeLibcallImpl; + def armpl_vatan2q_f64 : RuntimeLibcallImpl; + def armpl_vatanhq_f32 : RuntimeLibcallImpl; + def armpl_vatanhq_f64 : RuntimeLibcallImpl; + def armpl_vatanq_f32 : RuntimeLibcallImpl; + def armpl_vatanq_f64 : RuntimeLibcallImpl; + def armpl_vcbrtq_f32 : RuntimeLibcallImpl; + def armpl_vcbrtq_f64 : RuntimeLibcallImpl; + def armpl_vcopysignq_f32 : RuntimeLibcallImpl; + def armpl_vcopysignq_f64 : RuntimeLibcallImpl; + def armpl_vcoshq_f32 : RuntimeLibcallImpl; + def armpl_vcoshq_f64 : RuntimeLibcallImpl; + def armpl_vcospiq_f32 : RuntimeLibcallImpl; + def armpl_vcospiq_f64 : RuntimeLibcallImpl; + def armpl_vcosq_f32 : RuntimeLibcallImpl; + def armpl_vcosq_f64 : RuntimeLibcallImpl; + def armpl_verfcq_f32 : RuntimeLibcallImpl; + def armpl_verfcq_f64 : RuntimeLibcallImpl; + def armpl_verfq_f32 : RuntimeLibcallImpl; + def armpl_verfq_f64 : RuntimeLibcallImpl; + def armpl_vexp10q_f32 : RuntimeLibcallImpl; + def armpl_vexp10q_f64 : RuntimeLibcallImpl; + def armpl_vexp2q_f32 : RuntimeLibcallImpl; + def armpl_vexp2q_f64 : RuntimeLibcallImpl; + def armpl_vexpm1q_f32 : RuntimeLibcallImpl; + def armpl_vexpm1q_f64 : RuntimeLibcallImpl; + def armpl_vexpq_f32 : RuntimeLibcallImpl; + def armpl_vexpq_f64 : RuntimeLibcallImpl; + def armpl_vfdimq_f32 : RuntimeLibcallImpl; + def armpl_vfdimq_f64 : RuntimeLibcallImpl; + def armpl_vfmaq_f32 : RuntimeLibcallImpl; + def armpl_vfmaq_f64 : RuntimeLibcallImpl; + def armpl_vfmaxq_f32 : RuntimeLibcallImpl; + def armpl_vfmaxq_f64 : RuntimeLibcallImpl; + def armpl_vfminq_f32 : RuntimeLibcallImpl; + def armpl_vfminq_f64 : RuntimeLibcallImpl; + def armpl_vfmodq_f32 : RuntimeLibcallImpl; + def armpl_vfmodq_f64 : RuntimeLibcallImpl; + def armpl_vhypotq_f32 : RuntimeLibcallImpl; + def armpl_vhypotq_f64 : RuntimeLibcallImpl; + def armpl_vilogbq_f32 : RuntimeLibcallImpl; + def armpl_vilogbq_f64 : RuntimeLibcallImpl; + def armpl_vldexpq_f32 : RuntimeLibcallImpl; + def armpl_vldexpq_f64 : RuntimeLibcallImpl; + def armpl_vlgammaq_f32 : RuntimeLibcallImpl; + def armpl_vlgammaq_f64 : RuntimeLibcallImpl; + def armpl_vlog10q_f32 : RuntimeLibcallImpl; + def armpl_vlog10q_f64 : RuntimeLibcallImpl; + def armpl_vlog1pq_f32 : RuntimeLibcallImpl; + def armpl_vlog1pq_f64 : RuntimeLibcallImpl; + def armpl_vlog2q_f32 : RuntimeLibcallImpl; + def armpl_vlog2q_f64 : RuntimeLibcallImpl; + def armpl_vlogq_f32 : RuntimeLibcallImpl; + def armpl_vlogq_f64 : RuntimeLibcallImpl; + def armpl_vmodfq_f32 : RuntimeLibcallImpl; + def armpl_vmodfq_f64 : RuntimeLibcallImpl; + def armpl_vnextafterq_f32 : RuntimeLibcallImpl; + def armpl_vnextafterq_f64 : RuntimeLibcallImpl; + def armpl_vpowq_f32 : RuntimeLibcallImpl; + def armpl_vpowq_f64 : RuntimeLibcallImpl; + def armpl_vsincospiq_f32 : RuntimeLibcallImpl; + def armpl_vsincospiq_f64 : RuntimeLibcallImpl; + def armpl_vsincosq_f32 : RuntimeLibcallImpl; + def armpl_vsincosq_f64 : RuntimeLibcallImpl; + def armpl_vsinhq_f32 : RuntimeLibcallImpl; + def armpl_vsinhq_f64 : RuntimeLibcallImpl; + def armpl_vsinpiq_f32 : RuntimeLibcallImpl; + def armpl_vsinpiq_f64 : RuntimeLibcallImpl; + def armpl_vsinq_f32 : RuntimeLibcallImpl; + def armpl_vsinq_f64 : RuntimeLibcallImpl; + def armpl_vsqrtq_f32 : RuntimeLibcallImpl; + def armpl_vsqrtq_f64 : RuntimeLibcallImpl; + def armpl_vtanhq_f32 : RuntimeLibcallImpl; + def armpl_vtanhq_f64 : RuntimeLibcallImpl; + def armpl_vtanq_f32 : RuntimeLibcallImpl; + def armpl_vtanq_f64 : RuntimeLibcallImpl; + def armpl_vtgammaq_f32 : RuntimeLibcallImpl; + def armpl_vtgammaq_f64 : RuntimeLibcallImpl; +} + +//===----------------------------------------------------------------------===// +// AMD vector math library (AMDLIBM) functions +//===----------------------------------------------------------------------===// + +defset list AMDLIBM_VECFUNCS = { + def amd_vrd2_atan : RuntimeLibcallImpl; + def amd_vrd2_cbrt : RuntimeLibcallImpl; + def amd_vrd2_cos : RuntimeLibcallImpl; + def amd_vrd2_erf : RuntimeLibcallImpl; + def amd_vrd2_exp : RuntimeLibcallImpl; + def amd_vrd2_exp10 : RuntimeLibcallImpl; + def amd_vrd2_exp2 : RuntimeLibcallImpl; + def amd_vrd2_expm1 : RuntimeLibcallImpl; + def amd_vrd2_log : RuntimeLibcallImpl; + def amd_vrd2_log10 : RuntimeLibcallImpl; + def amd_vrd2_log1p : RuntimeLibcallImpl; + def amd_vrd2_log2 : RuntimeLibcallImpl; + def amd_vrd2_pow : RuntimeLibcallImpl; + def amd_vrd2_sin : RuntimeLibcallImpl; + def amd_vrd2_tan : RuntimeLibcallImpl; + def amd_vrd4_atan : RuntimeLibcallImpl; + def amd_vrd4_cos : RuntimeLibcallImpl; + def amd_vrd4_erf : RuntimeLibcallImpl; + def amd_vrd4_exp : RuntimeLibcallImpl; + def amd_vrd4_exp2 : RuntimeLibcallImpl; + def amd_vrd4_log : RuntimeLibcallImpl; + def amd_vrd4_log2 : RuntimeLibcallImpl; + def amd_vrd4_pow : RuntimeLibcallImpl; + def amd_vrd4_sin : RuntimeLibcallImpl; + def amd_vrd4_sincos : RuntimeLibcallImpl; + def amd_vrd4_tan : RuntimeLibcallImpl; + def amd_vrd8_asin : RuntimeLibcallImpl; + def amd_vrd8_atan : RuntimeLibcallImpl; + def amd_vrd8_cos : RuntimeLibcallImpl; + def amd_vrd8_erf : RuntimeLibcallImpl; + def amd_vrd8_exp : RuntimeLibcallImpl; + def amd_vrd8_exp2 : RuntimeLibcallImpl; + def amd_vrd8_log : RuntimeLibcallImpl; + def amd_vrd8_log2 : RuntimeLibcallImpl; + def amd_vrd8_pow : RuntimeLibcallImpl; + def amd_vrd8_sin : RuntimeLibcallImpl; + def amd_vrd8_sincos : RuntimeLibcallImpl; + def amd_vrd8_tan : RuntimeLibcallImpl; + def amd_vrs16_acosf : RuntimeLibcallImpl; + def amd_vrs16_asinf : RuntimeLibcallImpl; + def amd_vrs16_atanf : RuntimeLibcallImpl; + def amd_vrs16_cosf : RuntimeLibcallImpl; + def amd_vrs16_erff : RuntimeLibcallImpl; + def amd_vrs16_exp2f : RuntimeLibcallImpl; + def amd_vrs16_expf : RuntimeLibcallImpl; + def amd_vrs16_log10f : RuntimeLibcallImpl; + def amd_vrs16_log2f : RuntimeLibcallImpl; + def amd_vrs16_logf : RuntimeLibcallImpl; + def amd_vrs16_powf : RuntimeLibcallImpl; + def amd_vrs16_sincosf : RuntimeLibcallImpl; + def amd_vrs16_sinf : RuntimeLibcallImpl; + def amd_vrs16_tanf : RuntimeLibcallImpl; + def amd_vrs16_tanhf : RuntimeLibcallImpl; + def amd_vrs4_acosf : RuntimeLibcallImpl; + def amd_vrs4_asinf : RuntimeLibcallImpl; + def amd_vrs4_atanf : RuntimeLibcallImpl; + def amd_vrs4_cbrtf : RuntimeLibcallImpl; + def amd_vrs4_cosf : RuntimeLibcallImpl; + def amd_vrs4_coshf : RuntimeLibcallImpl; + def amd_vrs4_erff : RuntimeLibcallImpl; + def amd_vrs4_exp10f : RuntimeLibcallImpl; + def amd_vrs4_exp2f : RuntimeLibcallImpl; + def amd_vrs4_expf : RuntimeLibcallImpl; + def amd_vrs4_expm1f : RuntimeLibcallImpl; + def amd_vrs4_log10f : RuntimeLibcallImpl; + def amd_vrs4_log1pf : RuntimeLibcallImpl; + def amd_vrs4_log2f : RuntimeLibcallImpl; + def amd_vrs4_logf : RuntimeLibcallImpl; + def amd_vrs4_powf : RuntimeLibcallImpl; + def amd_vrs4_sincosf : RuntimeLibcallImpl; + def amd_vrs4_sinf : RuntimeLibcallImpl; + def amd_vrs4_tanf : RuntimeLibcallImpl; + def amd_vrs4_tanhf : RuntimeLibcallImpl; + def amd_vrs8_acosf : RuntimeLibcallImpl; + def amd_vrs8_asinf : RuntimeLibcallImpl; + def amd_vrs8_atanf : RuntimeLibcallImpl; + def amd_vrs8_cosf : RuntimeLibcallImpl; + def amd_vrs8_coshf : RuntimeLibcallImpl; + def amd_vrs8_erff : RuntimeLibcallImpl; + def amd_vrs8_exp2f : RuntimeLibcallImpl; + def amd_vrs8_expf : RuntimeLibcallImpl; + def amd_vrs8_log10f : RuntimeLibcallImpl; + def amd_vrs8_log2f : RuntimeLibcallImpl; + def amd_vrs8_logf : RuntimeLibcallImpl; + def amd_vrs8_powf : RuntimeLibcallImpl; + def amd_vrs8_sincosf : RuntimeLibcallImpl; + def amd_vrs8_sinf : RuntimeLibcallImpl; + def amd_vrs8_tanf : RuntimeLibcallImpl; + def amd_vrs8_tanhf : RuntimeLibcallImpl; +} From 25dee656c7d2a3ba90cf4d243c047ea14616e91a Mon Sep 17 00:00:00 2001 From: Wenju He Date: Tue, 25 Nov 2025 08:01:55 +0800 Subject: [PATCH 35/50] [OpenCL] Disable __opencl_c_ext_fp64_* features if cl_khr_fp64 is not supported (#169252) Fix kernel build when cl_khr_fp64 is not enabled: opencl-c.h:13785:50: error: unknown type name 'atomic_double' 13785 | double __ovld atomic_fetch_min(volatile __global atomic_double *, double); opencl-c.h:13785:67: error: use of type 'double' requires cl_khr_fp64 and __opencl_c_fp64 support 13785 | double __ovld atomic_fetch_min(volatile __global atomic_double *, double); This is a regression introduced by 423bdb2b. Before that commit, __opencl_c_ext_fp64_global_atomic_add was guarded by cl_khr_fp64 in opencl-c-base.h. --- clang/include/clang/Basic/TargetInfo.h | 3 +++ clang/lib/Basic/TargetInfo.cpp | 11 +++++++++++ clang/lib/Basic/Targets.cpp | 1 + .../test/Misc/opencl-c-3.0.incorrect_define.cl | 17 +++++++++++++++++ 4 files changed, 32 insertions(+) create mode 100644 clang/test/Misc/opencl-c-3.0.incorrect_define.cl diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h index 39af84c8d0872..1f5932225d31e 100644 --- a/clang/include/clang/Basic/TargetInfo.h +++ b/clang/include/clang/Basic/TargetInfo.h @@ -1848,6 +1848,9 @@ class TargetInfo : public TransferrableTargetInfo, } } + /// Set features that depend on other features. + virtual void setDependentOpenCLOpts(); + /// Get supported OpenCL extensions and optional core features. llvm::StringMap &getSupportedOpenCLOpts() { return getTargetOpts().OpenCLFeaturesMap; diff --git a/clang/lib/Basic/TargetInfo.cpp b/clang/lib/Basic/TargetInfo.cpp index 9a5db6e164f66..c0ed900ebd45c 100644 --- a/clang/lib/Basic/TargetInfo.cpp +++ b/clang/lib/Basic/TargetInfo.cpp @@ -640,6 +640,17 @@ bool TargetInfo::areDefaultedSMFStillPOD(const LangOptions &LangOpts) const { return LangOpts.getClangABICompat() > LangOptions::ClangABI::Ver15; } +void TargetInfo::setDependentOpenCLOpts() { + auto &Opts = getSupportedOpenCLOpts(); + if (!hasFeatureEnabled(Opts, "cl_khr_fp64") || + !hasFeatureEnabled(Opts, "__opencl_c_fp64")) { + setFeatureEnabled(Opts, "__opencl_c_ext_fp64_global_atomic_add", false); + setFeatureEnabled(Opts, "__opencl_c_ext_fp64_local_atomic_add", false); + setFeatureEnabled(Opts, "__opencl_c_ext_fp64_global_atomic_min_max", false); + setFeatureEnabled(Opts, "__opencl_c_ext_fp64_local_atomic_min_max", false); + } +} + LangAS TargetInfo::getOpenCLTypeAddrSpace(OpenCLTypeKind TK) const { switch (TK) { case OCLTK_Image: diff --git a/clang/lib/Basic/Targets.cpp b/clang/lib/Basic/Targets.cpp index f39c698b5d734..38eb1edd4bfb7 100644 --- a/clang/lib/Basic/Targets.cpp +++ b/clang/lib/Basic/Targets.cpp @@ -862,6 +862,7 @@ TargetInfo *TargetInfo::CreateTargetInfo(DiagnosticsEngine &Diags, Target->setSupportedOpenCLOpts(); Target->setCommandLineOpenCLOpts(); + Target->setDependentOpenCLOpts(); Target->setMaxAtomicWidth(); if (!Opts->DarwinTargetVariantTriple.empty()) diff --git a/clang/test/Misc/opencl-c-3.0.incorrect_define.cl b/clang/test/Misc/opencl-c-3.0.incorrect_define.cl new file mode 100644 index 0000000000000..7857175e46209 --- /dev/null +++ b/clang/test/Misc/opencl-c-3.0.incorrect_define.cl @@ -0,0 +1,17 @@ +// RUN: %clang_cc1 -verify -triple spir-unknown-unknown -cl-std=CL3.0 -cl-ext=-__opencl_c_fp64,-cl_khr_fp64 %s +// RUN: %clang_cc1 -verify -triple spir-unknown-unknown -cl-std=clc++2021 -cl-ext=-__opencl_c_fp64,-cl_khr_fp64 %s + +#if __opencl_c_ext_fp64_global_atomic_add != 0 +#error "Incorrectly defined __opencl_c_ext_fp64_global_atomic_add" +#endif +#if __opencl_c_ext_fp64_local_atomic_add != 0 +#error "Incorrectly defined __opencl_c_ext_fp64_local_atomic_add" +#endif +#if __opencl_c_ext_fp64_global_atomic_min_max != 0 +#error "Incorrectly defined __opencl_c_ext_fp64_global_atomic_min_max" +#endif +#if __opencl_c_ext_fp64_local_atomic_min_max != 0 +#error "Incorrectly defined __opencl_c_ext_fp64_local_atomic_min_max" +#endif + +// expected-no-diagnostics From 8947ba017fd8968292e7541a1bbfb82863e54041 Mon Sep 17 00:00:00 2001 From: Wenju He Date: Tue, 25 Nov 2025 08:02:14 +0800 Subject: [PATCH 36/50] [libclc] Add atomic_init, atomic_flag_clear and atomic_flag_test_and_set (#168329) --- .../clc/atomic/clc_atomic_flag_clear.h | 24 +++++++ .../clc/atomic/clc_atomic_flag_test_and_set.h | 24 +++++++ libclc/clc/lib/generic/SOURCES | 2 + .../generic/atomic/clc_atomic_flag_clear.cl | 25 +++++++ .../atomic/clc_atomic_flag_test_and_set.cl | 25 +++++++ .../clc/opencl/atomic/atomic_flag_clear.h | 46 +++++++++++++ .../opencl/atomic/atomic_flag_test_and_set.h | 50 ++++++++++++++ .../include/clc/opencl/atomic/atomic_init.h | 24 +++++++ .../include/clc/opencl/atomic/atomic_init.inc | 44 +++++++++++++ libclc/opencl/include/clc/opencl/types.h | 48 ++++++++++++++ libclc/opencl/include/clc/opencl/utils.h | 35 ++++++++++ libclc/opencl/lib/generic/SOURCES | 3 + .../lib/generic/atomic/atomic_flag_clear.cl | 61 +++++++++++++++++ .../atomic/atomic_flag_test_and_set.cl | 66 +++++++++++++++++++ .../opencl/lib/generic/atomic/atomic_init.cl | 18 +++++ .../opencl/lib/generic/atomic/atomic_init.inc | 46 +++++++++++++ 16 files changed, 541 insertions(+) create mode 100644 libclc/clc/include/clc/atomic/clc_atomic_flag_clear.h create mode 100644 libclc/clc/include/clc/atomic/clc_atomic_flag_test_and_set.h create mode 100644 libclc/clc/lib/generic/atomic/clc_atomic_flag_clear.cl create mode 100644 libclc/clc/lib/generic/atomic/clc_atomic_flag_test_and_set.cl create mode 100644 libclc/opencl/include/clc/opencl/atomic/atomic_flag_clear.h create mode 100644 libclc/opencl/include/clc/opencl/atomic/atomic_flag_test_and_set.h create mode 100644 libclc/opencl/include/clc/opencl/atomic/atomic_init.h create mode 100644 libclc/opencl/include/clc/opencl/atomic/atomic_init.inc create mode 100644 libclc/opencl/include/clc/opencl/types.h create mode 100644 libclc/opencl/include/clc/opencl/utils.h create mode 100644 libclc/opencl/lib/generic/atomic/atomic_flag_clear.cl create mode 100644 libclc/opencl/lib/generic/atomic/atomic_flag_test_and_set.cl create mode 100644 libclc/opencl/lib/generic/atomic/atomic_init.cl create mode 100644 libclc/opencl/lib/generic/atomic/atomic_init.inc diff --git a/libclc/clc/include/clc/atomic/clc_atomic_flag_clear.h b/libclc/clc/include/clc/atomic/clc_atomic_flag_clear.h new file mode 100644 index 0000000000000..fee7c0506abc1 --- /dev/null +++ b/libclc/clc/include/clc/atomic/clc_atomic_flag_clear.h @@ -0,0 +1,24 @@ +//===----------------------------------------------------------------------===// +// +// 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 __CLC_ATOMIC_CLC_ATOMIC_FLAG_CLEAR_H__ +#define __CLC_ATOMIC_CLC_ATOMIC_FLAG_CLEAR_H__ + +#include + +#define __CLC_DECLARE_ATOMIC_FLAG_CLEAR(ADDRSPACE) \ + _CLC_OVERLOAD _CLC_DECL void __clc_atomic_flag_clear( \ + ADDRSPACE int *Ptr, int MemoryOrder, int MemoryScope); + +__CLC_DECLARE_ATOMIC_FLAG_CLEAR(global) +__CLC_DECLARE_ATOMIC_FLAG_CLEAR(local) +#if _CLC_GENERIC_AS_SUPPORTED +__CLC_DECLARE_ATOMIC_FLAG_CLEAR() +#endif + +#endif // __CLC_ATOMIC_CLC_ATOMIC_FLAG_CLEAR_H__ diff --git a/libclc/clc/include/clc/atomic/clc_atomic_flag_test_and_set.h b/libclc/clc/include/clc/atomic/clc_atomic_flag_test_and_set.h new file mode 100644 index 0000000000000..afc373204ad70 --- /dev/null +++ b/libclc/clc/include/clc/atomic/clc_atomic_flag_test_and_set.h @@ -0,0 +1,24 @@ +//===----------------------------------------------------------------------===// +// +// 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 __CLC_ATOMIC_CLC_ATOMIC_FLAG_TEST_AND_SET_H__ +#define __CLC_ATOMIC_CLC_ATOMIC_FLAG_TEST_AND_SET_H__ + +#include + +#define __CLC_DECLARE_ATOMIC_FLAG_TEST_AND_SET(ADDRSPACE) \ + _CLC_OVERLOAD _CLC_DECL bool __clc_atomic_flag_test_and_set( \ + ADDRSPACE int *Ptr, int MemoryOrder, int MemoryScope); + +__CLC_DECLARE_ATOMIC_FLAG_TEST_AND_SET(global) +__CLC_DECLARE_ATOMIC_FLAG_TEST_AND_SET(local) +#if _CLC_GENERIC_AS_SUPPORTED +__CLC_DECLARE_ATOMIC_FLAG_TEST_AND_SET() +#endif + +#endif // __CLC_ATOMIC_CLC_ATOMIC_FLAG_TEST_AND_SET_H__ diff --git a/libclc/clc/lib/generic/SOURCES b/libclc/clc/lib/generic/SOURCES index ee4f771799e8e..64fc6b4827a1a 100644 --- a/libclc/clc/lib/generic/SOURCES +++ b/libclc/clc/lib/generic/SOURCES @@ -9,6 +9,8 @@ atomic/clc_atomic_fetch_min.cl atomic/clc_atomic_fetch_or.cl atomic/clc_atomic_fetch_sub.cl atomic/clc_atomic_fetch_xor.cl +atomic/clc_atomic_flag_clear.cl +atomic/clc_atomic_flag_test_and_set.cl atomic/clc_atomic_inc.cl atomic/clc_atomic_load.cl atomic/clc_atomic_store.cl diff --git a/libclc/clc/lib/generic/atomic/clc_atomic_flag_clear.cl b/libclc/clc/lib/generic/atomic/clc_atomic_flag_clear.cl new file mode 100644 index 0000000000000..e03e63bd82d5a --- /dev/null +++ b/libclc/clc/lib/generic/atomic/clc_atomic_flag_clear.cl @@ -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 +// +//===----------------------------------------------------------------------===// + +#include +#include + +#define __CLC_ATOMIC_FLAG_FALSE 0 + +#define __CLC_DEFINE_ATOMIC_FLAG_CLEAR(ADDRSPACE) \ + _CLC_OVERLOAD _CLC_DEF void __clc_atomic_flag_clear( \ + ADDRSPACE int *Ptr, int MemoryOrder, int MemoryScope) { \ + __clc_atomic_store(Ptr, __CLC_ATOMIC_FLAG_FALSE, MemoryOrder, \ + MemoryScope); \ + } + +__CLC_DEFINE_ATOMIC_FLAG_CLEAR(global) +__CLC_DEFINE_ATOMIC_FLAG_CLEAR(local) +#if _CLC_GENERIC_AS_SUPPORTED +__CLC_DEFINE_ATOMIC_FLAG_CLEAR() +#endif diff --git a/libclc/clc/lib/generic/atomic/clc_atomic_flag_test_and_set.cl b/libclc/clc/lib/generic/atomic/clc_atomic_flag_test_and_set.cl new file mode 100644 index 0000000000000..4a033e3532af9 --- /dev/null +++ b/libclc/clc/lib/generic/atomic/clc_atomic_flag_test_and_set.cl @@ -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 +// +//===----------------------------------------------------------------------===// + +#include +#include + +#define __CLC_ATOMIC_FLAG_TRUE 1 + +#define __CLC_DEFINE_ATOMIC_FLAG_TEST_AND_SET(ADDRSPACE) \ + _CLC_OVERLOAD _CLC_DEF bool __clc_atomic_flag_test_and_set( \ + ADDRSPACE int *Ptr, int MemoryOrder, int MemoryScope) { \ + return (bool)__clc_atomic_exchange(Ptr, __CLC_ATOMIC_FLAG_TRUE, \ + MemoryOrder, MemoryScope); \ + } + +__CLC_DEFINE_ATOMIC_FLAG_TEST_AND_SET(global) +__CLC_DEFINE_ATOMIC_FLAG_TEST_AND_SET(local) +#if _CLC_GENERIC_AS_SUPPORTED +__CLC_DEFINE_ATOMIC_FLAG_TEST_AND_SET() +#endif diff --git a/libclc/opencl/include/clc/opencl/atomic/atomic_flag_clear.h b/libclc/opencl/include/clc/opencl/atomic/atomic_flag_clear.h new file mode 100644 index 0000000000000..2fcd3eef43a65 --- /dev/null +++ b/libclc/opencl/include/clc/opencl/atomic/atomic_flag_clear.h @@ -0,0 +1,46 @@ +//===----------------------------------------------------------------------===// +// +// 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 __CLC_OPENCL_ATOMIC_ATOMIC_FLAG_CLEAR_H__ +#define __CLC_OPENCL_ATOMIC_ATOMIC_FLAG_CLEAR_H__ + +#include +#include + +#if defined(__opencl_c_atomic_order_seq_cst) && \ + defined(__opencl_c_atomic_scope_device) +_CLC_OVERLOAD _CLC_DECL void atomic_flag_clear(volatile __global atomic_flag *); +_CLC_OVERLOAD _CLC_DECL void atomic_flag_clear(volatile __local atomic_flag *); +#if defined(__opencl_c_generic_address_space) +_CLC_OVERLOAD _CLC_DECL void atomic_flag_clear(volatile atomic_flag *); +#endif // defined(__opencl_c_generic_address_space) +#endif + +#if defined(__opencl_c_atomic_scope_device) +_CLC_OVERLOAD _CLC_DECL void +atomic_flag_clear_explicit(volatile __global atomic_flag *, memory_order); +_CLC_OVERLOAD _CLC_DECL void +atomic_flag_clear_explicit(volatile __local atomic_flag *, memory_order); +#if defined(__opencl_c_generic_address_space) +_CLC_OVERLOAD _CLC_DECL void atomic_flag_clear_explicit(volatile atomic_flag *, + memory_order); +#endif // defined(__opencl_c_generic_address_space) +#endif + +_CLC_OVERLOAD _CLC_DECL void +atomic_flag_clear_explicit(volatile __global atomic_flag *, memory_order, + memory_scope); +_CLC_OVERLOAD _CLC_DECL void +atomic_flag_clear_explicit(volatile __local atomic_flag *, memory_order, + memory_scope); +#if defined(__opencl_c_generic_address_space) +_CLC_OVERLOAD _CLC_DECL void +atomic_flag_clear_explicit(volatile atomic_flag *, memory_order, memory_scope); +#endif // defined(__opencl_c_generic_address_space) + +#endif // __CLC_OPENCL_ATOMIC_ATOMIC_FLAG_CLEAR_H__ diff --git a/libclc/opencl/include/clc/opencl/atomic/atomic_flag_test_and_set.h b/libclc/opencl/include/clc/opencl/atomic/atomic_flag_test_and_set.h new file mode 100644 index 0000000000000..6e3a8e403d5da --- /dev/null +++ b/libclc/opencl/include/clc/opencl/atomic/atomic_flag_test_and_set.h @@ -0,0 +1,50 @@ +//===----------------------------------------------------------------------===// +// +// 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 __CLC_OPENCL_ATOMIC_ATOMIC_FLAG_TEST_AND_SET_H__ +#define __CLC_OPENCL_ATOMIC_ATOMIC_FLAG_TEST_AND_SET_H__ + +#include +#include + +#if defined(__opencl_c_atomic_order_seq_cst) && \ + defined(__opencl_c_atomic_scope_device) +_CLC_OVERLOAD _CLC_DECL bool +atomic_flag_test_and_set(volatile __global atomic_flag *); +_CLC_OVERLOAD _CLC_DECL bool +atomic_flag_test_and_set(volatile __local atomic_flag *); +#if defined(__opencl_c_generic_address_space) +_CLC_OVERLOAD _CLC_DECL bool atomic_flag_test_and_set(volatile atomic_flag *); +#endif // defined(__opencl_c_generic_address_space) +#endif + +#if defined(__opencl_c_atomic_scope_device) +_CLC_OVERLOAD _CLC_DECL bool +atomic_flag_test_and_set_explicit(volatile __global atomic_flag *, + memory_order); +_CLC_OVERLOAD _CLC_DECL bool +atomic_flag_test_and_set_explicit(volatile __local atomic_flag *, memory_order); +#if defined(__opencl_c_generic_address_space) +_CLC_OVERLOAD _CLC_DECL bool +atomic_flag_test_and_set_explicit(volatile atomic_flag *, memory_order); +#endif // defined(__opencl_c_generic_address_space) +#endif + +_CLC_OVERLOAD _CLC_DECL bool +atomic_flag_test_and_set_explicit(volatile __global atomic_flag *, memory_order, + memory_scope); +_CLC_OVERLOAD _CLC_DECL bool +atomic_flag_test_and_set_explicit(volatile __local atomic_flag *, memory_order, + memory_scope); +#if defined(__opencl_c_generic_address_space) +_CLC_OVERLOAD _CLC_DECL bool +atomic_flag_test_and_set_explicit(volatile atomic_flag *, memory_order, + memory_scope); +#endif // defined(__opencl_c_generic_address_space) + +#endif // __CLC_OPENCL_ATOMIC_ATOMIC_FLAG_TEST_AND_SET_H__ diff --git a/libclc/opencl/include/clc/opencl/atomic/atomic_init.h b/libclc/opencl/include/clc/opencl/atomic/atomic_init.h new file mode 100644 index 0000000000000..6a2b938fdd52f --- /dev/null +++ b/libclc/opencl/include/clc/opencl/atomic/atomic_init.h @@ -0,0 +1,24 @@ +//===----------------------------------------------------------------------===// +// +// 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 __CLC_OPENCL_ATOMIC_ATOMIC_INIT_H__ +#define __CLC_OPENCL_ATOMIC_ATOMIC_INIT_H__ + +#include + +#define __CLC_ATOMIC_GENTYPE __CLC_XCONCAT(atomic_, __CLC_GENTYPE) + +#define __CLC_BODY +#include + +#define __CLC_BODY +#include + +#undef __CLC_ATOMIC_GENTYPE + +#endif // __CLC_OPENCL_ATOMIC_ATOMIC_INIT_H__ diff --git a/libclc/opencl/include/clc/opencl/atomic/atomic_init.inc b/libclc/opencl/include/clc/opencl/atomic/atomic_init.inc new file mode 100644 index 0000000000000..80135fae4b39d --- /dev/null +++ b/libclc/opencl/include/clc/opencl/atomic/atomic_init.inc @@ -0,0 +1,44 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifdef __CLC_SCALAR + +#if defined(__opencl_c_fp64) && (defined(cl_khr_int64_base_atomics) && \ + defined(cl_khr_int64_extended_atomics)) +#define __CLC_HAVE_64_ATOMIC +#endif +#if defined(__CLC_FPSIZE) && \ + (__CLC_FPSIZE < 64 || defined(__CLC_HAVE_64_ATOMIC)) +#define __CLC_HAVE_FP_ATOMIC +#endif +#if defined(__CLC_GENSIZE) && \ + ((__CLC_GENSIZE == 32) || \ + (__CLC_GENSIZE == 64 && defined(__CLC_HAVE_64_ATOMIC))) +#define __CLC_HAVE_INT_ATOMIC +#endif +#if defined(__CLC_HAVE_FP_ATOMIC) || defined(__CLC_HAVE_INT_ATOMIC) + +#define __CLC_DECL_ATOMIC(ADDRSPACE) \ + _CLC_OVERLOAD _CLC_DECL void atomic_init( \ + volatile ADDRSPACE __CLC_ATOMIC_GENTYPE *Ptr, __CLC_GENTYPE Value); + +__CLC_DECL_ATOMIC(global) +__CLC_DECL_ATOMIC(local) +#if _CLC_GENERIC_AS_SUPPORTED +__CLC_DECL_ATOMIC() +#endif + +#undef __CLC_DECL_ATOMIC + +#endif // __CLC_HAVE_FP_ATOMIC || __CLC_HAVE_INT_ATOMIC + +#undef __CLC_HAVE_INT_ATOMIC +#undef __CLC_HAVE_FP_ATOMIC +#undef __CLC_HAVE_64_ATOMIC + +#endif // __CLC_SCALAR diff --git a/libclc/opencl/include/clc/opencl/types.h b/libclc/opencl/include/clc/opencl/types.h new file mode 100644 index 0000000000000..b1be88f21bdaa --- /dev/null +++ b/libclc/opencl/include/clc/opencl/types.h @@ -0,0 +1,48 @@ +//===----------------------------------------------------------------------===// +// +// 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 __CLC_OPENCL_TYPES_H__ +#define __CLC_OPENCL_TYPES_H__ + +// Copied from clang/lib/Headers/opencl-c-base.h + +typedef enum memory_scope { + memory_scope_work_item = __OPENCL_MEMORY_SCOPE_WORK_ITEM, + memory_scope_work_group = __OPENCL_MEMORY_SCOPE_WORK_GROUP, + memory_scope_device = __OPENCL_MEMORY_SCOPE_DEVICE, +#if defined(__opencl_c_atomic_scope_all_devices) + memory_scope_all_svm_devices = __OPENCL_MEMORY_SCOPE_ALL_SVM_DEVICES, +#if (__OPENCL_C_VERSION__ >= CL_VERSION_3_0 || __OPENCL_CPP_VERSION__ >= 202100) + memory_scope_all_devices = memory_scope_all_svm_devices, +#endif // (__OPENCL_C_VERSION__ >= CL_VERSION_3_0 || __OPENCL_CPP_VERSION__ >= + // 202100) +#endif // defined(__opencl_c_atomic_scope_all_devices) +/** + * Subgroups have different requirements on forward progress, so just test + * all the relevant macros. + * CL 3.0 sub-groups "they are not guaranteed to make independent forward + * progress" KHR subgroups "Subgroups within a workgroup are independent, make + * forward progress with respect to each other" + */ +#if defined(cl_intel_subgroups) || defined(cl_khr_subgroups) || \ + defined(__opencl_c_subgroups) + memory_scope_sub_group = __OPENCL_MEMORY_SCOPE_SUB_GROUP +#endif +} memory_scope; + +typedef enum memory_order { + memory_order_relaxed = __ATOMIC_RELAXED, + memory_order_acquire = __ATOMIC_ACQUIRE, + memory_order_release = __ATOMIC_RELEASE, + memory_order_acq_rel = __ATOMIC_ACQ_REL, +#if defined(__opencl_c_atomic_order_seq_cst) + memory_order_seq_cst = __ATOMIC_SEQ_CST +#endif +} memory_order; + +#endif // __CLC_OPENCL_TYPES_H__ diff --git a/libclc/opencl/include/clc/opencl/utils.h b/libclc/opencl/include/clc/opencl/utils.h new file mode 100644 index 0000000000000..42b948b8d30d2 --- /dev/null +++ b/libclc/opencl/include/clc/opencl/utils.h @@ -0,0 +1,35 @@ +//===----------------------------------------------------------------------===// +// +// 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 __CLC_OPENCL_UTILS_H__ +#define __CLC_OPENCL_UTILS_H__ + +#include +#include + +// INTEL_FEATURE_PISA +static _CLC_INLINE int __opencl_get_clang_memory_scope(memory_scope scope) { + switch (scope) { + case __OPENCL_MEMORY_SCOPE_WORK_ITEM: + return __MEMORY_SCOPE_SINGLE; +#if defined(cl_intel_subgroups) || defined(cl_khr_subgroups) || \ + defined(__opencl_c_subgroups) + case __OPENCL_MEMORY_SCOPE_SUB_GROUP: + return __MEMORY_SCOPE_WVFRNT; +#endif + case __OPENCL_MEMORY_SCOPE_WORK_GROUP: + return __MEMORY_SCOPE_WRKGRP; + case __OPENCL_MEMORY_SCOPE_DEVICE: + return __MEMORY_SCOPE_DEVICE; + default: + return __MEMORY_SCOPE_SYSTEM; + } +} +// end INTEL_FEATURE_PISA + +#endif // __CLC_OPENCL_UTILS_H__ diff --git a/libclc/opencl/lib/generic/SOURCES b/libclc/opencl/lib/generic/SOURCES index 61757efbcaad7..94a333e765b18 100644 --- a/libclc/opencl/lib/generic/SOURCES +++ b/libclc/opencl/lib/generic/SOURCES @@ -22,7 +22,10 @@ atomic/atomic_fetch_min.cl atomic/atomic_fetch_or.cl atomic/atomic_fetch_sub.cl atomic/atomic_fetch_xor.cl +atomic/atomic_flag_clear.cl +atomic/atomic_flag_test_and_set.cl atomic/atomic_inc.cl +atomic/atomic_init.cl atomic/atomic_load.cl atomic/atomic_max.cl atomic/atomic_min.cl diff --git a/libclc/opencl/lib/generic/atomic/atomic_flag_clear.cl b/libclc/opencl/lib/generic/atomic/atomic_flag_clear.cl new file mode 100644 index 0000000000000..c9f944903f831 --- /dev/null +++ b/libclc/opencl/lib/generic/atomic/atomic_flag_clear.cl @@ -0,0 +1,61 @@ +//===----------------------------------------------------------------------===// +// +// 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 +#include +#include + +#if defined(__opencl_c_atomic_order_seq_cst) && \ + defined(__opencl_c_atomic_scope_device) + +#define __CLC_DEFINE_ATOMIC_FLAG_CLEAR(ADDRSPACE) \ + _CLC_OVERLOAD _CLC_DEF void atomic_flag_clear( \ + volatile ADDRSPACE atomic_flag *object) { \ + __clc_atomic_flag_clear((ADDRSPACE int *)object, __ATOMIC_SEQ_CST, \ + __MEMORY_SCOPE_DEVICE); \ + } + +__CLC_DEFINE_ATOMIC_FLAG_CLEAR(global) +__CLC_DEFINE_ATOMIC_FLAG_CLEAR(local) +#if defined(__opencl_c_generic_address_space) +__CLC_DEFINE_ATOMIC_FLAG_CLEAR() +#endif + +#endif // defined(__opencl_c_atomic_order_seq_cst) && + // defined(__opencl_c_atomic_scope_device) + +#if defined(__opencl_c_atomic_scope_device) + +#define __CLC_DEFINE_ATOMIC_FLAG_CLEAR_ORDER(ADDRSPACE) \ + _CLC_OVERLOAD _CLC_DEF void atomic_flag_clear_explicit( \ + volatile ADDRSPACE atomic_flag *object, memory_order order) { \ + __clc_atomic_flag_clear((ADDRSPACE int *)object, order, \ + __MEMORY_SCOPE_DEVICE); \ + } + +__CLC_DEFINE_ATOMIC_FLAG_CLEAR_ORDER(global) +__CLC_DEFINE_ATOMIC_FLAG_CLEAR_ORDER(local) +#if defined(__opencl_c_generic_address_space) +__CLC_DEFINE_ATOMIC_FLAG_CLEAR_ORDER() +#endif + +#endif // defined(__opencl_c_atomic_scope_device) + +#define __CLC_DEFINE_ATOMIC_FLAG_CLEAR_ORDER_SCOPE(ADDRSPACE) \ + _CLC_OVERLOAD _CLC_DEF void atomic_flag_clear_explicit( \ + volatile ADDRSPACE atomic_flag *object, memory_order order, \ + memory_scope scope) { \ + __clc_atomic_flag_clear((ADDRSPACE int *)object, order, \ + __opencl_get_clang_memory_scope(scope)); \ + } + +__CLC_DEFINE_ATOMIC_FLAG_CLEAR_ORDER_SCOPE(global) +__CLC_DEFINE_ATOMIC_FLAG_CLEAR_ORDER_SCOPE(local) +#if defined(__opencl_c_generic_address_space) +__CLC_DEFINE_ATOMIC_FLAG_CLEAR_ORDER_SCOPE() +#endif diff --git a/libclc/opencl/lib/generic/atomic/atomic_flag_test_and_set.cl b/libclc/opencl/lib/generic/atomic/atomic_flag_test_and_set.cl new file mode 100644 index 0000000000000..e58079ee226a1 --- /dev/null +++ b/libclc/opencl/lib/generic/atomic/atomic_flag_test_and_set.cl @@ -0,0 +1,66 @@ +//===----------------------------------------------------------------------===// +// +// 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 +#include +#include + +#if defined(__opencl_c_atomic_order_seq_cst) && \ + defined(__opencl_c_atomic_scope_device) + +#define __CLC_DEFINE_ATOMIC_FLAG_TEST_AND_SET(ADDRSPACE) \ + _CLC_OVERLOAD _CLC_DEF bool atomic_flag_test_and_set( \ + volatile ADDRSPACE atomic_flag *object) { \ + return __clc_atomic_flag_test_and_set( \ + (ADDRSPACE int *)object, __ATOMIC_SEQ_CST, __MEMORY_SCOPE_DEVICE); \ + } + +__CLC_DEFINE_ATOMIC_FLAG_TEST_AND_SET(global) +__CLC_DEFINE_ATOMIC_FLAG_TEST_AND_SET(local) +#if defined(__opencl_c_generic_address_space) +__CLC_DEFINE_ATOMIC_FLAG_TEST_AND_SET() +#endif + +#undef __CLC_DEFINE_ATOMIC_FLAG_TEST_AND_SET + +#endif // defined(__opencl_c_atomic_order_seq_cst) && + // defined(__opencl_c_atomic_scope_device) + +#if defined(__opencl_c_atomic_scope_device) + +#define __CLC_DEFINE_ATOMIC_FLAG_TEST_AND_SET(ADDRSPACE) \ + _CLC_OVERLOAD _CLC_DEF bool atomic_flag_test_and_set_explicit( \ + volatile ADDRSPACE atomic_flag *object, memory_order order) { \ + return __clc_atomic_flag_test_and_set((ADDRSPACE int *)object, order, \ + __MEMORY_SCOPE_DEVICE); \ + } + +__CLC_DEFINE_ATOMIC_FLAG_TEST_AND_SET(global) +__CLC_DEFINE_ATOMIC_FLAG_TEST_AND_SET(local) +#if defined(__opencl_c_generic_address_space) +__CLC_DEFINE_ATOMIC_FLAG_TEST_AND_SET() +#endif + +#undef __CLC_DEFINE_ATOMIC_FLAG_TEST_AND_SET + +#endif // defined(__opencl_c_atomic_scope_device) + +#define __CLC_DEFINE_ATOMIC_FLAG_TEST_AND_SET(ADDRSPACE) \ + _CLC_OVERLOAD _CLC_DEF bool atomic_flag_test_and_set_explicit( \ + volatile ADDRSPACE atomic_flag *object, memory_order order, \ + memory_scope scope) { \ + return __clc_atomic_flag_test_and_set( \ + (ADDRSPACE int *)object, order, \ + __opencl_get_clang_memory_scope(scope)); \ + } + +__CLC_DEFINE_ATOMIC_FLAG_TEST_AND_SET(global) +__CLC_DEFINE_ATOMIC_FLAG_TEST_AND_SET(local) +#if defined(__opencl_c_generic_address_space) +__CLC_DEFINE_ATOMIC_FLAG_TEST_AND_SET() +#endif diff --git a/libclc/opencl/lib/generic/atomic/atomic_init.cl b/libclc/opencl/lib/generic/atomic/atomic_init.cl new file mode 100644 index 0000000000000..b688d9b04da74 --- /dev/null +++ b/libclc/opencl/lib/generic/atomic/atomic_init.cl @@ -0,0 +1,18 @@ +//===----------------------------------------------------------------------===// +// +// 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 +#include + +#define __CLC_ATOMIC_GENTYPE __CLC_XCONCAT(atomic_, __CLC_GENTYPE) + +#define __CLC_BODY +#include + +#define __CLC_BODY +#include diff --git a/libclc/opencl/lib/generic/atomic/atomic_init.inc b/libclc/opencl/lib/generic/atomic/atomic_init.inc new file mode 100644 index 0000000000000..2e23df76a8c15 --- /dev/null +++ b/libclc/opencl/lib/generic/atomic/atomic_init.inc @@ -0,0 +1,46 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifdef __CLC_SCALAR + +#if defined(__opencl_c_fp64) && (defined(cl_khr_int64_base_atomics) && \ + defined(cl_khr_int64_extended_atomics)) +#define __CLC_HAVE_64_ATOMIC +#endif +#if defined(__CLC_FPSIZE) && \ + (__CLC_FPSIZE < 64 || defined(__CLC_HAVE_64_ATOMIC)) +#define __CLC_HAVE_FP_ATOMIC +#endif +#if defined(__CLC_GENSIZE) && \ + ((__CLC_GENSIZE == 32) || \ + (__CLC_GENSIZE == 64 && defined(__CLC_HAVE_64_ATOMIC))) +#define __CLC_HAVE_INT_ATOMIC +#endif +#if defined(__CLC_HAVE_FP_ATOMIC) || defined(__CLC_HAVE_INT_ATOMIC) + +#define __CLC_DEFINE_ATOMIC(ADDRSPACE) \ + _CLC_OVERLOAD _CLC_DEF void atomic_init( \ + volatile ADDRSPACE __CLC_ATOMIC_GENTYPE *Ptr, __CLC_GENTYPE Value) { \ + *(ADDRSPACE __CLC_GENTYPE *)Ptr = Value; \ + } + +__CLC_DEFINE_ATOMIC(global) +__CLC_DEFINE_ATOMIC(local) +#if _CLC_GENERIC_AS_SUPPORTED +__CLC_DEFINE_ATOMIC() +#endif + +#undef __CLC_DEFINE_ATOMIC + +#endif // __CLC_HAVE_FP_ATOMIC || __CLC_HAVE_INT_ATOMIC + +#undef __CLC_HAVE_INT_ATOMIC +#undef __CLC_HAVE_FP_ATOMIC +#undef __CLC_HAVE_64_ATOMIC + +#endif // __CLC_SCALAR From 81e91ea1c52a77093a44a186958cca29cf4d3dd8 Mon Sep 17 00:00:00 2001 From: Chengjun Date: Mon, 24 Nov 2025 16:11:05 -0800 Subject: [PATCH 37/50] [NVPTX] Use PRMT instruction to lower i16 bswap (#168968) Previously, i16 `bswap` was lowered using multiple shift and OR operations. This patch adds a pattern to directly lower i16 `bswap` using the `PRMT` (permute) instruction, which is more efficient. Additionally, the lowering of `bswap` is moved into operation legalization, which allows for DAGCombiner to optimize the lowered code. --- llvm/lib/Target/NVPTX/NVPTXISelLowering.cpp | 47 ++++++++++++- llvm/lib/Target/NVPTX/NVPTXInstrInfo.td | 32 --------- llvm/test/CodeGen/NVPTX/bswap.ll | 74 +++++++++------------ 3 files changed, 77 insertions(+), 76 deletions(-) diff --git a/llvm/lib/Target/NVPTX/NVPTXISelLowering.cpp b/llvm/lib/Target/NVPTX/NVPTXISelLowering.cpp index a77eb0240e677..454a237b1be78 100644 --- a/llvm/lib/Target/NVPTX/NVPTXISelLowering.cpp +++ b/llvm/lib/Target/NVPTX/NVPTXISelLowering.cpp @@ -713,8 +713,6 @@ NVPTXTargetLowering::NVPTXTargetLowering(const NVPTXTargetMachine &TM, Custom); } - setOperationAction(ISD::BSWAP, MVT::i16, Expand); - setOperationAction(ISD::BR_JT, MVT::Other, Custom); setOperationAction(ISD::BRIND, MVT::Other, Expand); @@ -1106,6 +1104,10 @@ NVPTXTargetLowering::NVPTXTargetLowering(const NVPTXTargetMachine &TM, // * MVT::Other - internal.addrspace.wrap setOperationAction(ISD::INTRINSIC_WO_CHAIN, {MVT::i32, MVT::i128, MVT::v4f32, MVT::Other}, Custom); + + // Custom lowering for bswap + setOperationAction(ISD::BSWAP, {MVT::i16, MVT::i32, MVT::i64, MVT::v2i16}, + Custom); } TargetLoweringBase::LegalizeTypeAction @@ -2570,6 +2572,44 @@ static SDValue lowerTcgen05St(SDValue Op, SelectionDAG &DAG) { return Tcgen05StNode; } +static SDValue lowerBSWAP(SDValue Op, SelectionDAG &DAG) { + SDLoc DL(Op); + SDValue Src = Op.getOperand(0); + EVT VT = Op.getValueType(); + + switch (VT.getSimpleVT().SimpleTy) { + case MVT::i16: { + SDValue Extended = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i32, Src); + SDValue Swapped = + getPRMT(Extended, DAG.getConstant(0, DL, MVT::i32), 0x7701, DL, DAG); + return DAG.getNode(ISD::TRUNCATE, DL, MVT::i16, Swapped); + } + case MVT::i32: { + return getPRMT(Src, DAG.getConstant(0, DL, MVT::i32), 0x0123, DL, DAG); + } + case MVT::v2i16: { + SDValue Converted = DAG.getBitcast(MVT::i32, Src); + SDValue Swapped = + getPRMT(Converted, DAG.getConstant(0, DL, MVT::i32), 0x2301, DL, DAG); + return DAG.getNode(ISD::BITCAST, DL, MVT::v2i16, Swapped); + } + case MVT::i64: { + SDValue UnpackSrc = + DAG.getNode(NVPTXISD::UNPACK_VECTOR, DL, {MVT::i32, MVT::i32}, Src); + SDValue SwappedLow = + getPRMT(UnpackSrc.getValue(0), DAG.getConstant(0, DL, MVT::i32), 0x0123, + DL, DAG); + SDValue SwappedHigh = + getPRMT(UnpackSrc.getValue(1), DAG.getConstant(0, DL, MVT::i32), 0x0123, + DL, DAG); + return DAG.getNode(NVPTXISD::BUILD_VECTOR, DL, MVT::i64, + {SwappedHigh, SwappedLow}); + } + default: + llvm_unreachable("unsupported type for bswap"); + } +} + static unsigned getTcgen05MMADisableOutputLane(unsigned IID) { switch (IID) { case Intrinsic::nvvm_tcgen05_mma_shared_disable_output_lane_cg1: @@ -3193,7 +3233,8 @@ NVPTXTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const { return lowerCTLZCTPOP(Op, DAG); case ISD::FREM: return lowerFREM(Op, DAG); - + case ISD::BSWAP: + return lowerBSWAP(Op, DAG); default: llvm_unreachable("Custom lowering not defined for operation"); } diff --git a/llvm/lib/Target/NVPTX/NVPTXInstrInfo.td b/llvm/lib/Target/NVPTX/NVPTXInstrInfo.td index 8b129e7e5eeae..04e2dd435cdf0 100644 --- a/llvm/lib/Target/NVPTX/NVPTXInstrInfo.td +++ b/llvm/lib/Target/NVPTX/NVPTXInstrInfo.td @@ -2468,38 +2468,6 @@ let Predicates = [hasPTX<73>, hasSM<52>] in { include "NVPTXIntrinsics.td" -//----------------------------------- -// Notes -//----------------------------------- -// BSWAP is currently expanded. The following is a more efficient -// - for < sm_20, use vector scalar mov, as tesla support native 16-bit register -// - for sm_20, use pmpt (use vector scalar mov to get the pack and -// unpack). sm_20 supports native 32-bit register, but not native 16-bit -// register. - -def : Pat < - (i32 (bswap i32:$a)), - (PRMT_B32rii $a, (i32 0), (i32 0x0123), PrmtNONE)>; - -def : Pat < - (v2i16 (bswap v2i16:$a)), - (PRMT_B32rii $a, (i32 0), (i32 0x2301), PrmtNONE)>; - -def : Pat < - (i64 (bswap i64:$a)), - (V2I32toI64 - (PRMT_B32rii (I64toI32H_Sink $a), (i32 0), (i32 0x0123), PrmtNONE), - (PRMT_B32rii (I64toI32L_Sink $a), (i32 0), (i32 0x0123), PrmtNONE))>, - Requires<[hasPTX<71>]>; - -// Fall back to the old way if we don't have PTX 7.1. -def : Pat < - (i64 (bswap i64:$a)), - (V2I32toI64 - (PRMT_B32rii (I64toI32H $a), (i32 0), (i32 0x0123), PrmtNONE), - (PRMT_B32rii (I64toI32L $a), (i32 0), (i32 0x0123), PrmtNONE))>; - - //////////////////////////////////////////////////////////////////////////////// // PTX Fence instructions //////////////////////////////////////////////////////////////////////////////// diff --git a/llvm/test/CodeGen/NVPTX/bswap.ll b/llvm/test/CodeGen/NVPTX/bswap.ll index e3d1c80922609..8050c6f1c7031 100644 --- a/llvm/test/CodeGen/NVPTX/bswap.ll +++ b/llvm/test/CodeGen/NVPTX/bswap.ll @@ -1,25 +1,18 @@ ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 4 -; RUN: llc < %s -mtriple=nvptx64 -mcpu=sm_20 -mattr=+ptx70 | FileCheck -check-prefixes CHECK,PTX70 %s +; RUN: llc < %s -mtriple=nvptx64 -mcpu=sm_20 | FileCheck %s ; RUN: %if ptxas %{ llc < %s -mtriple=nvptx64 -mcpu=sm_20 | %ptxas-verify %} -; RUN: %if ptxas-isa-7.0 %{ llc < %s -mtriple=nvptx64 -mcpu=sm_20 -mattr=+ptx70 | %ptxas-verify %} -; RUN: llc < %s -mtriple=nvptx64 -mcpu=sm_20 -mattr=+ptx71 | FileCheck -check-prefixes CHECK,PTX71 %s -; RUN: %if ptxas-isa-7.1 %{ llc < %s -mtriple=nvptx64 -mcpu=sm_20 -mattr=+ptx71 | %ptxas-verify %} target triple = "nvptx64-nvidia-cuda" define i16 @bswap16(i16 %a) { ; CHECK-LABEL: bswap16( ; CHECK: { -; CHECK-NEXT: .reg .b16 %rs<5>; -; CHECK-NEXT: .reg .b32 %r<2>; +; CHECK-NEXT: .reg .b32 %r<3>; ; CHECK-EMPTY: ; CHECK-NEXT: // %bb.0: -; CHECK-NEXT: ld.param.b16 %rs1, [bswap16_param_0]; -; CHECK-NEXT: shr.u16 %rs2, %rs1, 8; -; CHECK-NEXT: shl.b16 %rs3, %rs1, 8; -; CHECK-NEXT: or.b16 %rs4, %rs3, %rs2; -; CHECK-NEXT: cvt.u32.u16 %r1, %rs4; -; CHECK-NEXT: st.param.b32 [func_retval0], %r1; +; CHECK-NEXT: ld.param.b16 %r1, [bswap16_param_0]; +; CHECK-NEXT: prmt.b32 %r2, %r1, 0, 0x7701U; +; CHECK-NEXT: st.param.b32 [func_retval0], %r2; ; CHECK-NEXT: ret; %b = tail call i16 @llvm.bswap.i16(i16 %a) ret i16 %b @@ -56,40 +49,39 @@ define <2 x i16> @bswapv2i16(<2 x i16> %a) #0 { } define i64 @bswap64(i64 %a) { -; PTX70-LABEL: bswap64( -; PTX70: { -; PTX70-NEXT: .reg .b32 %r<5>; -; PTX70-NEXT: .reg .b64 %rd<3>; -; PTX70-EMPTY: -; PTX70-NEXT: // %bb.0: -; PTX70-NEXT: ld.param.b64 %rd1, [bswap64_param_0]; -; PTX70-NEXT: { .reg .b32 tmp; mov.b64 {%r1, tmp}, %rd1; } -; PTX70-NEXT: prmt.b32 %r2, %r1, 0, 0x123U; -; PTX70-NEXT: { .reg .b32 tmp; mov.b64 {tmp, %r3}, %rd1; } -; PTX70-NEXT: prmt.b32 %r4, %r3, 0, 0x123U; -; PTX70-NEXT: mov.b64 %rd2, {%r4, %r2}; -; PTX70-NEXT: st.param.b64 [func_retval0], %rd2; -; PTX70-NEXT: ret; -; -; PTX71-LABEL: bswap64( -; PTX71: { -; PTX71-NEXT: .reg .b32 %r<5>; -; PTX71-NEXT: .reg .b64 %rd<3>; -; PTX71-EMPTY: -; PTX71-NEXT: // %bb.0: -; PTX71-NEXT: ld.param.b64 %rd1, [bswap64_param_0]; -; PTX71-NEXT: mov.b64 {%r1, _}, %rd1; -; PTX71-NEXT: prmt.b32 %r2, %r1, 0, 0x123U; -; PTX71-NEXT: mov.b64 {_, %r3}, %rd1; -; PTX71-NEXT: prmt.b32 %r4, %r3, 0, 0x123U; -; PTX71-NEXT: mov.b64 %rd2, {%r4, %r2}; -; PTX71-NEXT: st.param.b64 [func_retval0], %rd2; -; PTX71-NEXT: ret; +; CHECK-LABEL: bswap64( +; CHECK: { +; CHECK-NEXT: .reg .b32 %r<5>; +; CHECK-NEXT: .reg .b64 %rd<3>; +; CHECK-EMPTY: +; CHECK-NEXT: // %bb.0: +; CHECK-NEXT: ld.param.b64 %rd1, [bswap64_param_0]; +; CHECK-NEXT: mov.b64 {%r1, %r2}, %rd1; +; CHECK-NEXT: prmt.b32 %r3, %r1, 0, 0x123U; +; CHECK-NEXT: prmt.b32 %r4, %r2, 0, 0x123U; +; CHECK-NEXT: mov.b64 %rd2, {%r4, %r3}; +; CHECK-NEXT: st.param.b64 [func_retval0], %rd2; +; CHECK-NEXT: ret; %b = tail call i64 @llvm.bswap.i64(i64 %a) ret i64 %b } +define <2 x i32> @bswapv2i32(<2 x i32> %a) { +; CHECK-LABEL: bswapv2i32( +; CHECK: { +; CHECK-NEXT: .reg .b32 %r<5>; +; CHECK-EMPTY: +; CHECK-NEXT: // %bb.0: +; CHECK-NEXT: ld.param.v2.b32 {%r1, %r2}, [bswapv2i32_param_0]; +; CHECK-NEXT: prmt.b32 %r3, %r2, 0, 0x123U; +; CHECK-NEXT: prmt.b32 %r4, %r1, 0, 0x123U; +; CHECK-NEXT: st.param.v2.b32 [func_retval0], {%r4, %r3}; +; CHECK-NEXT: ret; + %b = tail call <2 x i32> @llvm.bswap.v2i32(<2 x i32> %a) + ret <2 x i32> %b +} declare i16 @llvm.bswap.i16(i16) declare i32 @llvm.bswap.i32(i32) declare <2 x i16> @llvm.bswap.v2i16(<2 x i16>) declare i64 @llvm.bswap.i64(i64) +declare <2 x i32> @llvm.bswap.v2i32(<2 x i32>) From ac4cf404d8f39e316f37c3732ab75be729604107 Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Mon, 24 Nov 2025 16:21:28 -0800 Subject: [PATCH 38/50] [bazel] Use zstd from the BCR (#169146) This way if the downstream consuming project uses zstd we make sure they are dedup'd. This uses a new rule to make sure layering_check still works while allowing us to augment the upstream library rules with LLVM specific `defines`. --- utils/bazel/MODULE.bazel | 2 +- utils/bazel/MODULE.bazel.lock | 17 ++----- utils/bazel/extensions.bzl | 10 ---- .../llvm-project-overlay/lld/BUILD.bazel | 2 +- .../llvm-project-overlay/llvm/BUILD.bazel | 2 +- .../third-party/BUILD.bazel | 34 +++++++++++++ .../third-party/cc_library_wrapper.bzl | 50 +++++++++++++++++++ utils/bazel/third_party_build/zstd.BUILD | 18 ++----- 8 files changed, 95 insertions(+), 40 deletions(-) create mode 100644 utils/bazel/llvm-project-overlay/third-party/BUILD.bazel create mode 100644 utils/bazel/llvm-project-overlay/third-party/cc_library_wrapper.bzl diff --git a/utils/bazel/MODULE.bazel b/utils/bazel/MODULE.bazel index 1a8327c33d246..cf760ba24cb4c 100644 --- a/utils/bazel/MODULE.bazel +++ b/utils/bazel/MODULE.bazel @@ -15,6 +15,7 @@ bazel_dep(name = "rules_cc", version = "0.2.11") bazel_dep(name = "rules_foreign_cc", version = "0.15.1") bazel_dep(name = "rules_python", version = "1.6.3") bazel_dep(name = "rules_shell", version = "0.6.1") +bazel_dep(name = "zstd", version = "1.5.7", repo_name = "llvm_zstd") llvm_repos_extension = use_extension(":extensions.bzl", "llvm_repos_extension") use_repo( @@ -22,7 +23,6 @@ use_repo( "gmp", "llvm-raw", "llvm_zlib", - "llvm_zstd", "mpc", "mpfr", "nanobind", diff --git a/utils/bazel/MODULE.bazel.lock b/utils/bazel/MODULE.bazel.lock index 3b196231c6723..c923f3aaea68d 100644 --- a/utils/bazel/MODULE.bazel.lock +++ b/utils/bazel/MODULE.bazel.lock @@ -224,13 +224,15 @@ "https://bcr.bazel.build/modules/zlib/1.2.12/MODULE.bazel": "3b1a8834ada2a883674be8cbd36ede1b6ec481477ada359cd2d3ddc562340b27", "https://bcr.bazel.build/modules/zlib/1.3.1.bcr.5/MODULE.bazel": "eec517b5bbe5492629466e11dae908d043364302283de25581e3eb944326c4ca", "https://bcr.bazel.build/modules/zlib/1.3.1.bcr.5/source.json": "22bc55c47af97246cfc093d0acf683a7869377de362b5d1c552c2c2e16b7a806", - "https://bcr.bazel.build/modules/zlib/1.3.1/MODULE.bazel": "751c9940dcfe869f5f7274e1295422a34623555916eb98c174c1e945594bf198" + "https://bcr.bazel.build/modules/zlib/1.3.1/MODULE.bazel": "751c9940dcfe869f5f7274e1295422a34623555916eb98c174c1e945594bf198", + "https://bcr.bazel.build/modules/zstd/1.5.7/MODULE.bazel": "f5780cdbd6f4c5bb985a20f839844316fe48fb5e463056f372dbc37cfabdf450", + "https://bcr.bazel.build/modules/zstd/1.5.7/source.json": "f72c48184b6528ffc908a5a2bcbf3070c6684f3db03da2182c8ca999ae5f5cfd" }, "selectedYankedVersions": {}, "moduleExtensions": { "//:extensions.bzl%llvm_repos_extension": { "general": { - "bzlTransitiveDigest": "ojj7cD2YU2vcH58jVPVj2juUYn5SvdSNj1pmWb8Xo/k=", + "bzlTransitiveDigest": "05R8ZuqDbhn1LOyXHQzta+x0dI9dEY6RIu21atUo+Kw=", "usagesDigest": "X0yUkkWyxQ2Y5oZVDkRSE/K4YkDWo1IjhHsL+1weKyU=", "recordedFileInputs": {}, "recordedDirentsInputs": {}, @@ -314,17 +316,6 @@ "build_file": "@@+llvm_repos_extension+llvm-raw//utils/bazel/third_party_build:pfm.BUILD" } }, - "llvm_zstd": { - "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", - "attributes": { - "build_file": "@@+llvm_repos_extension+llvm-raw//utils/bazel/third_party_build:zstd.BUILD", - "sha256": "7c42d56fac126929a6a85dbc73ff1db2411d04f104fae9bdea51305663a83fd0", - "strip_prefix": "zstd-1.5.2", - "urls": [ - "https://github.com/facebook/zstd/releases/download/v1.5.2/zstd-1.5.2.tar.gz" - ] - } - }, "pybind11": { "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", "attributes": { diff --git a/utils/bazel/extensions.bzl b/utils/bazel/extensions.bzl index bb5ce1955f916..e57046530aa89 100644 --- a/utils/bazel/extensions.bzl +++ b/utils/bazel/extensions.bzl @@ -79,16 +79,6 @@ def _llvm_repos_extension_impl(module_ctx): build_file = "@llvm-raw//utils/bazel/third_party_build:pfm.BUILD", ) - http_archive( - name = "llvm_zstd", - build_file = "@llvm-raw//utils/bazel/third_party_build:zstd.BUILD", - sha256 = "7c42d56fac126929a6a85dbc73ff1db2411d04f104fae9bdea51305663a83fd0", - strip_prefix = "zstd-1.5.2", - urls = [ - "https://github.com/facebook/zstd/releases/download/v1.5.2/zstd-1.5.2.tar.gz", - ], - ) - http_archive( name = "pybind11", url = "https://github.com/pybind/pybind11/archive/v2.10.3.zip", diff --git a/utils/bazel/llvm-project-overlay/lld/BUILD.bazel b/utils/bazel/llvm-project-overlay/lld/BUILD.bazel index 162c4f955d150..8a03266da6327 100644 --- a/utils/bazel/llvm-project-overlay/lld/BUILD.bazel +++ b/utils/bazel/llvm-project-overlay/lld/BUILD.bazel @@ -105,8 +105,8 @@ cc_library( "//llvm:TargetParser", "//llvm:TransformUtils", "//llvm:config", + "//third-party:zstd", "@llvm_zlib//:zlib", - "@llvm_zstd//:zstd", ], ) diff --git a/utils/bazel/llvm-project-overlay/llvm/BUILD.bazel b/utils/bazel/llvm-project-overlay/llvm/BUILD.bazel index f67e4ea29b51f..b59e6ea973f14 100644 --- a/utils/bazel/llvm-project-overlay/llvm/BUILD.bazel +++ b/utils/bazel/llvm-project-overlay/llvm/BUILD.bazel @@ -331,7 +331,7 @@ cc_library( # We unconditionally depend on the custom LLVM zstd wrapper. This will # be an empty library unless zstd is enabled, in which case it will # both provide the necessary dependencies and configuration defines. - "@llvm_zstd//:zstd", + "//third-party:zstd", ], ) diff --git a/utils/bazel/llvm-project-overlay/third-party/BUILD.bazel b/utils/bazel/llvm-project-overlay/third-party/BUILD.bazel new file mode 100644 index 0000000000000..bf780b5f3c0bf --- /dev/null +++ b/utils/bazel/llvm-project-overlay/third-party/BUILD.bazel @@ -0,0 +1,34 @@ +# This file is licensed 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 +load("@bazel_skylib//rules:common_settings.bzl", "bool_flag") +load(":cc_library_wrapper.bzl", "cc_library_wrapper") + +package(default_visibility = ["//visibility:public"]) + +bool_flag( + name = "llvm_enable_zstd", + build_setting_default = True, +) + +config_setting( + name = "llvm_zstd_enabled", + flag_values = {":llvm_enable_zstd": "true"}, +) + +cc_library_wrapper( + name = "zstd", + defines = select({ + ":llvm_zstd_enabled": [ + "LLVM_ENABLE_ZSTD=1", + "ZSTD_MULTITHREAD", + ], + "//conditions:default": [], + }), + deps = select({ + ":llvm_zstd_enabled": [ + "@llvm_zstd//:zstd", + ], + "//conditions:default": [], + }), +) diff --git a/utils/bazel/llvm-project-overlay/third-party/cc_library_wrapper.bzl b/utils/bazel/llvm-project-overlay/third-party/cc_library_wrapper.bzl new file mode 100644 index 0000000000000..b484a611571e3 --- /dev/null +++ b/utils/bazel/llvm-project-overlay/third-party/cc_library_wrapper.bzl @@ -0,0 +1,50 @@ +# This file is licensed 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 + +"""Re-export a cc_library with added LLVM specific settings. + +This re-exports the dependent libraries in a way that satisfies layering_check + +cc_library_wrapper( + name = "library_wrapper", + deps = [ + "@example//:library", + ], + defines = [ + "LLVM_ENABLE_EXAMPLE=1", + ], +) +""" + +load("@rules_cc//cc/common:cc_common.bzl", "cc_common") +load("@rules_cc//cc/common:cc_info.bzl", "CcInfo") + +visibility("private") + +def _cc_library_wrapper_impl(ctx): + all_cc_infos = [dep[CcInfo] for dep in ctx.attr.deps] + if ctx.attr.defines: + all_cc_infos.append(CcInfo( + compilation_context = cc_common.create_compilation_context( + defines = depset(ctx.attr.defines), + ), + )) + + return cc_common.merge_cc_infos(direct_cc_infos = all_cc_infos) + +cc_library_wrapper = rule( + implementation = _cc_library_wrapper_impl, + attrs = { + "deps": attr.label_list( + doc = "Dependencies to cc_library targets to re-export.", + providers = [CcInfo], + ), + "defines": attr.string_list( + doc = "Additional preprocessor definitions to add to all dependent targets.", + default = [], + ), + }, + doc = "Re-export a cc_library with added LLVM specific settings.", + provides = [CcInfo], +) diff --git a/utils/bazel/third_party_build/zstd.BUILD b/utils/bazel/third_party_build/zstd.BUILD index 7d022d4226de1..89da165225ad7 100644 --- a/utils/bazel/third_party_build/zstd.BUILD +++ b/utils/bazel/third_party_build/zstd.BUILD @@ -1,7 +1,7 @@ # This file is licensed 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 -load("@bazel_skylib//rules:common_settings.bzl", "bool_flag") +load("@rules_cc//cc:cc_library.bzl", "cc_library") package( default_visibility = ["//visibility:public"], @@ -9,20 +9,10 @@ package( licenses = ["notice"], ) -bool_flag( - name = "llvm_enable_zstd", - build_setting_default = True, -) - -config_setting( - name = "llvm_zstd_enabled", - flag_values = {":llvm_enable_zstd": "true"}, -) - cc_library( name = "zstd", srcs = select({ - ":llvm_zstd_enabled": glob([ + "@llvm-project//third-party:llvm_zstd_enabled": glob([ "lib/common/*.c", "lib/common/*.h", "lib/compress/*.c", @@ -36,7 +26,7 @@ cc_library( "//conditions:default": [], }), hdrs = select({ - ":llvm_zstd_enabled": [ + "@llvm-project//third-party:llvm_zstd_enabled": [ "lib/zdict.h", "lib/zstd.h", "lib/zstd_errors.h", @@ -44,7 +34,7 @@ cc_library( "//conditions:default": [], }), defines = select({ - ":llvm_zstd_enabled": [ + "@llvm-project//third-party:llvm_zstd_enabled": [ "LLVM_ENABLE_ZSTD=1", "ZSTD_MULTITHREAD", ], From e23328b45719683c76deae7fab9a24523bf25520 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Valentin=20Clement=20=28=E3=83=90=E3=83=AC=E3=83=B3?= =?UTF-8?q?=E3=82=BF=E3=82=A4=E3=83=B3=20=E3=82=AF=E3=83=AC=E3=83=A1?= =?UTF-8?q?=E3=83=B3=29?= Date: Mon, 24 Nov 2025 16:41:03 -0800 Subject: [PATCH 39/50] [flang][cuda] Add support for cluster_block_index in cooperative groups (#169427) --- .../Optimizer/Builder/CUDAIntrinsicCall.h | 1 + .../Optimizer/Builder/CUDAIntrinsicCall.cpp | 61 +++++++++++++------ flang/module/cooperative_groups.f90 | 7 +++ flang/test/Lower/CUDA/cuda-cluster.cuf | 21 +++++++ 4 files changed, 73 insertions(+), 17 deletions(-) diff --git a/flang/include/flang/Optimizer/Builder/CUDAIntrinsicCall.h b/flang/include/flang/Optimizer/Builder/CUDAIntrinsicCall.h index cedc7a9437eb5..977bc0f4ee58c 100644 --- a/flang/include/flang/Optimizer/Builder/CUDAIntrinsicCall.h +++ b/flang/include/flang/Optimizer/Builder/CUDAIntrinsicCall.h @@ -47,6 +47,7 @@ struct CUDAIntrinsicLibrary : IntrinsicLibrary { void genBarrierInit(llvm::ArrayRef); mlir::Value genBarrierTryWait(mlir::Type, llvm::ArrayRef); mlir::Value genBarrierTryWaitSleep(mlir::Type, llvm::ArrayRef); + mlir::Value genClusterBlockIndex(mlir::Type, llvm::ArrayRef); mlir::Value genClusterDimBlocks(mlir::Type, llvm::ArrayRef); void genFenceProxyAsync(llvm::ArrayRef); template diff --git a/flang/lib/Optimizer/Builder/CUDAIntrinsicCall.cpp b/flang/lib/Optimizer/Builder/CUDAIntrinsicCall.cpp index a770e2d9cdeff..a0d9678683e44 100644 --- a/flang/lib/Optimizer/Builder/CUDAIntrinsicCall.cpp +++ b/flang/lib/Optimizer/Builder/CUDAIntrinsicCall.cpp @@ -368,6 +368,11 @@ static constexpr IntrinsicHandler cudaHandlers[]{ &CI::genNVVMTime), {}, /*isElemental=*/false}, + {"cluster_block_index", + static_cast( + &CI::genClusterBlockIndex), + {}, + /*isElemental=*/false}, {"cluster_dim_blocks", static_cast( &CI::genClusterDimBlocks), @@ -990,6 +995,42 @@ CUDAIntrinsicLibrary::genBarrierTryWaitSleep(mlir::Type resultType, .getResult(0); } +static void insertValueAtPos(fir::FirOpBuilder &builder, mlir::Location loc, + fir::RecordType recTy, mlir::Value base, + mlir::Value dim, unsigned fieldPos) { + auto fieldName = recTy.getTypeList()[fieldPos].first; + mlir::Type fieldTy = recTy.getTypeList()[fieldPos].second; + mlir::Type fieldIndexType = fir::FieldType::get(base.getContext()); + mlir::Value fieldIndex = + fir::FieldIndexOp::create(builder, loc, fieldIndexType, fieldName, recTy, + /*typeParams=*/mlir::ValueRange{}); + mlir::Value coord = fir::CoordinateOp::create( + builder, loc, builder.getRefType(fieldTy), base, fieldIndex); + fir::StoreOp::create(builder, loc, dim, coord); +} + +// CLUSTER_BLOCK_INDEX +mlir::Value +CUDAIntrinsicLibrary::genClusterBlockIndex(mlir::Type resultType, + llvm::ArrayRef args) { + assert(args.size() == 0); + auto recTy = mlir::cast(resultType); + assert(recTy && "RecordType expepected"); + mlir::Value res = fir::AllocaOp::create(builder, loc, resultType); + mlir::Type i32Ty = builder.getI32Type(); + mlir::Value x = mlir::NVVM::BlockInClusterIdXOp::create(builder, loc, i32Ty); + mlir::Value one = builder.createIntegerConstant(loc, i32Ty, 1); + x = mlir::arith::AddIOp::create(builder, loc, x, one); + insertValueAtPos(builder, loc, recTy, res, x, 0); + mlir::Value y = mlir::NVVM::BlockInClusterIdYOp::create(builder, loc, i32Ty); + y = mlir::arith::AddIOp::create(builder, loc, y, one); + insertValueAtPos(builder, loc, recTy, res, y, 1); + mlir::Value z = mlir::NVVM::BlockInClusterIdZOp::create(builder, loc, i32Ty); + z = mlir::arith::AddIOp::create(builder, loc, z, one); + insertValueAtPos(builder, loc, recTy, res, z, 2); + return res; +} + // CLUSTER_DIM_BLOCKS mlir::Value CUDAIntrinsicLibrary::genClusterDimBlocks(mlir::Type resultType, @@ -998,27 +1039,13 @@ CUDAIntrinsicLibrary::genClusterDimBlocks(mlir::Type resultType, auto recTy = mlir::cast(resultType); assert(recTy && "RecordType expepected"); mlir::Value res = fir::AllocaOp::create(builder, loc, resultType); - - auto insertDim = [&](mlir::Value dim, unsigned fieldPos) { - auto fieldName = recTy.getTypeList()[fieldPos].first; - mlir::Type fieldTy = recTy.getTypeList()[fieldPos].second; - mlir::Type fieldIndexType = fir::FieldType::get(resultType.getContext()); - mlir::Value fieldIndex = fir::FieldIndexOp::create( - builder, loc, fieldIndexType, fieldName, recTy, - /*typeParams=*/mlir::ValueRange{}); - mlir::Value coord = fir::CoordinateOp::create( - builder, loc, builder.getRefType(fieldTy), res, fieldIndex); - fir::StoreOp::create(builder, loc, dim, coord); - }; - mlir::Type i32Ty = builder.getI32Type(); mlir::Value x = mlir::NVVM::ClusterDimBlocksXOp::create(builder, loc, i32Ty); - insertDim(x, 0); + insertValueAtPos(builder, loc, recTy, res, x, 0); mlir::Value y = mlir::NVVM::ClusterDimBlocksYOp::create(builder, loc, i32Ty); - insertDim(y, 1); + insertValueAtPos(builder, loc, recTy, res, y, 1); mlir::Value z = mlir::NVVM::ClusterDimBlocksZOp::create(builder, loc, i32Ty); - insertDim(z, 2); - + insertValueAtPos(builder, loc, recTy, res, z, 2); return res; } diff --git a/flang/module/cooperative_groups.f90 b/flang/module/cooperative_groups.f90 index 2631975837a5b..8bb4af3afa791 100644 --- a/flang/module/cooperative_groups.f90 +++ b/flang/module/cooperative_groups.f90 @@ -38,6 +38,13 @@ module cooperative_groups integer(4) :: rank end type thread_group +interface + attributes(device) function cluster_block_index() + import + type(dim3) :: cluster_block_index + end function +end interface + interface attributes(device) function cluster_dim_blocks() import diff --git a/flang/test/Lower/CUDA/cuda-cluster.cuf b/flang/test/Lower/CUDA/cuda-cluster.cuf index 51cc4208a35de..78cca15b11dab 100644 --- a/flang/test/Lower/CUDA/cuda-cluster.cuf +++ b/flang/test/Lower/CUDA/cuda-cluster.cuf @@ -32,3 +32,24 @@ end subroutine ! CHECK: %[[Z:.*]] = nvvm.read.ptx.sreg.cluster.nctaid.z : i32 ! CHECK: %[[COORD_Z:.*]] = fir.coordinate_of %{{.*}}, z : (!fir.ref>) -> !fir.ref ! CHECK: fir.store %[[Z]] to %[[COORD_Z]] : !fir.ref + +attributes(global) subroutine test_cluster_block_index() + use cooperative_groups + type(dim3) :: blockIndex + + blockIndex = cluster_block_index() +end subroutine + +! CHECK-LABEL: func.func @_QPtest_cluster_block_index() attributes {cuf.proc_attr = #cuf.cuda_proc} +! CHECK: %[[X:.*]] = nvvm.read.ptx.sreg.cluster.ctaid.x : i32 +! CHECK: %[[X1:.*]] = arith.addi %[[X]], %c1{{.*}} : i32 +! CHECK: %[[COORD_X:.*]] = fir.coordinate_of %{{.*}}, x : (!fir.ref>) -> !fir.ref +! CHECK: fir.store %[[X1]] to %[[COORD_X]] : !fir.ref +! CHECK: %[[Y:.*]] = nvvm.read.ptx.sreg.cluster.ctaid.y : i32 +! CHECK: %[[Y1:.*]] = arith.addi %[[Y]], %c1{{.*}} : i32 +! CHECK: %[[COORD_Y:.*]] = fir.coordinate_of %{{.*}}, y : (!fir.ref>) -> !fir.ref +! CHECK: fir.store %[[Y1]] to %[[COORD_Y]] : !fir.ref +! CHECK: %[[Z:.*]] = nvvm.read.ptx.sreg.cluster.ctaid.z : i32 +! CHECK: %[[Z1:.*]] = arith.addi %[[Z]], %c1{{.*}} : i32 +! CHECK: %[[COORD_Z:.*]] = fir.coordinate_of %{{.*}}, z : (!fir.ref>) -> !fir.ref +! CHECK: fir.store %[[Z1]] to %[[COORD_Z]] : !fir.ref From 1b8626b5064fc58caa8dfd268b8b854f9f1b8543 Mon Sep 17 00:00:00 2001 From: "Yaxun (Sam) Liu" Date: Mon, 24 Nov 2025 19:43:12 -0500 Subject: [PATCH 40/50] Improve HIP docs on fat binary registration ordering (#168566) Clarify how Clang-generated HIP fat binaries are registered and unregistered with the HIP runtime, and how this interacts with global constructors, destructors, and atexit handlers. Document that there is no strong guarantee on ordering relative to user-defined global ctors/dtors, recommend that HIP application developers avoid using kernels or device variables from global ctors/dtors, and describe the implications for HIP runtime developers (synchronization and guards in __hipRegisterFatBinary/__hipUnregisterFatBinary). This is motivated by questions from HIP application and runtime developers about fat binary registration/unregistration order and its potential interference with their own initialization and teardown code. --- clang/docs/HIPSupport.rst | 89 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/clang/docs/HIPSupport.rst b/clang/docs/HIPSupport.rst index ab9ea110e6d54..92ea07974373e 100644 --- a/clang/docs/HIPSupport.rst +++ b/clang/docs/HIPSupport.rst @@ -210,6 +210,95 @@ Host Code Compilation - These relocatable objects are then linked together. - Host code within a TU can call host functions and launch kernels from another TU. +HIP Fat Binary Registration and Unregistration +============================================== + +When compiling HIP for AMD GPUs, Clang embeds device code into HIP "fat +binaries" and generates host-side helper functions that register these +fat binaries with the HIP runtime at program start and unregister them at +program exit. In non-RDC mode (``-fno-gpu-rdc``), each compilation unit +typically produces its own HIP fat binary: a container that holds, for every +enabled GPU architecture, a fully linked offloading device image (for example, +a GPU code object) that can be loaded directly by the HIP runtime. In RDC mode +(``-fgpu-rdc``), each compilation unit contributes device code in a relocatable +form (for example, GPU object files or LLVM IR). A later device-link step links +those relocatable inputs into fully linked device images per GPU architecture +and then packages those images into a HIP fat binary container. + +Registering a HIP fat binary allows the runtime to discover the kernels and +device variables defined in that container and to associate host-side addresses +and symbols with the corresponding GPU-side entities. For example, when a +host-side kernel launch stub is called, the HIP runtime uses information +established during registration (and the fat binary handle it returned) to +identify which GPU kernel symbol to launch from which device image. + +At the LLVM IR level, Clang/LLVM typically create an internal module +constructor (for example ``__hip_module_ctor`` or a ``.hip.fatbin_reg`` +function) and add it to ``@llvm.global_ctors``. This constructor is called by +the C runtime before ``main`` and it: + +* calls ``__hipRegisterFatBinary`` with a pointer to an internal wrapper + object that describes the HIP fat binary; +* stores the returned handle in an internal global variable; +* calls an internal helper such as ``__hip_register_globals`` to register + kernels, device variables and other metadata associated with the fat binary; +* registers a corresponding module destructor with ``atexit`` so it will run + during program termination and use the stored handle to unregister the fat + binary from the HIP runtime. + +The module destructor (for example ``__hip_module_dtor`` or a +``.hip.fatbin_unreg`` function) loads the stored handle, checks that it is +non-null, calls ``__hipUnregisterFatBinary`` to unregister the fat binary from +the HIP runtime, and then clears the handle. This ensures that the HIP runtime +sees each fat binary registered exactly once and that it is unregistered once +at exit, even when multiple translation units contribute HIP kernels to the +same host program. + +These registration/unregistration helpers are implementation details of Clang's +HIP code generation; user code should not call ``__hipRegisterFatBinary`` or +``__hipUnregisterFatBinary`` directly. + +Implications for HIP Application Developers +------------------------------------------- + +From the point of view of HIP application code, Clang and the HIP runtime +provide the following guarantees: + +* Kernels and device variables defined in HIP code will be registered with the + HIP runtime before ``main`` begins execution. +* Fat binaries will be unregistered via an ``atexit``-registered module + destructor after ``main`` returns (or after ``exit`` is called). + +Beyond these points, the detailed ordering of fat binary registration and +unregistration relative to user-defined global constructors, destructors and +other ``atexit`` handlers is not specified and should not be relied upon. +Applications should avoid depending on HIP kernels or device variables being +usable from global constructors or destructors, and instead perform HIP +initialization and teardown that touches device state in ``main`` (or in +functions called from ``main``). + +Implications for HIP Runtime Developers +--------------------------------------- + +HIP runtime implementations that are linked with Clang-generated host code +must handle registration and unregistration in the presence of uncertain +global ctor/dtor ordering: + +* ``__hipRegisterFatBinary`` must accept a pointer to the compiler-generated + wrapper object and return an opaque handle that remains valid for as long as + the fat binary may be used. +* ``__hipUnregisterFatBinary`` must accept the handle previously returned by + ``__hipRegisterFatBinary`` and perform any necessary cleanup. It may be + called late in process teardown, after other parts of the runtime have + started shutting down, so it should be robust in the presence of partially + torn-down state. +* Runtimes should use appropriate synchronization and guards so that fat + binary registration does not observe uninitialized resources and + unregistration does not release resources that are still required by other + runtime components. In particular, registration and unregistration routines + should be written to be safe under repeated calls and in the presence of + concurrent or overlapping initialization/teardown logic. + Syntax Difference with CUDA =========================== From 2f8e71287542a597be246d34699c93345d096f22 Mon Sep 17 00:00:00 2001 From: Abhinav Gaba Date: Mon, 24 Nov 2025 16:48:23 -0800 Subject: [PATCH 41/50] [NFC][OpenMP] Add use_device_ptr/addr tests for when the lookup fails. (#169428) As per OpenMP 5.1, the pointers are expected to retain their original values when a lookup fails and there is no device pointer to translate to. --- ...get_data_use_device_addr_arrsec_fallback.c | 24 ++++++++++++++ ...target_data_use_device_addr_var_fallback.c | 21 ++++++++++++ .../target_data_use_device_ptr_var_fallback.c | 32 +++++++++++++++++++ 3 files changed, 77 insertions(+) create mode 100644 offload/test/mapping/use_device_addr/target_data_use_device_addr_arrsec_fallback.c create mode 100644 offload/test/mapping/use_device_addr/target_data_use_device_addr_var_fallback.c create mode 100644 offload/test/mapping/use_device_ptr/target_data_use_device_ptr_var_fallback.c diff --git a/offload/test/mapping/use_device_addr/target_data_use_device_addr_arrsec_fallback.c b/offload/test/mapping/use_device_addr/target_data_use_device_addr_arrsec_fallback.c new file mode 100644 index 0000000000000..4b67a3bc2aa7f --- /dev/null +++ b/offload/test/mapping/use_device_addr/target_data_use_device_addr_arrsec_fallback.c @@ -0,0 +1,24 @@ +// RUN: %libomptarget-compilexx-run-and-check-generic + +// Test that when a use_device_addr lookup fails, the +// list-item retains its original address by default. +// +// This is necessary because we must assume that the +// list-item is device-accessible, even if it was not +// previously mapped. + +// XFAIL: * + +#include +int h[10]; +int *ph = &h[0]; + +void f1() { + printf("%p\n", &h[2]); // CHECK: 0x[[#%x,ADDR:]] +#pragma omp target data use_device_addr(h[2]) + printf("%p\n", &h[2]); // CHECK-NEXT: 0x{{0*}}[[#ADDR]] +#pragma omp target data use_device_addr(ph[2]) + printf("%p\n", &ph[2]); // CHECK-NEXT: 0x{{0*}}[[#ADDR]] +} + +int main() { f1(); } diff --git a/offload/test/mapping/use_device_addr/target_data_use_device_addr_var_fallback.c b/offload/test/mapping/use_device_addr/target_data_use_device_addr_var_fallback.c new file mode 100644 index 0000000000000..4495a46b6d204 --- /dev/null +++ b/offload/test/mapping/use_device_addr/target_data_use_device_addr_var_fallback.c @@ -0,0 +1,21 @@ +// RUN: %libomptarget-compilexx-run-and-check-generic + +// Test that when a use_device_addr lookup fails, the +// list-item retains its original address by default. +// +// This is necessary because we must assume that the +// list-item is device-accessible, even if it was not +// previously mapped. + +// XFAIL: * + +#include +int x; + +void f1() { + printf("%p\n", &x); // CHECK: 0x[[#%x,ADDR:]] +#pragma omp target data use_device_addr(x) + printf("%p\n", &x); // CHECK-NEXT: 0x{{0*}}[[#ADDR]] +} + +int main() { f1(); } diff --git a/offload/test/mapping/use_device_ptr/target_data_use_device_ptr_var_fallback.c b/offload/test/mapping/use_device_ptr/target_data_use_device_ptr_var_fallback.c new file mode 100644 index 0000000000000..e8fa3b69e9296 --- /dev/null +++ b/offload/test/mapping/use_device_ptr/target_data_use_device_ptr_var_fallback.c @@ -0,0 +1,32 @@ +// RUN: %libomptarget-compilexx-run-and-check-generic + +// Test that when a use_device_ptr lookup fails, the +// privatized pointer retains its original value by +// default. +// +// This is necessary because we must assume that the +// pointee is device-accessible, even if it was not +// previously mapped. +// +// OpenMP 5.1, sec 2.14.2, target data construct, p 188, l26-31: +// If a list item that appears in a use_device_ptr clause ... does not point to +// a mapped object, it must contain a valid device address for the target +// device, and the list item references are instead converted to references to a +// local device pointer that refers to this device address. +// +// Note: OpenMP 6.1 will have a way to change the +// fallback behavior: preserve or nullify. + +// XFAIL: * + +#include +int x; +int *xp = &x; + +void f1() { + printf("%p\n", xp); // CHECK: 0x[[#%x,ADDR:]] +#pragma omp target data use_device_ptr(xp) + printf("%p\n", xp); // CHECK-NEXT: 0x{{0*}}[[#ADDR]] +} + +int main() { f1(); } From 78994706d87e617e8063dfb73a585c8f7c7e738c Mon Sep 17 00:00:00 2001 From: Matthias Springer Date: Tue, 25 Nov 2025 09:09:26 +0800 Subject: [PATCH 42/50] [mlir][arith] Add support for `extf`, `truncf` to `ArithToAPFloat` (#169275) Add support for `arith.extf` and `arith.truncf`. No support for custom rounding modes yet. --- .../ArithToAPFloat/ArithToAPFloat.cpp | 100 ++++++++++++++---- mlir/lib/ExecutionEngine/APFloatWrappers.cpp | 17 ++- .../ArithToApfloat/arith-to-apfloat.mlir | 22 ++++ .../Arith/CPU/test-apfloat-emulation.mlir | 15 ++- 4 files changed, 130 insertions(+), 24 deletions(-) diff --git a/mlir/lib/Conversion/ArithToAPFloat/ArithToAPFloat.cpp b/mlir/lib/Conversion/ArithToAPFloat/ArithToAPFloat.cpp index 699edb188a70a..9aee85bc7e9ea 100644 --- a/mlir/lib/Conversion/ArithToAPFloat/ArithToAPFloat.cpp +++ b/mlir/lib/Conversion/ArithToAPFloat/ArithToAPFloat.cpp @@ -41,24 +41,15 @@ static FuncOp createFnDecl(OpBuilder &b, SymbolOpInterface symTable, } /// Helper function to look up or create the symbol for a runtime library -/// function for a binary arithmetic operation. -/// -/// Parameter 1: APFloat semantics -/// Parameter 2: Left-hand side operand -/// Parameter 3: Right-hand side operand -/// -/// This function will return a failure if the function is found but has an -/// unexpected signature. -/// +/// function with the given parameter types. Always returns an int64_t. static FailureOr -lookupOrCreateBinaryFn(OpBuilder &b, SymbolOpInterface symTable, StringRef name, - SymbolTableCollection *symbolTables = nullptr) { - auto i32Type = IntegerType::get(symTable->getContext(), 32); +lookupOrCreateApFloatFn(OpBuilder &b, SymbolOpInterface symTable, + StringRef name, TypeRange paramTypes, + SymbolTableCollection *symbolTables = nullptr) { auto i64Type = IntegerType::get(symTable->getContext(), 64); std::string funcName = (llvm::Twine("_mlir_apfloat_") + name).str(); - FunctionType funcT = - FunctionType::get(b.getContext(), {i32Type, i64Type, i64Type}, {i64Type}); + auto funcT = FunctionType::get(b.getContext(), paramTypes, {i64Type}); FailureOr func = lookupFnDecl(symTable, funcName, funcT, symbolTables); // Failed due to type mismatch. @@ -72,6 +63,31 @@ lookupOrCreateBinaryFn(OpBuilder &b, SymbolOpInterface symTable, StringRef name, /*setPrivate=*/true, symbolTables); } +/// Helper function to look up or create the symbol for a runtime library +/// function for a binary arithmetic operation. +/// +/// Parameter 1: APFloat semantics +/// Parameter 2: Left-hand side operand +/// Parameter 3: Right-hand side operand +/// +/// This function will return a failure if the function is found but has an +/// unexpected signature. +/// +static FailureOr +lookupOrCreateBinaryFn(OpBuilder &b, SymbolOpInterface symTable, StringRef name, + SymbolTableCollection *symbolTables = nullptr) { + auto i32Type = IntegerType::get(symTable->getContext(), 32); + auto i64Type = IntegerType::get(symTable->getContext(), 64); + return lookupOrCreateApFloatFn(b, symTable, name, {i32Type, i64Type, i64Type}, + symbolTables); +} + +static Value getSemanticsValue(OpBuilder &b, Location loc, FloatType floatTy) { + int32_t sem = llvm::APFloatBase::SemanticsToEnum(floatTy.getFloatSemantics()); + return arith::ConstantOp::create(b, loc, b.getI32Type(), + b.getIntegerAttr(b.getI32Type(), sem)); +} + /// Rewrite a binary arithmetic operation to an APFloat function call. template struct BinaryArithOpToAPFloatConversion final : OpRewritePattern { @@ -104,11 +120,7 @@ struct BinaryArithOpToAPFloatConversion final : OpRewritePattern { arith::BitcastOp::create(rewriter, loc, intWType, op.getRhs())); // Call APFloat function. - int32_t sem = - llvm::APFloatBase::SemanticsToEnum(floatTy.getFloatSemantics()); - Value semValue = arith::ConstantOp::create( - rewriter, loc, rewriter.getI32Type(), - rewriter.getIntegerAttr(rewriter.getI32Type(), sem)); + Value semValue = getSemanticsValue(rewriter, loc, floatTy); SmallVector params = {semValue, lhsBits, rhsBits}; auto resultOp = func::CallOp::create(rewriter, loc, TypeRange(rewriter.getI64Type()), @@ -126,6 +138,53 @@ struct BinaryArithOpToAPFloatConversion final : OpRewritePattern { const char *APFloatName; }; +template +struct FpToFpConversion final : OpRewritePattern { + FpToFpConversion(MLIRContext *context, SymbolOpInterface symTable, + PatternBenefit benefit = 1) + : OpRewritePattern(context, benefit), symTable(symTable) {} + + LogicalResult matchAndRewrite(OpTy op, + PatternRewriter &rewriter) const override { + // Get APFloat function from runtime library. + auto i32Type = IntegerType::get(symTable->getContext(), 32); + auto i64Type = IntegerType::get(symTable->getContext(), 64); + FailureOr fn = lookupOrCreateApFloatFn( + rewriter, symTable, "convert", {i32Type, i32Type, i64Type}); + if (failed(fn)) + return fn; + + rewriter.setInsertionPoint(op); + // Cast operands to 64-bit integers. + Location loc = op.getLoc(); + auto inFloatTy = cast(op.getOperand().getType()); + auto inIntWType = rewriter.getIntegerType(inFloatTy.getWidth()); + auto int64Type = rewriter.getI64Type(); + Value operandBits = arith::ExtUIOp::create( + rewriter, loc, int64Type, + arith::BitcastOp::create(rewriter, loc, inIntWType, op.getOperand())); + + // Call APFloat function. + Value inSemValue = getSemanticsValue(rewriter, loc, inFloatTy); + auto outFloatTy = cast(op.getType()); + Value outSemValue = getSemanticsValue(rewriter, loc, outFloatTy); + std::array params = {inSemValue, outSemValue, operandBits}; + auto resultOp = + func::CallOp::create(rewriter, loc, TypeRange(rewriter.getI64Type()), + SymbolRefAttr::get(*fn), params); + + // Truncate result to the original width. + auto outIntWType = rewriter.getIntegerType(outFloatTy.getWidth()); + Value truncatedBits = arith::TruncIOp::create(rewriter, loc, outIntWType, + resultOp->getResult(0)); + rewriter.replaceOp( + op, arith::BitcastOp::create(rewriter, loc, outFloatTy, truncatedBits)); + return success(); + } + + SymbolOpInterface symTable; +}; + namespace { struct ArithToAPFloatConversionPass final : impl::ArithToAPFloatConversionPassBase { @@ -147,6 +206,9 @@ void ArithToAPFloatConversionPass::runOnOperation() { context, "divide", getOperation()); patterns.add>( context, "remainder", getOperation()); + patterns + .add, FpToFpConversion>( + context, getOperation()); LogicalResult result = success(); ScopedDiagnosticHandler scopedHandler(context, [&result](Diagnostic &diag) { if (diag.getSeverity() == DiagnosticSeverity::Error) { diff --git a/mlir/lib/ExecutionEngine/APFloatWrappers.cpp b/mlir/lib/ExecutionEngine/APFloatWrappers.cpp index 0a05f7369e556..511b05ea380f0 100644 --- a/mlir/lib/ExecutionEngine/APFloatWrappers.cpp +++ b/mlir/lib/ExecutionEngine/APFloatWrappers.cpp @@ -51,7 +51,7 @@ /// Binary operations with rounding mode. #define APFLOAT_BINARY_OP_ROUNDING_MODE(OP, ROUNDING_MODE) \ - MLIR_APFLOAT_WRAPPERS_EXPORT int64_t _mlir_apfloat_##OP( \ + MLIR_APFLOAT_WRAPPERS_EXPORT uint64_t _mlir_apfloat_##OP( \ int32_t semantics, uint64_t a, uint64_t b) { \ const llvm::fltSemantics &sem = llvm::APFloatBase::EnumToSemantics( \ static_cast(semantics)); \ @@ -86,4 +86,19 @@ MLIR_APFLOAT_WRAPPERS_EXPORT void printApFloat(int32_t semantics, uint64_t a) { double d = x.convertToDouble(); fprintf(stdout, "%lg", d); } + +MLIR_APFLOAT_WRAPPERS_EXPORT uint64_t +_mlir_apfloat_convert(int32_t inSemantics, int32_t outSemantics, uint64_t a) { + const llvm::fltSemantics &inSem = llvm::APFloatBase::EnumToSemantics( + static_cast(inSemantics)); + const llvm::fltSemantics &outSem = llvm::APFloatBase::EnumToSemantics( + static_cast(outSemantics)); + unsigned bitWidthIn = llvm::APFloatBase::semanticsSizeInBits(inSem); + llvm::APFloat val(inSem, llvm::APInt(bitWidthIn, a)); + // TODO: Custom rounding modes are not supported yet. + bool losesInfo; + val.convert(outSem, llvm::RoundingMode::NearestTiesToEven, &losesInfo); + llvm::APInt result = val.bitcastToAPInt(); + return result.getZExtValue(); +} } diff --git a/mlir/test/Conversion/ArithToApfloat/arith-to-apfloat.mlir b/mlir/test/Conversion/ArithToApfloat/arith-to-apfloat.mlir index 797f42c37a26f..038acbfc965a2 100644 --- a/mlir/test/Conversion/ArithToApfloat/arith-to-apfloat.mlir +++ b/mlir/test/Conversion/ArithToApfloat/arith-to-apfloat.mlir @@ -126,3 +126,25 @@ func.func @remf(%arg0: f4E2M1FN, %arg1: f4E2M1FN) { %0 = arith.remf %arg0, %arg1 : f4E2M1FN return } + +// ----- + +// CHECK: func.func private @_mlir_apfloat_convert(i32, i32, i64) -> i64 +// CHECK: %[[sem_in:.*]] = arith.constant 18 : i32 +// CHECK: %[[sem_out:.*]] = arith.constant 2 : i32 +// CHECK: call @_mlir_apfloat_convert(%[[sem_in]], %[[sem_out]], %{{.*}}) : (i32, i32, i64) -> i64 +func.func @extf(%arg0: f4E2M1FN) { + %0 = arith.extf %arg0 : f4E2M1FN to f32 + return +} + +// ----- + +// CHECK: func.func private @_mlir_apfloat_convert(i32, i32, i64) -> i64 +// CHECK: %[[sem_in:.*]] = arith.constant 1 : i32 +// CHECK: %[[sem_out:.*]] = arith.constant 18 : i32 +// CHECK: call @_mlir_apfloat_convert(%[[sem_in]], %[[sem_out]], %{{.*}}) : (i32, i32, i64) -> i64 +func.func @truncf(%arg0: bf16) { + %0 = arith.truncf %arg0 : bf16 to f4E2M1FN + return +} diff --git a/mlir/test/Integration/Dialect/Arith/CPU/test-apfloat-emulation.mlir b/mlir/test/Integration/Dialect/Arith/CPU/test-apfloat-emulation.mlir index dbaa20346a03a..51976434d2be2 100644 --- a/mlir/test/Integration/Dialect/Arith/CPU/test-apfloat-emulation.mlir +++ b/mlir/test/Integration/Dialect/Arith/CPU/test-apfloat-emulation.mlir @@ -27,14 +27,21 @@ func.func @entry() { %a1 = arith.constant 1.4 : f8E4M3FN %a2 = arith.constant 1.4 : f32 %b1, %b2 = func.call @foo() : () -> (f8E4M3FN, f32) - %c1 = arith.addf %a1, %b1 : f8E4M3FN // not supported by LLVM - %c2 = arith.addf %a2, %b2 : f32 // supported by LLVM - // CHECK: 3.5 + // CHECK: 2.2 + vector.print %b2 : f32 + + // CHECK-NEXT: 3.5 + %c1 = arith.addf %a1, %b1 : f8E4M3FN // not supported by LLVM vector.print %c1 : f8E4M3FN - // CHECK: 3.6 + // CHECK-NEXT: 3.6 + %c2 = arith.addf %a2, %b2 : f32 // supported by LLVM vector.print %c2 : f32 + // CHECK-NEXT: 2.25 + %cvt = arith.truncf %b2 : f32 to f8E4M3FN + vector.print %cvt : f8E4M3FN + return } From e6f2fbb0fa6b519643916e11552c88d680958ede Mon Sep 17 00:00:00 2001 From: Ryan Mast <3969255+nightlark@users.noreply.github.com> Date: Mon, 24 Nov 2025 17:21:24 -0800 Subject: [PATCH 43/50] [libclang/python] Enable packaging clang python bindings (#125806) This adds a pyproject.toml file for packaging the clang Python bindings as a sdist tarball and pure Python wheel packages for the clang python bindings. It is required to move updates of the clang and libclang PyPI packages to the LLVM monorepo. Versioning information is derived from LLVM git tags (using hatch-vcs, which is based on setuptools_scm), so no manual updates are needed to bump version numbers. The minimum python version required is set to 3.10 due to cindex.py using PEP 604 union type syntax (str | bytes | None). The .git_archival.txt file is populated with version information needed to get accurate version information if the bindings are installed from an LLVM/clang source code archive. The .gitignore file is populated with files that may get created as part of building/testing the sdist and wheel that should not be committed to source control. This is first step for addressing #125220, and moving publishing of the clang and libclang PyPI packages into the LLVM monorepo. Signed-off-by: Ryan Mast --- .gitattributes | 2 ++ clang/bindings/python/.git_archival.txt | 3 ++ clang/bindings/python/.gitignore | 21 ++++++++++++ clang/bindings/python/pyproject.toml | 43 +++++++++++++++++++++++++ 4 files changed, 69 insertions(+) create mode 100644 clang/bindings/python/.git_archival.txt create mode 100644 clang/bindings/python/.gitignore create mode 100644 clang/bindings/python/pyproject.toml diff --git a/.gitattributes b/.gitattributes index 6b281f33f737d..142d6689f1088 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,3 +1,5 @@ +clang/bindings/python/.git_archival.txt export-subst + libcxx/src/**/*.cpp merge=libcxx-reformat libcxx/include/**/*.h merge=libcxx-reformat diff --git a/clang/bindings/python/.git_archival.txt b/clang/bindings/python/.git_archival.txt new file mode 100644 index 0000000000000..7876d4af4c620 --- /dev/null +++ b/clang/bindings/python/.git_archival.txt @@ -0,0 +1,3 @@ +node: $Format:%H$ +node-date: $Format:%cI$ +describe-name: $Format:%(describe:tags=true,match=llvmorg-*[0-9]*)$ diff --git a/clang/bindings/python/.gitignore b/clang/bindings/python/.gitignore new file mode 100644 index 0000000000000..1641a745fb682 --- /dev/null +++ b/clang/bindings/python/.gitignore @@ -0,0 +1,21 @@ +# setuptools_scm auto-generated version file +_version.py + +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# Distribution / packaging +build/ +dist/ +*.egg-info/ + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ diff --git a/clang/bindings/python/pyproject.toml b/clang/bindings/python/pyproject.toml new file mode 100644 index 0000000000000..a7ea9f2860ac2 --- /dev/null +++ b/clang/bindings/python/pyproject.toml @@ -0,0 +1,43 @@ +[build-system] +requires = ["hatchling>=1.27", "hatch-vcs>=0.4"] +build-backend = "hatchling.build" + +[project] +name = "clang" +description = "clang python bindings" +readme = {file = "README.txt", content-type = "text/plain"} + +license = "Apache-2.0 WITH LLVM-exception" +authors = [ + { name = "LLVM" } +] +keywords = ["llvm", "clang", "libclang"] +classifiers = [ + "Intended Audience :: Developers", + "Development Status :: 5 - Production/Stable", + "Topic :: Software Development :: Compilers", + "Operating System :: OS Independent", + "Programming Language :: Python :: 3", +] +requires-python = ">=3.8" +dynamic = ["version"] + +[project.urls] +Homepage = "https://clang.llvm.org/" +Download = "https://llvm.org/releases/download.html" +Discussions = "https://discourse.llvm.org/" +"Issue Tracker" = "https://github.com/llvm/llvm-project/issues" +"Source Code" = "https://github.com/llvm/llvm-project/tree/main/clang/bindings/python" + +[tool.hatch.version] +source = "vcs" +version-scheme = "no-guess-dev" +# regex version capture group gets x.y.z with optional -rcN, -aN, -bN suffixes; -init is just consumed +tag-pattern = "^llvmorg-(?P\\d+(?:\\.\\d+)*(?:-rc\\d+)?)" + +[tool.hatch.build.hooks.vcs] +version-file = "clang/_version.py" + +[tool.hatch.version.raw-options] +search_parent_directories = true +version_scheme = "no-guess-dev" From 1782d27e67b9cde01a3722a1380ae3558da64452 Mon Sep 17 00:00:00 2001 From: ZhaoQi Date: Tue, 25 Nov 2025 09:24:39 +0800 Subject: [PATCH 44/50] [LoongArch] Fix for `VLDREPL` node validation (#168993) --- llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp | 12 +++++++----- .../Target/LoongArch/LoongArchSelectionDAGInfo.cpp | 10 ---------- .../lib/Target/LoongArch/LoongArchSelectionDAGInfo.h | 3 --- 3 files changed, 7 insertions(+), 18 deletions(-) diff --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp index ac95ef5f30888..b8c1c261fa6db 100644 --- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp +++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp @@ -2886,11 +2886,13 @@ static SDValue lowerBUILD_VECTORAsBroadCastLoad(BuildVectorSDNode *BVOp, if ((ExtType == ISD::EXTLOAD || ExtType == ISD::NON_EXTLOAD) && VT.getScalarSizeInBits() == LN->getMemoryVT().getScalarSizeInBits()) { - SDVTList Tys = - LN->isIndexed() - ? DAG.getVTList(VT, LN->getBasePtr().getValueType(), MVT::Other) - : DAG.getVTList(VT, MVT::Other); - SDValue Ops[] = {LN->getChain(), LN->getBasePtr(), LN->getOffset()}; + // Indexed loads and stores are not supported on LoongArch. + assert(LN->isUnindexed() && "Unexpected indexed load."); + + SDVTList Tys = DAG.getVTList(VT, MVT::Other); + // The offset operand of unindexed load is always undefined, so there is + // no need to pass it to VLDREPL. + SDValue Ops[] = {LN->getChain(), LN->getBasePtr()}; SDValue BCast = DAG.getNode(LoongArchISD::VLDREPL, DL, Tys, Ops); DAG.ReplaceAllUsesOfValueWith(SDValue(LN, 1), BCast.getValue(1)); return BCast; diff --git a/llvm/lib/Target/LoongArch/LoongArchSelectionDAGInfo.cpp b/llvm/lib/Target/LoongArch/LoongArchSelectionDAGInfo.cpp index 11d05042c94f8..c07adfc48a0f5 100644 --- a/llvm/lib/Target/LoongArch/LoongArchSelectionDAGInfo.cpp +++ b/llvm/lib/Target/LoongArch/LoongArchSelectionDAGInfo.cpp @@ -17,13 +17,3 @@ LoongArchSelectionDAGInfo::LoongArchSelectionDAGInfo() : SelectionDAGGenTargetInfo(LoongArchGenSDNodeInfo) {} LoongArchSelectionDAGInfo::~LoongArchSelectionDAGInfo() = default; - -void LoongArchSelectionDAGInfo::verifyTargetNode(const SelectionDAG &DAG, - const SDNode *N) const { - switch (N->getOpcode()) { - case LoongArchISD::VLDREPL: - // invalid number of operands; expected 2, got 3 - return; - } - SelectionDAGGenTargetInfo::verifyTargetNode(DAG, N); -} diff --git a/llvm/lib/Target/LoongArch/LoongArchSelectionDAGInfo.h b/llvm/lib/Target/LoongArch/LoongArchSelectionDAGInfo.h index ba5657080b3e4..7210a15297a3e 100644 --- a/llvm/lib/Target/LoongArch/LoongArchSelectionDAGInfo.h +++ b/llvm/lib/Target/LoongArch/LoongArchSelectionDAGInfo.h @@ -21,9 +21,6 @@ class LoongArchSelectionDAGInfo : public SelectionDAGGenTargetInfo { LoongArchSelectionDAGInfo(); ~LoongArchSelectionDAGInfo() override; - - void verifyTargetNode(const SelectionDAG &DAG, - const SDNode *N) const override; }; } // namespace llvm From 196f6de75a0fe6c66e58a9bbd90b30f7c4a69bde Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Tue, 25 Nov 2025 01:27:20 +0000 Subject: [PATCH 45/50] Update actions/checkout action to v6 (#169258) This PR contains the following updates: | Package | Type | Update | Change | |---|---|---|---| | [actions/checkout](https://redirect.github.com/actions/checkout) | action | major | `v5.0.0` -> `v6.0.0` | --- .github/workflows/bazel-checks.yml | 4 ++-- .github/workflows/build-ci-container-tooling.yml | 4 ++-- .github/workflows/build-ci-container-windows.yml | 2 +- .github/workflows/build-ci-container.yml | 4 ++-- .github/workflows/build-metrics-container.yml | 4 ++-- .github/workflows/check-ci.yml | 2 +- .github/workflows/ci-post-commit-analyzer.yml | 2 +- .github/workflows/commit-access-greeter.yml | 2 +- .github/workflows/commit-access-review.yml | 2 +- .github/workflows/docs.yml | 2 +- .github/workflows/email-check.yaml | 2 +- .github/workflows/gha-codeql.yml | 2 +- .github/workflows/hlsl-test-all.yaml | 8 ++++---- .github/workflows/issue-release-workflow.yml | 2 +- .github/workflows/issue-subscriber.yml | 2 +- .github/workflows/issue-write.yml | 2 +- .github/workflows/libc-fullbuild-tests.yml | 2 +- .github/workflows/libc-overlay-tests.yml | 2 +- .github/workflows/libclang-abi-tests.yml | 4 ++-- .github/workflows/libclang-python-tests.yml | 2 +- .github/workflows/libcxx-build-and-test.yaml | 10 +++++----- .github/workflows/libcxx-build-containers.yml | 2 +- .github/workflows/libcxx-check-generated-files.yml | 2 +- .github/workflows/libcxx-run-benchmarks.yml | 2 +- .github/workflows/llvm-abi-tests.yml | 4 ++-- .github/workflows/merged-prs.yml | 2 +- .github/workflows/mlir-spirv-tests.yml | 2 +- .github/workflows/new-prs.yml | 2 +- .github/workflows/pr-code-format.yml | 2 +- .github/workflows/pr-code-lint.yml | 2 +- .github/workflows/pr-request-release-note.yml | 2 +- .github/workflows/pr-subscriber.yml | 2 +- .github/workflows/premerge.yaml | 6 +++--- .github/workflows/release-asset-audit.yml | 2 +- .github/workflows/release-binaries.yml | 6 +++--- .github/workflows/release-documentation.yml | 4 ++-- .github/workflows/release-doxygen.yml | 2 +- .github/workflows/release-lit.yml | 2 +- .github/workflows/release-sources.yml | 2 +- .github/workflows/release-tasks.yml | 4 ++-- .github/workflows/scorecard.yml | 2 +- .github/workflows/spirv-tests.yml | 2 +- .../workflows/test-unprivileged-download-artifact.yml | 2 +- .github/workflows/version-check.yml | 2 +- 44 files changed, 63 insertions(+), 63 deletions(-) diff --git a/.github/workflows/bazel-checks.yml b/.github/workflows/bazel-checks.yml index dc9dcb97ce0a8..aa318569532ec 100644 --- a/.github/workflows/bazel-checks.yml +++ b/.github/workflows/bazel-checks.yml @@ -22,7 +22,7 @@ jobs: if: github.repository == 'llvm/llvm-project' steps: - name: Fetch LLVM sources - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - name: Setup Buildifier run: | sudo curl -L https://github.com/bazelbuild/buildtools/releases/download/v8.2.1/buildifier-linux-amd64 -o /usr/bin/buildifier --fail @@ -41,7 +41,7 @@ jobs: if: github.repository == 'llvm/llvm-project' steps: - name: Fetch LLVM sources - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 # TODO(boomanaiden154): We should use a purpose built container for this. Move # over when we have fixed the issues with using custom containers with Github # ARC in GKE. diff --git a/.github/workflows/build-ci-container-tooling.yml b/.github/workflows/build-ci-container-tooling.yml index 531da2ccbd446..c75d84829bba6 100644 --- a/.github/workflows/build-ci-container-tooling.yml +++ b/.github/workflows/build-ci-container-tooling.yml @@ -41,7 +41,7 @@ jobs: target: abi-tests steps: - name: Checkout LLVM - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: sparse-checkout: | .github/workflows/containers/github-action-ci-tooling/ @@ -67,7 +67,7 @@ jobs: runs-on: ubuntu-24.04 steps: - name: Checkout LLVM - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: sparse-checkout: | .github/actions/push-container diff --git a/.github/workflows/build-ci-container-windows.yml b/.github/workflows/build-ci-container-windows.yml index 3996948bb44e0..3fd1c73d0ee40 100644 --- a/.github/workflows/build-ci-container-windows.yml +++ b/.github/workflows/build-ci-container-windows.yml @@ -25,7 +25,7 @@ jobs: container-filename: ${{ steps.vars.outputs.container-filename }} steps: - name: Checkout LLVM - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: sparse-checkout: .github/workflows/containers/github-action-ci-windows - name: Write Variables diff --git a/.github/workflows/build-ci-container.yml b/.github/workflows/build-ci-container.yml index ddb803fb969ff..e17e852166cee 100644 --- a/.github/workflows/build-ci-container.yml +++ b/.github/workflows/build-ci-container.yml @@ -36,7 +36,7 @@ jobs: - cd $HOME && printf '#include \nint main(int argc, char **argv) { std::cout << "Hello\\n"; }' | clang++ -x c++ - && ./a.out | grep Hello steps: - name: Checkout LLVM - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: sparse-checkout: | .github/workflows/containers/github-action-ci/ @@ -62,7 +62,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: - name: Checkout LLVM - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: sparse-checkout: | .github/actions/push-container diff --git a/.github/workflows/build-metrics-container.yml b/.github/workflows/build-metrics-container.yml index e1407a29cc295..0436e6ec82fda 100644 --- a/.github/workflows/build-metrics-container.yml +++ b/.github/workflows/build-metrics-container.yml @@ -23,7 +23,7 @@ jobs: runs-on: ubuntu-24.04 steps: - name: Checkout LLVM - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: sparse-checkout: | .ci/metrics/ @@ -46,7 +46,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: - name: Checkout LLVM - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: sparse-checkout: | .github/actions/push-container diff --git a/.github/workflows/check-ci.yml b/.github/workflows/check-ci.yml index 7fecb010a64ff..914ead803181e 100644 --- a/.github/workflows/check-ci.yml +++ b/.github/workflows/check-ci.yml @@ -22,7 +22,7 @@ jobs: if: github.repository == 'llvm/llvm-project' steps: - name: Fetch LLVM sources - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: sparse-checkout: .ci - name: Setup Python diff --git a/.github/workflows/ci-post-commit-analyzer.yml b/.github/workflows/ci-post-commit-analyzer.yml index 59df0b68a8ad7..abd64809f9dc9 100644 --- a/.github/workflows/ci-post-commit-analyzer.yml +++ b/.github/workflows/ci-post-commit-analyzer.yml @@ -41,7 +41,7 @@ jobs: LLVM_VERSION: 18 steps: - name: Checkout Source - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - name: Setup ccache uses: hendrikmuhs/ccache-action@bfa03e1de4d7f7c3e80ad9109feedd05c4f5a716 # v1.2.19 diff --git a/.github/workflows/commit-access-greeter.yml b/.github/workflows/commit-access-greeter.yml index f31cd015642e2..d11bdec6b2ea8 100644 --- a/.github/workflows/commit-access-greeter.yml +++ b/.github/workflows/commit-access-greeter.yml @@ -18,7 +18,7 @@ jobs: github.event.label.name == 'infra:commit-access-request' runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: sparse-checkout: llvm/utils/git/ diff --git a/.github/workflows/commit-access-review.yml b/.github/workflows/commit-access-review.yml index 7cdcfca532990..f6ec0bc9d4a9a 100644 --- a/.github/workflows/commit-access-review.yml +++ b/.github/workflows/commit-access-review.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-24.04 steps: - name: Fetch LLVM sources - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - name: Install dependencies run: | diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 3eb146d21dc40..ef1b727dc00a8 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -55,7 +55,7 @@ jobs: if: github.repository == 'llvm/llvm-project' steps: - name: Fetch LLVM sources - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: fetch-depth: 2 - name: Get subprojects that have doc changes diff --git a/.github/workflows/email-check.yaml b/.github/workflows/email-check.yaml index ba625b2b3b062..28cd2905d816d 100644 --- a/.github/workflows/email-check.yaml +++ b/.github/workflows/email-check.yaml @@ -14,7 +14,7 @@ jobs: if: github.repository == 'llvm/llvm-project' steps: - name: Fetch LLVM sources - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: ref: ${{ github.event.pull_request.head.sha }} diff --git a/.github/workflows/gha-codeql.yml b/.github/workflows/gha-codeql.yml index 689bdf408522b..9c6c23e34758c 100644 --- a/.github/workflows/gha-codeql.yml +++ b/.github/workflows/gha-codeql.yml @@ -24,7 +24,7 @@ jobs: security-events: write steps: - name: Checkout LLVM - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: sparse-checkout: | .github/ diff --git a/.github/workflows/hlsl-test-all.yaml b/.github/workflows/hlsl-test-all.yaml index 6e5bfd5b870a3..cc4b52ae6a728 100644 --- a/.github/workflows/hlsl-test-all.yaml +++ b/.github/workflows/hlsl-test-all.yaml @@ -29,25 +29,25 @@ jobs: runs-on: ${{ inputs.SKU }} steps: - name: Checkout DXC - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: repository: Microsoft/DirectXShaderCompiler ref: main path: DXC submodules: true - name: Checkout LLVM - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: ref: ${{ inputs.LLVM-branch }} path: llvm-project - name: Checkout OffloadTest - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: repository: llvm/offload-test-suite ref: main path: OffloadTest - name: Checkout Golden Images - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: repository: llvm/offload-golden-images ref: main diff --git a/.github/workflows/issue-release-workflow.yml b/.github/workflows/issue-release-workflow.yml index 7fd0280b2eedf..9aa1276e10e92 100644 --- a/.github/workflows/issue-release-workflow.yml +++ b/.github/workflows/issue-release-workflow.yml @@ -42,7 +42,7 @@ jobs: contains(github.event.action == 'opened' && github.event.issue.body || github.event.comment.body, '/cherry-pick') steps: - name: Fetch LLVM sources - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: repository: llvm/llvm-project # GitHub stores the token used for checkout and uses it for pushes diff --git a/.github/workflows/issue-subscriber.yml b/.github/workflows/issue-subscriber.yml index afcd17c757b39..0006b982aeae6 100644 --- a/.github/workflows/issue-subscriber.yml +++ b/.github/workflows/issue-subscriber.yml @@ -14,7 +14,7 @@ jobs: if: github.repository == 'llvm/llvm-project' steps: - name: Checkout Automation Script - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: sparse-checkout: llvm/utils/git/ ref: main diff --git a/.github/workflows/issue-write.yml b/.github/workflows/issue-write.yml index 4f8fd7a48aff6..ece6081ce9ba6 100644 --- a/.github/workflows/issue-write.yml +++ b/.github/workflows/issue-write.yml @@ -27,7 +27,7 @@ jobs: ) steps: - name: Fetch Sources - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: sparse-checkout: | .github/workflows/unprivileged-download-artifact/action.yml diff --git a/.github/workflows/libc-fullbuild-tests.yml b/.github/workflows/libc-fullbuild-tests.yml index 01fd895cce7e8..13c0c2b82ab42 100644 --- a/.github/workflows/libc-fullbuild-tests.yml +++ b/.github/workflows/libc-fullbuild-tests.yml @@ -88,7 +88,7 @@ jobs: # - c_compiler: gcc # cpp_compiler: g++ steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 # Libc's build is relatively small comparing with other components of LLVM. # A fresh fullbuild takes about 190MiB of uncompressed disk space, which can diff --git a/.github/workflows/libc-overlay-tests.yml b/.github/workflows/libc-overlay-tests.yml index df9a20dce8eae..29bcd0f600490 100644 --- a/.github/workflows/libc-overlay-tests.yml +++ b/.github/workflows/libc-overlay-tests.yml @@ -41,7 +41,7 @@ jobs: cpp_compiler: clang++ steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 # Libc's build is relatively small comparing with other components of LLVM. # A fresh linux overlay takes about 180MiB of uncompressed disk space, which can diff --git a/.github/workflows/libclang-abi-tests.yml b/.github/workflows/libclang-abi-tests.yml index 0d3f9fe3f69ea..b8be6a42e0fa8 100644 --- a/.github/workflows/libclang-abi-tests.yml +++ b/.github/workflows/libclang-abi-tests.yml @@ -38,7 +38,7 @@ jobs: LLVM_VERSION_PATCH: ${{ steps.version.outputs.patch }} steps: - name: Checkout source - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: fetch-depth: 250 @@ -102,7 +102,7 @@ jobs: repo: ${{ github.repository }} steps: - name: Download source code - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: ref: ${{ matrix.ref }} repository: ${{ matrix.repo }} diff --git a/.github/workflows/libclang-python-tests.yml b/.github/workflows/libclang-python-tests.yml index 0d66f5d595e0e..69d281b65b5fb 100644 --- a/.github/workflows/libclang-python-tests.yml +++ b/.github/workflows/libclang-python-tests.yml @@ -32,7 +32,7 @@ jobs: matrix: python-version: ["3.8", "3.13"] steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - name: Setup Python uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0 with: diff --git a/.github/workflows/libcxx-build-and-test.yaml b/.github/workflows/libcxx-build-and-test.yaml index 7dad30f994fd1..8e6dc48f4c495 100644 --- a/.github/workflows/libcxx-build-and-test.yaml +++ b/.github/workflows/libcxx-build-and-test.yaml @@ -54,7 +54,7 @@ jobs: cc: 'gcc-15' cxx: 'g++-15' steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - name: ${{ matrix.config }}.${{ matrix.cxx }} run: libcxx/utils/ci/run-buildbot ${{ matrix.config }} env: @@ -99,7 +99,7 @@ jobs: cc: 'clang-20' cxx: 'clang++-20' steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - name: ${{ matrix.config }} run: libcxx/utils/ci/run-buildbot ${{ matrix.config }} env: @@ -163,7 +163,7 @@ jobs: machine: llvm-premerge-libcxx-runners runs-on: ${{ matrix.machine }} steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - name: ${{ matrix.config }} run: libcxx/utils/ci/run-buildbot ${{ matrix.config }} env: @@ -211,7 +211,7 @@ jobs: os: macos-15 runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - uses: maxim-lobanov/setup-xcode@60606e260d2fc5762a71e64e74b2174e8ea3c8bd # v1.6.0 with: # https://github.com/actions/runner-images/blob/main/images/macos/macos-15-Readme.md @@ -253,7 +253,7 @@ jobs: - { config: mingw-static, mingw: true, runner: windows-11-arm } runs-on: ${{ matrix.runner != '' && matrix.runner || 'windows-2022' }} steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - name: Install dependencies run: | pip install psutil diff --git a/.github/workflows/libcxx-build-containers.yml b/.github/workflows/libcxx-build-containers.yml index eee7bb8913944..a49ad812606e8 100644 --- a/.github/workflows/libcxx-build-containers.yml +++ b/.github/workflows/libcxx-build-containers.yml @@ -30,7 +30,7 @@ jobs: packages: write steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 # The default Docker storage location for GitHub Actions doesn't have # enough disk space, so change it to /mnt, which has more disk space. diff --git a/.github/workflows/libcxx-check-generated-files.yml b/.github/workflows/libcxx-check-generated-files.yml index ba97ccc64ba70..a25dc8b70001d 100644 --- a/.github/workflows/libcxx-check-generated-files.yml +++ b/.github/workflows/libcxx-check-generated-files.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-24.04 steps: - name: Fetch LLVM sources - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - name: Install dependencies uses: aminya/setup-cpp@9bc9b8cd8a8d678f920e4e1e73f29da8010ced51 # v1.7.2 diff --git a/.github/workflows/libcxx-run-benchmarks.yml b/.github/workflows/libcxx-run-benchmarks.yml index e2ca940d2f0b3..64a902482f9a3 100644 --- a/.github/workflows/libcxx-run-benchmarks.yml +++ b/.github/workflows/libcxx-run-benchmarks.yml @@ -56,7 +56,7 @@ jobs: BENCHMARKS=$(echo "$COMMENT_BODY" | sed -nE 's/\/libcxx-bot benchmark (.+)/\1/p') echo "benchmarks=${BENCHMARKS}" >> ${GITHUB_OUTPUT} - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: ref: ${{ steps.vars.outputs.pr_head }} fetch-depth: 0 diff --git a/.github/workflows/llvm-abi-tests.yml b/.github/workflows/llvm-abi-tests.yml index 7bd4a471bfd3a..4b0268b0ad9f2 100644 --- a/.github/workflows/llvm-abi-tests.yml +++ b/.github/workflows/llvm-abi-tests.yml @@ -38,7 +38,7 @@ jobs: LLVM_VERSION_PATCH: ${{ steps.version.outputs.patch }} steps: - name: Checkout source - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: fetch-depth: 250 @@ -90,7 +90,7 @@ jobs: repo: ${{ github.repository }} steps: - name: Download source code - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: ref: ${{ matrix.ref }} repository: ${{ matrix.repo }} diff --git a/.github/workflows/merged-prs.yml b/.github/workflows/merged-prs.yml index 107bbc51b5314..22786dc10b1ea 100644 --- a/.github/workflows/merged-prs.yml +++ b/.github/workflows/merged-prs.yml @@ -21,7 +21,7 @@ jobs: (github.event.pull_request.merged == true) steps: - name: Checkout Automation Script - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: sparse-checkout: llvm/utils/git/ ref: main diff --git a/.github/workflows/mlir-spirv-tests.yml b/.github/workflows/mlir-spirv-tests.yml index 5bb16c739cdde..e9b0cddb391be 100644 --- a/.github/workflows/mlir-spirv-tests.yml +++ b/.github/workflows/mlir-spirv-tests.yml @@ -28,7 +28,7 @@ jobs: container: image: ghcr.io/llvm/ci-ubuntu-24.04:latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - name: Setup ccache uses: hendrikmuhs/ccache-action@bfa03e1de4d7f7c3e80ad9109feedd05c4f5a716 # v1.2.19 with: diff --git a/.github/workflows/new-prs.yml b/.github/workflows/new-prs.yml index f5826728d2c7b..01032230c3883 100644 --- a/.github/workflows/new-prs.yml +++ b/.github/workflows/new-prs.yml @@ -34,7 +34,7 @@ jobs: (github.event.pull_request.author_association != 'OWNER') steps: - name: Checkout Automation Script - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: sparse-checkout: llvm/utils/git/ ref: main diff --git a/.github/workflows/pr-code-format.yml b/.github/workflows/pr-code-format.yml index dc253e4fbae98..441f94960bc0a 100644 --- a/.github/workflows/pr-code-format.yml +++ b/.github/workflows/pr-code-format.yml @@ -21,7 +21,7 @@ jobs: if: github.repository == 'llvm/llvm-project' steps: - name: Fetch LLVM sources - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: fetch-depth: 2 diff --git a/.github/workflows/pr-code-lint.yml b/.github/workflows/pr-code-lint.yml index 5444a29c22205..ea4f8217cd003 100644 --- a/.github/workflows/pr-code-lint.yml +++ b/.github/workflows/pr-code-lint.yml @@ -27,7 +27,7 @@ jobs: cancel-in-progress: true steps: - name: Fetch LLVM sources - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: fetch-depth: 2 diff --git a/.github/workflows/pr-request-release-note.yml b/.github/workflows/pr-request-release-note.yml index c2dc2de65f133..ac80347d00ab4 100644 --- a/.github/workflows/pr-request-release-note.yml +++ b/.github/workflows/pr-request-release-note.yml @@ -19,7 +19,7 @@ jobs: # We need to pull the script from the main branch, so that we ensure # we get the latest version of this script. - name: Checkout Scripts - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: sparse-checkout: | llvm/utils/git/requirements.txt diff --git a/.github/workflows/pr-subscriber.yml b/.github/workflows/pr-subscriber.yml index 23c7a679185ee..eac93be196356 100644 --- a/.github/workflows/pr-subscriber.yml +++ b/.github/workflows/pr-subscriber.yml @@ -14,7 +14,7 @@ jobs: if: github.repository == 'llvm/llvm-project' steps: - name: Checkout Automation Script - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: sparse-checkout: llvm/utils/git/ ref: main diff --git a/.github/workflows/premerge.yaml b/.github/workflows/premerge.yaml index daf88b5b22125..252d7fbe8e67f 100644 --- a/.github/workflows/premerge.yaml +++ b/.github/workflows/premerge.yaml @@ -58,7 +58,7 @@ jobs: shell: bash steps: - name: Checkout LLVM - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: fetch-depth: 2 - name: Build and Test @@ -139,7 +139,7 @@ jobs: shell: bash steps: - name: Checkout LLVM - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: fetch-depth: 2 - name: Compute Projects @@ -196,7 +196,7 @@ jobs: (github.event_name != 'pull_request' || github.event.action != 'closed') steps: - name: Checkout LLVM - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: fetch-depth: 2 - name: Setup ccache diff --git a/.github/workflows/release-asset-audit.yml b/.github/workflows/release-asset-audit.yml index b658167d1db36..66ea3537a9162 100644 --- a/.github/workflows/release-asset-audit.yml +++ b/.github/workflows/release-asset-audit.yml @@ -23,7 +23,7 @@ jobs: if: github.repository == 'llvm/llvm-project' steps: - name: Checkout LLVM - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: sparse-checkout: | .github/workflows/release-asset-audit.py diff --git a/.github/workflows/release-binaries.yml b/.github/workflows/release-binaries.yml index 64f371e9f8db8..104d37db8a28d 100644 --- a/.github/workflows/release-binaries.yml +++ b/.github/workflows/release-binaries.yml @@ -71,7 +71,7 @@ jobs: python-version: '3.14' - name: Checkout LLVM - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - name: Install Dependencies shell: bash @@ -184,7 +184,7 @@ jobs: steps: - name: Checkout LLVM - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: ref: ${{ needs.prepare.outputs.ref }} @@ -246,7 +246,7 @@ jobs: steps: - name: Checkout Release Scripts - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: sparse-checkout: | llvm/utils/release/github-upload-release.py diff --git a/.github/workflows/release-documentation.yml b/.github/workflows/release-documentation.yml index c09ad57066711..23bc0aed4a546 100644 --- a/.github/workflows/release-documentation.yml +++ b/.github/workflows/release-documentation.yml @@ -38,7 +38,7 @@ jobs: upload: ${{ inputs.upload && !contains(inputs.release-version, 'rc') }} steps: - name: Checkout LLVM - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - name: Setup Python env uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0 @@ -70,7 +70,7 @@ jobs: - name: Clone www-releases if: env.upload - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: repository: ${{ github.repository_owner }}/www-releases ref: main diff --git a/.github/workflows/release-doxygen.yml b/.github/workflows/release-doxygen.yml index c31319e47833d..6e6ea883ef1d0 100644 --- a/.github/workflows/release-doxygen.yml +++ b/.github/workflows/release-doxygen.yml @@ -40,7 +40,7 @@ jobs: upload: ${{ inputs.upload && !contains(inputs.release-version, 'rc') }} steps: - name: Checkout LLVM - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - name: Setup Python env uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0 diff --git a/.github/workflows/release-lit.yml b/.github/workflows/release-lit.yml index f2fd4a52328a7..e7a94572429d0 100644 --- a/.github/workflows/release-lit.yml +++ b/.github/workflows/release-lit.yml @@ -28,7 +28,7 @@ jobs: runs-on: ubuntu-24.04 steps: - name: Checkout LLVM - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: ref: "llvmorg-${{ inputs.release-version }}" diff --git a/.github/workflows/release-sources.yml b/.github/workflows/release-sources.yml index 4c47bd7575d99..9b21d2adfd27a 100644 --- a/.github/workflows/release-sources.yml +++ b/.github/workflows/release-sources.yml @@ -71,7 +71,7 @@ jobs: attestations: write steps: - name: Checkout LLVM - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: ref: ${{ needs.inputs.outputs.ref }} fetch-tags: true diff --git a/.github/workflows/release-tasks.yml b/.github/workflows/release-tasks.yml index d4c2a55fcc9d7..199017a4a7b27 100644 --- a/.github/workflows/release-tasks.yml +++ b/.github/workflows/release-tasks.yml @@ -38,7 +38,7 @@ jobs: sudo apt-get install python3-github - name: Checkout LLVM - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - name: Create Release env: @@ -132,7 +132,7 @@ jobs: sudo apt-get install python3-github - name: Checkout LLVM - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: sparse-checkout: llvm/utils/release/github-upload-release.py sparse-checkout-cone-mode: false diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 597b6f0c0e0f0..4ce3df621bb76 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -31,7 +31,7 @@ jobs: steps: - name: "Checkout code" - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: persist-credentials: false diff --git a/.github/workflows/spirv-tests.yml b/.github/workflows/spirv-tests.yml index 69374ae563306..5ede9df3b006d 100644 --- a/.github/workflows/spirv-tests.yml +++ b/.github/workflows/spirv-tests.yml @@ -24,7 +24,7 @@ jobs: container: image: ghcr.io/llvm/ci-ubuntu-24.04:latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - name: Setup ccache uses: hendrikmuhs/ccache-action@bfa03e1de4d7f7c3e80ad9109feedd05c4f5a716 # v1.2.19 with: diff --git a/.github/workflows/test-unprivileged-download-artifact.yml b/.github/workflows/test-unprivileged-download-artifact.yml index a9c0912b0f44e..39ac3d57a3879 100644 --- a/.github/workflows/test-unprivileged-download-artifact.yml +++ b/.github/workflows/test-unprivileged-download-artifact.yml @@ -38,7 +38,7 @@ jobs: needs: [ upload-test-artifact ] steps: - name: Chekcout LLVM - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: sparse-checkout: | .github/workflows/unprivileged-download-artifact/action.yml diff --git a/.github/workflows/version-check.yml b/.github/workflows/version-check.yml index 7e451880f4cfa..b3fc1f49db56a 100644 --- a/.github/workflows/version-check.yml +++ b/.github/workflows/version-check.yml @@ -17,7 +17,7 @@ jobs: runs-on: ubuntu-24.04 steps: - name: Fetch LLVM sources - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 + uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: fetch-depth: 0 From 3db8ed05004d4a1f2fb7cb34813c5e44a2e6722a Mon Sep 17 00:00:00 2001 From: Matthias Springer Date: Tue, 25 Nov 2025 09:50:20 +0800 Subject: [PATCH 46/50] [mlir][arith] Add support for `fptosi`, `fptoui` to `ArithToAPFloat` (#169277) Add support for `arith.fptosi` and `arith.fptoui`. --- .../ArithToAPFloat/ArithToAPFloat.cpp | 64 ++++++++++++++++++- mlir/lib/ExecutionEngine/APFloatWrappers.cpp | 18 ++++++ .../ArithToApfloat/arith-to-apfloat.mlir | 26 ++++++++ .../Arith/CPU/test-apfloat-emulation.mlir | 10 +++ 4 files changed, 116 insertions(+), 2 deletions(-) diff --git a/mlir/lib/Conversion/ArithToAPFloat/ArithToAPFloat.cpp b/mlir/lib/Conversion/ArithToAPFloat/ArithToAPFloat.cpp index 9aee85bc7e9ea..1de67d0fd184c 100644 --- a/mlir/lib/Conversion/ArithToAPFloat/ArithToAPFloat.cpp +++ b/mlir/lib/Conversion/ArithToAPFloat/ArithToAPFloat.cpp @@ -159,9 +159,8 @@ struct FpToFpConversion final : OpRewritePattern { Location loc = op.getLoc(); auto inFloatTy = cast(op.getOperand().getType()); auto inIntWType = rewriter.getIntegerType(inFloatTy.getWidth()); - auto int64Type = rewriter.getI64Type(); Value operandBits = arith::ExtUIOp::create( - rewriter, loc, int64Type, + rewriter, loc, i64Type, arith::BitcastOp::create(rewriter, loc, inIntWType, op.getOperand())); // Call APFloat function. @@ -185,6 +184,63 @@ struct FpToFpConversion final : OpRewritePattern { SymbolOpInterface symTable; }; +template +struct FpToIntConversion final : OpRewritePattern { + FpToIntConversion(MLIRContext *context, SymbolOpInterface symTable, + bool isUnsigned, PatternBenefit benefit = 1) + : OpRewritePattern(context, benefit), symTable(symTable), + isUnsigned(isUnsigned) {} + + LogicalResult matchAndRewrite(OpTy op, + PatternRewriter &rewriter) const override { + if (op.getType().getIntOrFloatBitWidth() > 64) + return rewriter.notifyMatchFailure( + op, "result type > 64 bits is not supported"); + + // Get APFloat function from runtime library. + auto i1Type = IntegerType::get(symTable->getContext(), 1); + auto i32Type = IntegerType::get(symTable->getContext(), 32); + auto i64Type = IntegerType::get(symTable->getContext(), 64); + FailureOr fn = + lookupOrCreateApFloatFn(rewriter, symTable, "convert_to_int", + {i32Type, i32Type, i1Type, i64Type}); + if (failed(fn)) + return fn; + + rewriter.setInsertionPoint(op); + // Cast operands to 64-bit integers. + Location loc = op.getLoc(); + auto inFloatTy = cast(op.getOperand().getType()); + auto inIntWType = rewriter.getIntegerType(inFloatTy.getWidth()); + Value operandBits = arith::ExtUIOp::create( + rewriter, loc, i64Type, + arith::BitcastOp::create(rewriter, loc, inIntWType, op.getOperand())); + + // Call APFloat function. + Value inSemValue = getSemanticsValue(rewriter, loc, inFloatTy); + auto outIntTy = cast(op.getType()); + Value outWidthValue = arith::ConstantOp::create( + rewriter, loc, i32Type, + rewriter.getIntegerAttr(i32Type, outIntTy.getWidth())); + Value isUnsignedValue = arith::ConstantOp::create( + rewriter, loc, i1Type, rewriter.getIntegerAttr(i1Type, isUnsigned)); + SmallVector params = {inSemValue, outWidthValue, isUnsignedValue, + operandBits}; + auto resultOp = + func::CallOp::create(rewriter, loc, TypeRange(rewriter.getI64Type()), + SymbolRefAttr::get(*fn), params); + + // Truncate result to the original width. + Value truncatedBits = arith::TruncIOp::create(rewriter, loc, outIntTy, + resultOp->getResult(0)); + rewriter.replaceOp(op, truncatedBits); + return success(); + } + + SymbolOpInterface symTable; + bool isUnsigned; +}; + namespace { struct ArithToAPFloatConversionPass final : impl::ArithToAPFloatConversionPassBase { @@ -209,6 +265,10 @@ void ArithToAPFloatConversionPass::runOnOperation() { patterns .add, FpToFpConversion>( context, getOperation()); + patterns.add>(context, getOperation(), + /*isUnsigned=*/false); + patterns.add>(context, getOperation(), + /*isUnsigned=*/true); LogicalResult result = success(); ScopedDiagnosticHandler scopedHandler(context, [&result](Diagnostic &diag) { if (diag.getSeverity() == DiagnosticSeverity::Error) { diff --git a/mlir/lib/ExecutionEngine/APFloatWrappers.cpp b/mlir/lib/ExecutionEngine/APFloatWrappers.cpp index 511b05ea380f0..8b89c43446765 100644 --- a/mlir/lib/ExecutionEngine/APFloatWrappers.cpp +++ b/mlir/lib/ExecutionEngine/APFloatWrappers.cpp @@ -20,6 +20,7 @@ // APFloatBase::Semantics enum value. // #include "llvm/ADT/APFloat.h" +#include "llvm/ADT/APSInt.h" #ifdef _WIN32 #ifndef MLIR_APFLOAT_WRAPPERS_EXPORT @@ -101,4 +102,21 @@ _mlir_apfloat_convert(int32_t inSemantics, int32_t outSemantics, uint64_t a) { llvm::APInt result = val.bitcastToAPInt(); return result.getZExtValue(); } + +MLIR_APFLOAT_WRAPPERS_EXPORT uint64_t _mlir_apfloat_convert_to_int( + int32_t semantics, int32_t resultWidth, bool isUnsigned, uint64_t a) { + const llvm::fltSemantics &sem = llvm::APFloatBase::EnumToSemantics( + static_cast(semantics)); + unsigned inputWidth = llvm::APFloatBase::semanticsSizeInBits(sem); + llvm::APFloat val(sem, llvm::APInt(inputWidth, a)); + llvm::APSInt result(resultWidth, isUnsigned); + bool isExact; + // TODO: Custom rounding modes are not supported yet. + val.convertToInteger(result, llvm::RoundingMode::NearestTiesToEven, &isExact); + // This function always returns uint64_t, regardless of the desired result + // width. It does not matter whether we zero-extend or sign-extend the APSInt + // to 64 bits because the generated IR in arith-to-apfloat will truncate the + // result to the desired result width. + return result.getZExtValue(); +} } diff --git a/mlir/test/Conversion/ArithToApfloat/arith-to-apfloat.mlir b/mlir/test/Conversion/ArithToApfloat/arith-to-apfloat.mlir index 038acbfc965a2..f1acfd5e5618a 100644 --- a/mlir/test/Conversion/ArithToApfloat/arith-to-apfloat.mlir +++ b/mlir/test/Conversion/ArithToApfloat/arith-to-apfloat.mlir @@ -148,3 +148,29 @@ func.func @truncf(%arg0: bf16) { %0 = arith.truncf %arg0 : bf16 to f4E2M1FN return } + +// ----- + +// CHECK: func.func private @_mlir_apfloat_convert_to_int(i32, i32, i1, i64) -> i64 +// CHECK: %[[sem_in:.*]] = arith.constant 0 : i32 +// CHECK: %[[out_width:.*]] = arith.constant 4 : i32 +// CHECK: %[[is_unsigned:.*]] = arith.constant false +// CHECK: %[[res:.*]] = call @_mlir_apfloat_convert_to_int(%[[sem_in]], %[[out_width]], %[[is_unsigned]], %{{.*}}) : (i32, i32, i1, i64) -> i64 +// CHECK: arith.trunci %[[res]] : i64 to i4 +func.func @fptosi(%arg0: f16) { + %0 = arith.fptosi %arg0 : f16 to i4 + return +} + +// ----- + +// CHECK: func.func private @_mlir_apfloat_convert_to_int(i32, i32, i1, i64) -> i64 +// CHECK: %[[sem_in:.*]] = arith.constant 0 : i32 +// CHECK: %[[out_width:.*]] = arith.constant 4 : i32 +// CHECK: %[[is_unsigned:.*]] = arith.constant true +// CHECK: %[[res:.*]] = call @_mlir_apfloat_convert_to_int(%[[sem_in]], %[[out_width]], %[[is_unsigned]], %{{.*}}) : (i32, i32, i1, i64) -> i64 +// CHECK: arith.trunci %[[res]] : i64 to i4 +func.func @fptoui(%arg0: f16) { + %0 = arith.fptoui %arg0 : f16 to i4 + return +} diff --git a/mlir/test/Integration/Dialect/Arith/CPU/test-apfloat-emulation.mlir b/mlir/test/Integration/Dialect/Arith/CPU/test-apfloat-emulation.mlir index 51976434d2be2..5e93945c3eb60 100644 --- a/mlir/test/Integration/Dialect/Arith/CPU/test-apfloat-emulation.mlir +++ b/mlir/test/Integration/Dialect/Arith/CPU/test-apfloat-emulation.mlir @@ -43,5 +43,15 @@ func.func @entry() { %cvt = arith.truncf %b2 : f32 to f8E4M3FN vector.print %cvt : f8E4M3FN + // CHECK-NEXT: 1 + // Bit pattern: 01, interpreted as signed integer: 1 + %cvt_int_signed = arith.fptosi %cvt : f8E4M3FN to i2 + vector.print %cvt_int_signed : i2 + + // CHECK-NEXT: -2 + // Bit pattern: 10, interpreted as signed integer: -2 + %cvt_int_unsigned = arith.fptoui %cvt : f8E4M3FN to i2 + vector.print %cvt_int_unsigned : i2 + return } From d7f630139023d3d13d38f0bc42536b67f1f5e38f Mon Sep 17 00:00:00 2001 From: Hristo Hristov Date: Tue, 25 Nov 2025 04:02:40 +0200 Subject: [PATCH 47/50] [libc++][string] Applied `[[nodiscard]]` to non-member functions (#169330) `[[nodiscard]]` should be applied to functions where discarding the return value is most likely a correctness issue. - https://libcxx.llvm.org/CodingGuidelines.html#apply-nodiscard-where-relevant --- libcxx/include/string | 99 ++++++++++--------- .../diagnostics/string.nodiscard.verify.cpp | 77 +++++++++++++++ 2 files changed, 130 insertions(+), 46 deletions(-) diff --git a/libcxx/include/string b/libcxx/include/string index 6b42cb2c7586d..2b3ba6d2d9b62 100644 --- a/libcxx/include/string +++ b/libcxx/include/string @@ -3851,46 +3851,52 @@ swap(basic_string<_CharT, _Traits, _Allocator>& __lhs, basic_string<_CharT, _Tra __lhs.swap(__rhs); } -_LIBCPP_EXPORTED_FROM_ABI int stoi(const string& __str, size_t* __idx = nullptr, int __base = 10); -_LIBCPP_EXPORTED_FROM_ABI long stol(const string& __str, size_t* __idx = nullptr, int __base = 10); -_LIBCPP_EXPORTED_FROM_ABI unsigned long stoul(const string& __str, size_t* __idx = nullptr, int __base = 10); -_LIBCPP_EXPORTED_FROM_ABI long long stoll(const string& __str, size_t* __idx = nullptr, int __base = 10); -_LIBCPP_EXPORTED_FROM_ABI unsigned long long stoull(const string& __str, size_t* __idx = nullptr, int __base = 10); - -_LIBCPP_EXPORTED_FROM_ABI float stof(const string& __str, size_t* __idx = nullptr); -_LIBCPP_EXPORTED_FROM_ABI double stod(const string& __str, size_t* __idx = nullptr); -_LIBCPP_EXPORTED_FROM_ABI long double stold(const string& __str, size_t* __idx = nullptr); - -_LIBCPP_EXPORTED_FROM_ABI string to_string(int __val); -_LIBCPP_EXPORTED_FROM_ABI string to_string(unsigned __val); -_LIBCPP_EXPORTED_FROM_ABI string to_string(long __val); -_LIBCPP_EXPORTED_FROM_ABI string to_string(unsigned long __val); -_LIBCPP_EXPORTED_FROM_ABI string to_string(long long __val); -_LIBCPP_EXPORTED_FROM_ABI string to_string(unsigned long long __val); -_LIBCPP_EXPORTED_FROM_ABI string to_string(float __val); -_LIBCPP_EXPORTED_FROM_ABI string to_string(double __val); -_LIBCPP_EXPORTED_FROM_ABI string to_string(long double __val); +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI int stoi(const string& __str, size_t* __idx = nullptr, int __base = 10); +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI unsigned long +stoul(const string& __str, size_t* __idx = nullptr, int __base = 10); +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI long stol(const string& __str, size_t* __idx = nullptr, int __base = 10); +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI long long +stoll(const string& __str, size_t* __idx = nullptr, int __base = 10); +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI unsigned long long +stoull(const string& __str, size_t* __idx = nullptr, int __base = 10); + +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI float stof(const string& __str, size_t* __idx = nullptr); +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI double stod(const string& __str, size_t* __idx = nullptr); +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI long double stold(const string& __str, size_t* __idx = nullptr); + +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI string to_string(int __val); +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI string to_string(unsigned __val); +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI string to_string(long __val); +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI string to_string(unsigned long __val); +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI string to_string(long long __val); +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI string to_string(unsigned long long __val); +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI string to_string(float __val); +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI string to_string(double __val); +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI string to_string(long double __val); # if _LIBCPP_HAS_WIDE_CHARACTERS -_LIBCPP_EXPORTED_FROM_ABI int stoi(const wstring& __str, size_t* __idx = nullptr, int __base = 10); -_LIBCPP_EXPORTED_FROM_ABI long stol(const wstring& __str, size_t* __idx = nullptr, int __base = 10); -_LIBCPP_EXPORTED_FROM_ABI unsigned long stoul(const wstring& __str, size_t* __idx = nullptr, int __base = 10); -_LIBCPP_EXPORTED_FROM_ABI long long stoll(const wstring& __str, size_t* __idx = nullptr, int __base = 10); -_LIBCPP_EXPORTED_FROM_ABI unsigned long long stoull(const wstring& __str, size_t* __idx = nullptr, int __base = 10); - -_LIBCPP_EXPORTED_FROM_ABI float stof(const wstring& __str, size_t* __idx = nullptr); -_LIBCPP_EXPORTED_FROM_ABI double stod(const wstring& __str, size_t* __idx = nullptr); -_LIBCPP_EXPORTED_FROM_ABI long double stold(const wstring& __str, size_t* __idx = nullptr); - -_LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(int __val); -_LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(unsigned __val); -_LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(long __val); -_LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(unsigned long __val); -_LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(long long __val); -_LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(unsigned long long __val); -_LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(float __val); -_LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(double __val); -_LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(long double __val); +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI int stoi(const wstring& __str, size_t* __idx = nullptr, int __base = 10); +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI long stol(const wstring& __str, size_t* __idx = nullptr, int __base = 10); +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI unsigned long +stoul(const wstring& __str, size_t* __idx = nullptr, int __base = 10); +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI long long +stoll(const wstring& __str, size_t* __idx = nullptr, int __base = 10); +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI unsigned long long +stoull(const wstring& __str, size_t* __idx = nullptr, int __base = 10); + +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI float stof(const wstring& __str, size_t* __idx = nullptr); +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI double stod(const wstring& __str, size_t* __idx = nullptr); +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI long double stold(const wstring& __str, size_t* __idx = nullptr); + +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(int __val); +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(unsigned __val); +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(long __val); +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(unsigned long __val); +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(long long __val); +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(unsigned long long __val); +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(float __val); +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(double __val); +[[__nodiscard__]] _LIBCPP_EXPORTED_FROM_ABI wstring to_wstring(long double __val); # endif // _LIBCPP_HAS_WIDE_CHARACTERS template @@ -3899,7 +3905,7 @@ _LIBCPP_TEMPLATE_DATA_VIS const typename basic_string<_CharT, _Traits, _Allocato template struct __string_hash : public __unary_function, _Allocator>, size_t> { - _LIBCPP_HIDE_FROM_ABI size_t + [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI size_t operator()(const basic_string<_CharT, char_traits<_CharT>, _Allocator>& __val) const _NOEXCEPT { return std::__do_string_hash(__val.data(), __val.data() + __val.size()); } @@ -3970,30 +3976,31 @@ erase_if(basic_string<_CharT, _Traits, _Allocator>& __str, _Predicate __pred) { // Literal suffixes for basic_string [basic.string.literals] inline namespace literals { inline namespace string_literals { -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string operator""s(const char* __str, size_t __len) { return basic_string(__str, __len); } # if _LIBCPP_HAS_WIDE_CHARACTERS -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string -operator""s(const wchar_t* __str, size_t __len) { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI +_LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string operator""s(const wchar_t* __str, size_t __len) { return basic_string(__str, __len); } # endif # if _LIBCPP_HAS_CHAR8_T -inline _LIBCPP_HIDE_FROM_ABI constexpr basic_string operator""s(const char8_t* __str, size_t __len) { +[[__nodiscard__]] inline + _LIBCPP_HIDE_FROM_ABI constexpr basic_string operator""s(const char8_t* __str, size_t __len) { return basic_string(__str, __len); } # endif -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string -operator""s(const char16_t* __str, size_t __len) { +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI +_LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string operator""s(const char16_t* __str, size_t __len) { return basic_string(__str, __len); } -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string +[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 basic_string operator""s(const char32_t* __str, size_t __len) { return basic_string(__str, __len); } diff --git a/libcxx/test/libcxx/diagnostics/string.nodiscard.verify.cpp b/libcxx/test/libcxx/diagnostics/string.nodiscard.verify.cpp index f020516a2495a..0ff92cac3a3b2 100644 --- a/libcxx/test/libcxx/diagnostics/string.nodiscard.verify.cpp +++ b/libcxx/test/libcxx/diagnostics/string.nodiscard.verify.cpp @@ -130,3 +130,80 @@ void test() { str.subview(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} #endif } + +void test_nonmembers() { + // Numeric conversions + + std::string str; + + std::stoi(str); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + std::stol(str); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + std::stoll(str); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + std::stoull(str); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + + std::stof(str); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + std::stod(str); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + std::stold(str); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + + std::to_string(94); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + std::to_string(82U); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + std::to_string(94L); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + std::to_string(82UL); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + std::to_string(94LL); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + std::to_string(82ULL); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + std::to_string(94.0F); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + std::to_string(82.0); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + std::to_string(94.0L); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + +#if !defined(TEST_HAS_NO_WIDE_CHARACTERS) + + std::wstring wstr; + + std::stoi(wstr); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + std::stol(wstr); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + std::stoll(wstr); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + std::stoull(wstr); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + + std::stof(wstr); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + std::stod(wstr); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + std::stold(wstr); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + + std::to_wstring(94); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + std::to_wstring(82U); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + std::to_wstring(94L); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + std::to_wstring(82UL); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + std::to_wstring(94LL); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + std::to_wstring(82ULL); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + std::to_wstring(94.0F); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + std::to_wstring(82.0); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + std::to_wstring(94.0L); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + +#endif + + // std::hash<> + + std::hash hash; + + hash(str); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}} + +#if TEST_STD_VER >= 14 + // string literals + + using namespace std::string_literals; + + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + ""s; // const char* +# if !defined(TEST_HAS_NO_WIDE_CHARACTERS) + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + L""s; // const wchar_t* +# endif +# if !defined(TEST_HAS_NO_CHAR8_T) + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + u8""s; // const char8_t* +# endif + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + u""s; // const char16_t* + // expected-warning@+1 {{ignoring return value of function declared with 'nodiscard' attribute}} + U""s; // const char32_t* +#endif +} From b63a1883c153245837933e646bdf6c2b4a7bb36b Mon Sep 17 00:00:00 2001 From: Craig Topper Date: Mon, 24 Nov 2025 18:21:37 -0800 Subject: [PATCH 48/50] [RISCV] Use a switch in VSETVLIInfo::print(). NFC (#169441) This allows the compiler to verify we've covered all enum values. --- llvm/lib/Target/RISCV/RISCVInsertVSETVLI.cpp | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/llvm/lib/Target/RISCV/RISCVInsertVSETVLI.cpp b/llvm/lib/Target/RISCV/RISCVInsertVSETVLI.cpp index e5819d90526d9..2ddc9b0adb9e1 100644 --- a/llvm/lib/Target/RISCV/RISCVInsertVSETVLI.cpp +++ b/llvm/lib/Target/RISCV/RISCVInsertVSETVLI.cpp @@ -838,16 +838,23 @@ class VSETVLIInfo { /// @{ void print(raw_ostream &OS) const { OS << "{"; - if (!isValid()) + switch (State) { + case Uninitialized: OS << "Uninitialized"; - if (isUnknown()) + break; + case Unknown: OS << "unknown"; - if (hasAVLReg()) + break; + case AVLIsReg: OS << "AVLReg=" << llvm::printReg(getAVLReg()); - if (hasAVLImm()) + break; + case AVLIsImm: OS << "AVLImm=" << (unsigned)AVLImm; - if (hasAVLVLMAX()) + break; + case AVLIsVLMAX: OS << "AVLVLMAX"; + break; + } OS << ", "; unsigned LMul; From 8217c6415ab76c2a0f06705100c76207cd1e6bc0 Mon Sep 17 00:00:00 2001 From: Kewen Meng Date: Mon, 24 Nov 2025 18:30:02 -0800 Subject: [PATCH 49/50] Revert "[MC] Use a variant to hold MCCFIInstruction state (NFC)" (#169442) Reverts llvm/llvm-project#164720 Revert to unblock bots. https://lab.llvm.org/buildbot/#/builders/140/builds/34645 --- llvm/include/llvm/MC/MCDwarf.h | 137 ++++++++++++++++++--------------- 1 file changed, 77 insertions(+), 60 deletions(-) diff --git a/llvm/include/llvm/MC/MCDwarf.h b/llvm/include/llvm/MC/MCDwarf.h index 640d2eeb68d61..9944a9a92ab1f 100644 --- a/llvm/include/llvm/MC/MCDwarf.h +++ b/llvm/include/llvm/MC/MCDwarf.h @@ -29,7 +29,6 @@ #include #include #include -#include #include namespace llvm { @@ -532,47 +531,67 @@ class MCCFIInstruction { OpValOffset, }; - // Held in ExtraFields for most common OpTypes, exceptions follow. - struct CommonFields { - unsigned Register = std::numeric_limits::max(); - int64_t Offset = 0; - unsigned Register2 = std::numeric_limits::max(); - unsigned AddressSpace = 0; - }; - // Held in ExtraFields when OpEscape. - struct EscapeFields { - std::vector Values; - std::string Comment; - }; - // Held in ExtraFields when OpLabel. - struct LabelFields { - MCSymbol *CfiLabel = nullptr; - }; - private: MCSymbol *Label; - std::variant ExtraFields; + union { + struct { + unsigned Register; + int64_t Offset; + } RI; + struct { + unsigned Register; + int64_t Offset; + unsigned AddressSpace; + } RIA; + struct { + unsigned Register; + unsigned Register2; + } RR; + MCSymbol *CfiLabel; + } U; OpType Operation; SMLoc Loc; + std::vector Values; + std::string Comment; - template - MCCFIInstruction(OpType Op, MCSymbol *L, FieldsType &&EF, SMLoc Loc) - : Label(L), ExtraFields(std::forward(EF)), Operation(Op), - Loc(Loc) {} + MCCFIInstruction(OpType Op, MCSymbol *L, unsigned R, int64_t O, SMLoc Loc, + StringRef V = "", StringRef Comment = "") + : Label(L), Operation(Op), Loc(Loc), Values(V.begin(), V.end()), + Comment(Comment) { + assert(Op != OpRegister && Op != OpLLVMDefAspaceCfa); + U.RI = {R, O}; + } + MCCFIInstruction(OpType Op, MCSymbol *L, unsigned R1, unsigned R2, SMLoc Loc) + : Label(L), Operation(Op), Loc(Loc) { + assert(Op == OpRegister); + U.RR = {R1, R2}; + } + MCCFIInstruction(OpType Op, MCSymbol *L, unsigned R, int64_t O, unsigned AS, + SMLoc Loc) + : Label(L), Operation(Op), Loc(Loc) { + assert(Op == OpLLVMDefAspaceCfa); + U.RIA = {R, O, AS}; + } + + MCCFIInstruction(OpType Op, MCSymbol *L, MCSymbol *CfiLabel, SMLoc Loc) + : Label(L), Operation(Op), Loc(Loc) { + assert(Op == OpLabel); + U.CfiLabel = CfiLabel; + } public: /// .cfi_def_cfa defines a rule for computing CFA as: take address from /// Register and add Offset to it. static MCCFIInstruction cfiDefCfa(MCSymbol *L, unsigned Register, int64_t Offset, SMLoc Loc = {}) { - return {OpDefCfa, L, CommonFields{Register, Offset}, Loc}; + return MCCFIInstruction(OpDefCfa, L, Register, Offset, Loc); } /// .cfi_def_cfa_register modifies a rule for computing CFA. From now /// on Register will be used instead of the old one. Offset remains the same. static MCCFIInstruction createDefCfaRegister(MCSymbol *L, unsigned Register, SMLoc Loc = {}) { - return {OpDefCfaRegister, L, CommonFields{Register}, Loc}; + return MCCFIInstruction(OpDefCfaRegister, L, Register, INT64_C(0), Loc); } /// .cfi_def_cfa_offset modifies a rule for computing CFA. Register @@ -580,7 +599,7 @@ class MCCFIInstruction { /// that will be added to a defined register to the compute CFA address. static MCCFIInstruction cfiDefCfaOffset(MCSymbol *L, int64_t Offset, SMLoc Loc = {}) { - return {OpDefCfaOffset, L, CommonFields{0, Offset}, Loc}; + return MCCFIInstruction(OpDefCfaOffset, L, 0, Offset, Loc); } /// .cfi_adjust_cfa_offset Same as .cfi_def_cfa_offset, but @@ -588,7 +607,7 @@ class MCCFIInstruction { /// offset. static MCCFIInstruction createAdjustCfaOffset(MCSymbol *L, int64_t Adjustment, SMLoc Loc = {}) { - return {OpAdjustCfaOffset, L, CommonFields{0, Adjustment}, Loc}; + return MCCFIInstruction(OpAdjustCfaOffset, L, 0, Adjustment, Loc); } // FIXME: Update the remaining docs to use the new proposal wording. @@ -599,15 +618,15 @@ class MCCFIInstruction { int64_t Offset, unsigned AddressSpace, SMLoc Loc) { - return {OpLLVMDefAspaceCfa, L, - CommonFields{Register, Offset, 0, AddressSpace}, Loc}; + return MCCFIInstruction(OpLLVMDefAspaceCfa, L, Register, Offset, + AddressSpace, Loc); } /// .cfi_offset Previous value of Register is saved at offset Offset /// from CFA. static MCCFIInstruction createOffset(MCSymbol *L, unsigned Register, int64_t Offset, SMLoc Loc = {}) { - return {OpOffset, L, CommonFields{Register, Offset}, Loc}; + return MCCFIInstruction(OpOffset, L, Register, Offset, Loc); } /// .cfi_rel_offset Previous value of Register is saved at offset @@ -615,30 +634,30 @@ class MCCFIInstruction { /// using the known displacement of the CFA register from the CFA. static MCCFIInstruction createRelOffset(MCSymbol *L, unsigned Register, int64_t Offset, SMLoc Loc = {}) { - return {OpRelOffset, L, CommonFields{Register, Offset}, Loc}; + return MCCFIInstruction(OpRelOffset, L, Register, Offset, Loc); } /// .cfi_register Previous value of Register1 is saved in /// register Register2. static MCCFIInstruction createRegister(MCSymbol *L, unsigned Register1, unsigned Register2, SMLoc Loc = {}) { - return {OpRegister, L, CommonFields{Register1, 0, Register2}, Loc}; + return MCCFIInstruction(OpRegister, L, Register1, Register2, Loc); } /// .cfi_window_save SPARC register window is saved. static MCCFIInstruction createWindowSave(MCSymbol *L, SMLoc Loc = {}) { - return {OpWindowSave, L, CommonFields{}, Loc}; + return MCCFIInstruction(OpWindowSave, L, 0, INT64_C(0), Loc); } /// .cfi_negate_ra_state AArch64 negate RA state. static MCCFIInstruction createNegateRAState(MCSymbol *L, SMLoc Loc = {}) { - return {OpNegateRAState, L, CommonFields{}, Loc}; + return MCCFIInstruction(OpNegateRAState, L, 0, INT64_C(0), Loc); } /// .cfi_negate_ra_state_with_pc AArch64 negate RA state with PC. static MCCFIInstruction createNegateRAStateWithPC(MCSymbol *L, SMLoc Loc = {}) { - return {OpNegateRAStateWithPC, L, CommonFields{}, Loc}; + return MCCFIInstruction(OpNegateRAStateWithPC, L, 0, INT64_C(0), Loc); } /// .cfi_restore says that the rule for Register is now the same as it @@ -646,106 +665,104 @@ class MCCFIInstruction { /// by .cfi_startproc were executed. static MCCFIInstruction createRestore(MCSymbol *L, unsigned Register, SMLoc Loc = {}) { - return {OpRestore, L, CommonFields{Register}, Loc}; + return MCCFIInstruction(OpRestore, L, Register, INT64_C(0), Loc); } /// .cfi_undefined From now on the previous value of Register can't be /// restored anymore. static MCCFIInstruction createUndefined(MCSymbol *L, unsigned Register, SMLoc Loc = {}) { - return {OpUndefined, L, CommonFields{Register}, Loc}; + return MCCFIInstruction(OpUndefined, L, Register, INT64_C(0), Loc); } /// .cfi_same_value Current value of Register is the same as in the /// previous frame. I.e., no restoration is needed. static MCCFIInstruction createSameValue(MCSymbol *L, unsigned Register, SMLoc Loc = {}) { - return {OpSameValue, L, CommonFields{Register}, Loc}; + return MCCFIInstruction(OpSameValue, L, Register, INT64_C(0), Loc); } /// .cfi_remember_state Save all current rules for all registers. static MCCFIInstruction createRememberState(MCSymbol *L, SMLoc Loc = {}) { - return {OpRememberState, L, CommonFields{}, Loc}; + return MCCFIInstruction(OpRememberState, L, 0, INT64_C(0), Loc); } /// .cfi_restore_state Restore the previously saved state. static MCCFIInstruction createRestoreState(MCSymbol *L, SMLoc Loc = {}) { - return {OpRestoreState, L, CommonFields{}, Loc}; + return MCCFIInstruction(OpRestoreState, L, 0, INT64_C(0), Loc); } /// .cfi_escape Allows the user to add arbitrary bytes to the unwind /// info. static MCCFIInstruction createEscape(MCSymbol *L, StringRef Vals, SMLoc Loc = {}, StringRef Comment = "") { - return {OpEscape, L, - EscapeFields{std::vector(Vals.begin(), Vals.end()), - Comment.str()}, - Loc}; + return MCCFIInstruction(OpEscape, L, 0, 0, Loc, Vals, Comment); } /// A special wrapper for .cfi_escape that indicates GNU_ARGS_SIZE static MCCFIInstruction createGnuArgsSize(MCSymbol *L, int64_t Size, SMLoc Loc = {}) { - return {OpGnuArgsSize, L, CommonFields{0, Size}, Loc}; + return MCCFIInstruction(OpGnuArgsSize, L, 0, Size, Loc); } static MCCFIInstruction createLabel(MCSymbol *L, MCSymbol *CfiLabel, SMLoc Loc) { - return {OpLabel, L, LabelFields{CfiLabel}, Loc}; + return MCCFIInstruction(OpLabel, L, CfiLabel, Loc); } /// .cfi_val_offset Previous value of Register is offset Offset from the /// current CFA register. static MCCFIInstruction createValOffset(MCSymbol *L, unsigned Register, int64_t Offset, SMLoc Loc = {}) { - return {OpValOffset, L, CommonFields{Register, Offset}, Loc}; + return MCCFIInstruction(OpValOffset, L, Register, Offset, Loc); } OpType getOperation() const { return Operation; } MCSymbol *getLabel() const { return Label; } unsigned getRegister() const { + if (Operation == OpRegister) + return U.RR.Register; + if (Operation == OpLLVMDefAspaceCfa) + return U.RIA.Register; assert(Operation == OpDefCfa || Operation == OpOffset || Operation == OpRestore || Operation == OpUndefined || Operation == OpSameValue || Operation == OpDefCfaRegister || - Operation == OpRelOffset || Operation == OpValOffset || - Operation == OpRegister || Operation == OpLLVMDefAspaceCfa); - return std::get(ExtraFields).Register; + Operation == OpRelOffset || Operation == OpValOffset); + return U.RI.Register; } unsigned getRegister2() const { assert(Operation == OpRegister); - return std::get(ExtraFields).Register2; + return U.RR.Register2; } unsigned getAddressSpace() const { assert(Operation == OpLLVMDefAspaceCfa); - return std::get(ExtraFields).AddressSpace; + return U.RIA.AddressSpace; } int64_t getOffset() const { + if (Operation == OpLLVMDefAspaceCfa) + return U.RIA.Offset; assert(Operation == OpDefCfa || Operation == OpOffset || Operation == OpRelOffset || Operation == OpDefCfaOffset || Operation == OpAdjustCfaOffset || Operation == OpGnuArgsSize || - Operation == OpValOffset || Operation == OpLLVMDefAspaceCfa); - return std::get(ExtraFields).Offset; + Operation == OpValOffset); + return U.RI.Offset; } MCSymbol *getCfiLabel() const { assert(Operation == OpLabel); - return std::get(ExtraFields).CfiLabel; + return U.CfiLabel; } StringRef getValues() const { assert(Operation == OpEscape); - auto &Values = std::get(ExtraFields).Values; return StringRef(&Values[0], Values.size()); } - StringRef getComment() const { - assert(Operation == OpEscape); - return std::get(ExtraFields).Comment; - } + StringRef getComment() const { return Comment; } SMLoc getLoc() const { return Loc; } }; From 6ec686735c850d05592b28783f8300c725a50d78 Mon Sep 17 00:00:00 2001 From: Matthias Springer Date: Tue, 25 Nov 2025 10:31:23 +0800 Subject: [PATCH 50/50] [mlir][arith] Add support for `sitofp`, `uitofp` to `ArithToAPFloat` (#169284) Add support for `arith.sitofp` and `arith.uitofp`. --- .../ArithToAPFloat/ArithToAPFloat.cpp | 71 +++++++++++++++++++ mlir/lib/ExecutionEngine/APFloatWrappers.cpp | 12 ++++ .../ArithToApfloat/arith-to-apfloat.mlir | 24 +++++++ .../Arith/CPU/test-apfloat-emulation.mlir | 13 ++++ 4 files changed, 120 insertions(+) diff --git a/mlir/lib/Conversion/ArithToAPFloat/ArithToAPFloat.cpp b/mlir/lib/Conversion/ArithToAPFloat/ArithToAPFloat.cpp index 1de67d0fd184c..81fbdb1611deb 100644 --- a/mlir/lib/Conversion/ArithToAPFloat/ArithToAPFloat.cpp +++ b/mlir/lib/Conversion/ArithToAPFloat/ArithToAPFloat.cpp @@ -241,6 +241,73 @@ struct FpToIntConversion final : OpRewritePattern { bool isUnsigned; }; +template +struct IntToFpConversion final : OpRewritePattern { + IntToFpConversion(MLIRContext *context, SymbolOpInterface symTable, + bool isUnsigned, PatternBenefit benefit = 1) + : OpRewritePattern(context, benefit), symTable(symTable), + isUnsigned(isUnsigned) {} + + LogicalResult matchAndRewrite(OpTy op, + PatternRewriter &rewriter) const override { + Location loc = op.getLoc(); + if (op.getIn().getType().getIntOrFloatBitWidth() > 64) { + return rewriter.notifyMatchFailure( + loc, "integer bitwidth > 64 is not supported"); + } + + // Get APFloat function from runtime library. + auto i1Type = IntegerType::get(symTable->getContext(), 1); + auto i32Type = IntegerType::get(symTable->getContext(), 32); + auto i64Type = IntegerType::get(symTable->getContext(), 64); + FailureOr fn = + lookupOrCreateApFloatFn(rewriter, symTable, "convert_from_int", + {i32Type, i32Type, i1Type, i64Type}); + if (failed(fn)) + return fn; + + rewriter.setInsertionPoint(op); + // Cast operands to 64-bit integers. + auto inIntTy = cast(op.getOperand().getType()); + Value operandBits = op.getOperand(); + if (operandBits.getType().getIntOrFloatBitWidth() < 64) { + if (isUnsigned) { + operandBits = + arith::ExtUIOp::create(rewriter, loc, i64Type, operandBits); + } else { + operandBits = + arith::ExtSIOp::create(rewriter, loc, i64Type, operandBits); + } + } + + // Call APFloat function. + auto outFloatTy = cast(op.getType()); + Value outSemValue = getSemanticsValue(rewriter, loc, outFloatTy); + Value inWidthValue = arith::ConstantOp::create( + rewriter, loc, i32Type, + rewriter.getIntegerAttr(i32Type, inIntTy.getWidth())); + Value isUnsignedValue = arith::ConstantOp::create( + rewriter, loc, i1Type, rewriter.getIntegerAttr(i1Type, isUnsigned)); + SmallVector params = {outSemValue, inWidthValue, isUnsignedValue, + operandBits}; + auto resultOp = + func::CallOp::create(rewriter, loc, TypeRange(rewriter.getI64Type()), + SymbolRefAttr::get(*fn), params); + + // Truncate result to the original width. + auto outIntWType = rewriter.getIntegerType(outFloatTy.getWidth()); + Value truncatedBits = arith::TruncIOp::create(rewriter, loc, outIntWType, + resultOp->getResult(0)); + Value result = + arith::BitcastOp::create(rewriter, loc, outFloatTy, truncatedBits); + rewriter.replaceOp(op, result); + return success(); + } + + SymbolOpInterface symTable; + bool isUnsigned; +}; + namespace { struct ArithToAPFloatConversionPass final : impl::ArithToAPFloatConversionPassBase { @@ -269,6 +336,10 @@ void ArithToAPFloatConversionPass::runOnOperation() { /*isUnsigned=*/false); patterns.add>(context, getOperation(), /*isUnsigned=*/true); + patterns.add>(context, getOperation(), + /*isUnsigned=*/false); + patterns.add>(context, getOperation(), + /*isUnsigned=*/true); LogicalResult result = success(); ScopedDiagnosticHandler scopedHandler(context, [&result](Diagnostic &diag) { if (diag.getSeverity() == DiagnosticSeverity::Error) { diff --git a/mlir/lib/ExecutionEngine/APFloatWrappers.cpp b/mlir/lib/ExecutionEngine/APFloatWrappers.cpp index 8b89c43446765..44980ccd77491 100644 --- a/mlir/lib/ExecutionEngine/APFloatWrappers.cpp +++ b/mlir/lib/ExecutionEngine/APFloatWrappers.cpp @@ -119,4 +119,16 @@ MLIR_APFLOAT_WRAPPERS_EXPORT uint64_t _mlir_apfloat_convert_to_int( // result to the desired result width. return result.getZExtValue(); } + +MLIR_APFLOAT_WRAPPERS_EXPORT uint64_t _mlir_apfloat_convert_from_int( + int32_t semantics, int32_t inputWidth, bool isUnsigned, uint64_t a) { + llvm::APInt val(inputWidth, a, /*isSigned=*/!isUnsigned); + const llvm::fltSemantics &sem = llvm::APFloatBase::EnumToSemantics( + static_cast(semantics)); + llvm::APFloat result(sem); + // TODO: Custom rounding modes are not supported yet. + result.convertFromAPInt(val, /*IsSigned=*/!isUnsigned, + llvm::RoundingMode::NearestTiesToEven); + return result.bitcastToAPInt().getZExtValue(); +} } diff --git a/mlir/test/Conversion/ArithToApfloat/arith-to-apfloat.mlir b/mlir/test/Conversion/ArithToApfloat/arith-to-apfloat.mlir index f1acfd5e5618a..d71d81dddcd4f 100644 --- a/mlir/test/Conversion/ArithToApfloat/arith-to-apfloat.mlir +++ b/mlir/test/Conversion/ArithToApfloat/arith-to-apfloat.mlir @@ -174,3 +174,27 @@ func.func @fptoui(%arg0: f16) { %0 = arith.fptoui %arg0 : f16 to i4 return } + +// ----- + +// CHECK: func.func private @_mlir_apfloat_convert_from_int(i32, i32, i1, i64) -> i64 +// CHECK: %[[sem_out:.*]] = arith.constant 18 : i32 +// CHECK: %[[in_width:.*]] = arith.constant 32 : i32 +// CHECK: %[[is_unsigned:.*]] = arith.constant false +// CHECK: %[[res:.*]] = call @_mlir_apfloat_convert_from_int(%[[sem_out]], %[[in_width]], %[[is_unsigned]], %{{.*}}) : (i32, i32, i1, i64) -> i64 +func.func @sitofp(%arg0: i32) { + %0 = arith.sitofp %arg0 : i32 to f4E2M1FN + return +} + +// ----- + +// CHECK: func.func private @_mlir_apfloat_convert_from_int(i32, i32, i1, i64) -> i64 +// CHECK: %[[sem_out:.*]] = arith.constant 18 : i32 +// CHECK: %[[in_width:.*]] = arith.constant 32 : i32 +// CHECK: %[[is_unsigned:.*]] = arith.constant true +// CHECK: %[[res:.*]] = call @_mlir_apfloat_convert_from_int(%[[sem_out]], %[[in_width]], %[[is_unsigned]], %{{.*}}) : (i32, i32, i1, i64) -> i64 +func.func @uitofp(%arg0: i32) { + %0 = arith.uitofp %arg0 : i32 to f4E2M1FN + return +} diff --git a/mlir/test/Integration/Dialect/Arith/CPU/test-apfloat-emulation.mlir b/mlir/test/Integration/Dialect/Arith/CPU/test-apfloat-emulation.mlir index 5e93945c3eb60..8046610d479a8 100644 --- a/mlir/test/Integration/Dialect/Arith/CPU/test-apfloat-emulation.mlir +++ b/mlir/test/Integration/Dialect/Arith/CPU/test-apfloat-emulation.mlir @@ -53,5 +53,18 @@ func.func @entry() { %cvt_int_unsigned = arith.fptoui %cvt : f8E4M3FN to i2 vector.print %cvt_int_unsigned : i2 + // CHECK-NEXT: -6 + // Bit pattern: 1...11110111, interpreted as signed: -9 + // Closest f4E2M1FN value: -6.0 + %c9 = arith.constant -9 : i16 + %cvt_from_signed_int = arith.sitofp %c9 : i16 to f4E2M1FN + vector.print %cvt_from_signed_int : f4E2M1FN + + // CHECK-NEXT: 6 + // Bit pattern: 1...11110111, interpreted as unsigned: 65527 + // Closest f4E2M1FN value: 6.0 + %cvt_from_unsigned_int = arith.uitofp %c9 : i16 to f4E2M1FN + vector.print %cvt_from_unsigned_int : f4E2M1FN + return }