diff --git a/.github/workflows/build-ci-container.yml b/.github/workflows/build-ci-container.yml index 85ecc82fa6490..8a81d47186469 100644 --- a/.github/workflows/build-ci-container.yml +++ b/.github/workflows/build-ci-container.yml @@ -27,6 +27,7 @@ jobs: container-name-tag: ${{ steps.vars.outputs.container-name-tag }} container-name-agent-tag: ${{ steps.vars.outputs.container-name-agent-tag }} container-filename: ${{ steps.vars.outputs.container-filename }} + container-agent-filename: ${{ steps.vars.outputs.container-agent-filename }} steps: - name: Checkout LLVM uses: actions/checkout@v4 @@ -42,6 +43,7 @@ jobs: echo "container-name-tag=$container_name:$tag" >> $GITHUB_OUTPUT echo "container-name-agent-tag=$container_name-agent:$tag" >> $GITHUB_OUTPUT echo "container-filename=$(echo $container_name:$tag | sed -e 's/\//-/g' -e 's/:/-/g').tar" >> $GITHUB_OUTPUT + echo "container-agent-filename=$(echo $container_name-agent:$tag | sed -e 's/\//-/g' -e 's/:/-/g').tar" >> $GITHUB_OUTPUT - name: Build container working-directory: ./.github/workflows/containers/github-action-ci/ run: | @@ -53,13 +55,14 @@ jobs: # maintain minimal permissions while building the container. - name: Save container image run: | - podman save ${{ steps.vars.outputs.container-name-tag }} ${{ steps.vars.outputs.container-name-agent-tag }} > ${{ steps.vars.outputs.container-filename }} + podman save ${{ steps.vars.outputs.container-name-tag }} > ${{ steps.vars.outputs.container-filename }} + podman save ${{ steps.vars.outputs.container-name-agent-tag }} > ${{ steps.vars.outputs.container-agent-filename }} - name: Upload container image uses: actions/upload-artifact@v4 with: name: container - path: ${{ steps.vars.outputs.container-filename }} + path: "*.tar" retention-days: 14 - name: Test Container @@ -92,6 +95,7 @@ jobs: podman push ${{ needs.build-ci-container.outputs.container-name-tag }} podman push ${{ needs.build-ci-container.outputs.container-name }}:latest + podman load -i ${{ needs.build-ci-container.outputs.container-agent-filename }} podman tag ${{ needs.build-ci-container.outputs.container-name-agent-tag }} ${{ needs.build-ci-container.outputs.container-name-agent }}:latest podman push ${{ needs.build-ci-container.outputs.container-name-agent-tag }} podman push ${{ needs.build-ci-container.outputs.container-name-agent }}:latest diff --git a/.github/workflows/libclang-abi-tests.yml b/.github/workflows/libclang-abi-tests.yml index 9e839ff49e283..41b3075288d2d 100644 --- a/.github/workflows/libclang-abi-tests.yml +++ b/.github/workflows/libclang-abi-tests.yml @@ -130,7 +130,7 @@ jobs: sed -i 's/LLVM_[0-9]\+/LLVM_NOVERSION/' $lib-${{ matrix.ref }}.abi done - name: Upload ABI file - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # 4.6.0 with: name: ${{ matrix.name }} path: '*${{ matrix.ref }}.abi' @@ -143,12 +143,12 @@ jobs: - abi-dump steps: - name: Download baseline - uses: actions/download-artifact@v3 + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # 4.1.8 with: name: build-baseline path: build-baseline - name: Download latest - uses: actions/download-artifact@v3 + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # 4.1.8 with: name: build-latest path: build-latest @@ -162,7 +162,7 @@ jobs: done - name: Upload ABI Comparison if: always() - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # 4.6.0 with: name: compat-report-${{ github.sha }} path: compat_reports/ diff --git a/.github/workflows/libcxx-restart-preempted-jobs.yaml b/.github/workflows/libcxx-restart-preempted-jobs.yaml index 82d84c01c92af..e7e3772d4de22 100644 --- a/.github/workflows/libcxx-restart-preempted-jobs.yaml +++ b/.github/workflows/libcxx-restart-preempted-jobs.yaml @@ -92,6 +92,12 @@ jobs: check_run_id: check_run_id }) + // For temporary debugging purposes to see the structure of the annotations. + console.log(annotations); + + has_failed_job = false; + saved_failure_message = null; + for (annotation of annotations.data) { if (annotation.annotation_level != 'failure') { continue; @@ -106,15 +112,32 @@ jobs: const failure_match = annotation.message.match(failure_regex); if (failure_match != null) { - // We only want to restart the workflow if all of the failures were due to preemption. - // We don't want to restart the workflow if there were other failures. - core.notice('Choosing not to rerun workflow because we found a non-preemption failure' + - 'Failure message: "' + annotation.message + '"'); - await create_check_run('skipped', 'Choosing not to rerun workflow because we found a non-preemption failure\n' - + 'Failure message: ' + annotation.message) - return; + has_failed_job = true; + saved_failure_message = annotation.message; } } + if (has_failed_job && (! has_preempted_job)) { + // We only want to restart the workflow if all of the failures were due to preemption. + // We don't want to restart the workflow if there were other failures. + // + // However, libcxx runners running inside docker containers produce both a preemption message and failure message. + // + // The desired approach is to ignore failure messages which appear on the same job as a preemption message + // (An job is a single run with a specific configuration, ex generic-gcc, gcc-14). + // + // However, it's unclear that this code achieves the desired approach, and it may ignore all failures + // if a preemption message is found at all on any run. + // + // For now, it's more important to restart preempted workflows than to avoid restarting workflows with + // non-preemption failures. + // + // TODO Figure this out. + core.notice('Choosing not to rerun workflow because we found a non-preemption failure' + + 'Failure message: "' + saved_failure_message + '"'); + await create_check_run('skipped', 'Choosing not to rerun workflow because we found a non-preemption failure\n' + + 'Failure message: ' + saved_failure_message) + return; + } } if (!has_preempted_job) { diff --git a/.github/workflows/llvm-tests.yml b/.github/workflows/llvm-tests.yml index 26e644229aaa2..4e570a7cb1455 100644 --- a/.github/workflows/llvm-tests.yml +++ b/.github/workflows/llvm-tests.yml @@ -137,14 +137,14 @@ jobs: # Remove symbol versioning from dumps, so we can compare across major versions. sed -i 's/LLVM_${{ matrix.llvm_version_major }}/LLVM_NOVERSION/' ${{ matrix.ref }}.abi - name: Upload ABI file - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # 4.6.0 with: name: ${{ matrix.name }} path: ${{ matrix.ref }}.abi - name: Upload symbol list file if: matrix.name == 'build-baseline' - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # 4.6.0 with: name: symbol-list path: llvm.symbols @@ -157,17 +157,17 @@ jobs: - abi-dump steps: - name: Download baseline - uses: actions/download-artifact@v3 + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # 4.1.8 with: name: build-baseline path: build-baseline - name: Download latest - uses: actions/download-artifact@v3 + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # 4.1.8 with: name: build-latest path: build-latest - name: Download symbol list - uses: actions/download-artifact@v3 + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # 4.1.8 with: name: symbol-list path: symbol-list @@ -186,7 +186,7 @@ jobs: abi-compliance-checker $EXTRA_ARGS -l libLLVM.so -old build-baseline/*.abi -new build-latest/*.abi || test "${{ needs.abi-dump-setup.outputs.ABI_HEADERS }}" = "llvm-c" - name: Upload ABI Comparison if: always() - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # 4.6.0 with: name: compat-report-${{ github.sha }} path: compat_reports/ diff --git a/.github/workflows/premerge.yaml b/.github/workflows/premerge.yaml index 6c7f1d81a953e..30f4fc807f3a5 100644 --- a/.github/workflows/premerge.yaml +++ b/.github/workflows/premerge.yaml @@ -18,11 +18,6 @@ jobs: concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }} cancel-in-progress: true - container: - image: ghcr.io/llvm/ci-ubuntu-22.04:latest - defaults: - run: - shell: bash steps: - name: Checkout LLVM uses: actions/checkout@v4 diff --git a/.github/workflows/release-documentation.yml b/.github/workflows/release-documentation.yml index 922c5093f1357..09e21585bfc56 100644 --- a/.github/workflows/release-documentation.yml +++ b/.github/workflows/release-documentation.yml @@ -59,7 +59,7 @@ jobs: ./llvm/utils/release/build-docs.sh -release "${{ inputs.release-version }}" -no-doxygen - name: Create Release Notes Artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # 4.6.0 with: name: release-notes path: docs-build/html-export/ diff --git a/.github/workflows/spirv-tests.yml b/.github/workflows/spirv-tests.yml index 34c77a398c150..ea466dc6c52e5 100644 --- a/.github/workflows/spirv-tests.yml +++ b/.github/workflows/spirv-tests.yml @@ -25,5 +25,5 @@ jobs: with: build_target: check-llvm-codegen-spirv projects: - extra_cmake_args: '-DLLVM_TARGETS_TO_BUILD="" -DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD="SPIRV" -DLLVM_INCLUDE_SPIRV_TOOLS_TESTS=ON' + extra_cmake_args: '-DLLVM_TARGETS_TO_BUILD="SPIRV" -DLLVM_INCLUDE_SPIRV_TOOLS_TESTS=ON' os_list: '["ubuntu-22.04"]' diff --git a/bolt/include/bolt/Profile/DataAggregator.h b/bolt/include/bolt/Profile/DataAggregator.h index 320623cfa15af..aa83d7f9b13ab 100644 --- a/bolt/include/bolt/Profile/DataAggregator.h +++ b/bolt/include/bolt/Profile/DataAggregator.h @@ -80,7 +80,6 @@ class DataAggregator : public DataReader { private: struct PerfBranchSample { SmallVector LBR; - uint64_t PC; }; struct PerfBasicSample { @@ -334,9 +333,6 @@ class DataAggregator : public DataReader { /// Process all branch events. void processBranchEvents(); - /// This member function supports generating data for AutoFDO LLVM tools. - std::error_code writeAutoFDOData(StringRef OutputFilename); - /// Parse the full output generated by perf script to report non-LBR samples. std::error_code parseBasicEvents(); diff --git a/bolt/lib/Profile/DataAggregator.cpp b/bolt/lib/Profile/DataAggregator.cpp index 2b02086e3e0c9..de9ec6c1723d5 100644 --- a/bolt/lib/Profile/DataAggregator.cpp +++ b/bolt/lib/Profile/DataAggregator.cpp @@ -108,15 +108,6 @@ TimeAggregator("time-aggr", cl::ZeroOrMore, cl::cat(AggregatorCategory)); -static cl::opt - UseEventPC("use-event-pc", - cl::desc("use event PC in combination with LBR sampling"), - cl::cat(AggregatorCategory)); - -static cl::opt WriteAutoFDOData( - "autofdo", cl::desc("generate autofdo textual data instead of bolt data"), - cl::cat(AggregatorCategory)); - } // namespace opts namespace { @@ -187,15 +178,13 @@ void DataAggregator::start() { /*Wait = */false); } else if (!opts::ITraceAggregation.empty()) { std::string ItracePerfScriptArgs = llvm::formatv( - "script -F pid,ip,brstack --itrace={0}", opts::ITraceAggregation); + "script -F pid,brstack --itrace={0}", opts::ITraceAggregation); launchPerfProcess("branch events with itrace", MainEventsPPI, ItracePerfScriptArgs.c_str(), /*Wait = */ false); } else { - launchPerfProcess("branch events", - MainEventsPPI, - "script -F pid,ip,brstack", - /*Wait = */false); + launchPerfProcess("branch events", MainEventsPPI, "script -F pid,brstack", + /*Wait = */ false); } // Note: we launch script for mem events regardless of the option, as the @@ -381,67 +370,6 @@ void DataAggregator::parsePreAggregated() { } } -std::error_code DataAggregator::writeAutoFDOData(StringRef OutputFilename) { - outs() << "PERF2BOLT: writing data for autofdo tools...\n"; - NamedRegionTimer T("writeAutoFDO", "Processing branch events", TimerGroupName, - TimerGroupDesc, opts::TimeAggregator); - - std::error_code EC; - raw_fd_ostream OutFile(OutputFilename, EC, sys::fs::OpenFlags::OF_None); - if (EC) - return EC; - - // Format: - // number of unique traces - // from_1-to_1:count_1 - // from_2-to_2:count_2 - // ...... - // from_n-to_n:count_n - // number of unique sample addresses - // addr_1:count_1 - // addr_2:count_2 - // ...... - // addr_n:count_n - // number of unique LBR entries - // src_1->dst_1:count_1 - // src_2->dst_2:count_2 - // ...... - // src_n->dst_n:count_n - - const uint64_t FirstAllocAddress = this->BC->FirstAllocAddress; - - // AutoFDO addresses are relative to the first allocated loadable program - // segment - auto filterAddress = [&FirstAllocAddress](uint64_t Address) -> uint64_t { - if (Address < FirstAllocAddress) - return 0; - return Address - FirstAllocAddress; - }; - - OutFile << FallthroughLBRs.size() << "\n"; - for (const auto &[Trace, Info] : FallthroughLBRs) { - OutFile << formatv("{0:x-}-{1:x-}:{2}\n", filterAddress(Trace.From), - filterAddress(Trace.To), - Info.InternCount + Info.ExternCount); - } - - OutFile << BasicSamples.size() << "\n"; - for (const auto [PC, HitCount] : BasicSamples) - OutFile << formatv("{0:x-}:{1}\n", filterAddress(PC), HitCount); - - OutFile << BranchLBRs.size() << "\n"; - for (const auto &[Trace, Info] : BranchLBRs) { - OutFile << formatv("{0:x-}->{1:x-}:{2}\n", filterAddress(Trace.From), - filterAddress(Trace.To), Info.TakenCount); - } - - outs() << "PERF2BOLT: wrote " << FallthroughLBRs.size() << " unique traces, " - << BasicSamples.size() << " sample addresses and " << BranchLBRs.size() - << " unique branches to " << OutputFilename << "\n"; - - return std::error_code(); -} - void DataAggregator::filterBinaryMMapInfo() { if (opts::FilterPID) { auto MMapInfoIter = BinaryMMapInfo.find(opts::FilterPID); @@ -583,15 +511,6 @@ Error DataAggregator::preprocessProfile(BinaryContext &BC) { (opts::BasicAggregation && parseBasicEvents())) errs() << "PERF2BOLT: failed to parse samples\n"; - // We can finish early if the goal is just to generate data for autofdo - if (opts::WriteAutoFDOData) { - if (std::error_code EC = writeAutoFDOData(opts::OutputFilename)) - errs() << "Error writing autofdo data to file: " << EC.message() << "\n"; - - deleteTempFiles(); - exit(0); - } - // Special handling for memory events if (prepareToParse("mem events", MemEventsPPI, MemEventsErrorCallback)) return Error::success(); @@ -1158,14 +1077,6 @@ ErrorOr DataAggregator::parseBranchSample() { return make_error_code(errc::no_such_process); } - while (checkAndConsumeFS()) { - } - - ErrorOr PCRes = parseHexField(FieldSeparator, true); - if (std::error_code EC = PCRes.getError()) - return EC; - Res.PC = PCRes.get(); - if (checkAndConsumeNewLine()) return Res; @@ -1472,9 +1383,9 @@ std::error_code DataAggregator::printLBRHeatMap() { uint64_t DataAggregator::parseLBRSample(const PerfBranchSample &Sample, bool NeedsSkylakeFix) { uint64_t NumTraces{0}; - // LBRs are stored in reverse execution order. NextPC refers to the next - // recorded executed PC. - uint64_t NextPC = opts::UseEventPC ? Sample.PC : 0; + // LBRs are stored in reverse execution order. NextLBR refers to the next + // executed branch record. + const LBREntry *NextLBR = nullptr; uint32_t NumEntry = 0; for (const LBREntry &LBR : Sample.LBR) { ++NumEntry; @@ -1486,10 +1397,10 @@ uint64_t DataAggregator::parseLBRSample(const PerfBranchSample &Sample, // chronological order) if (NeedsSkylakeFix && NumEntry <= 2) continue; - if (NextPC) { + if (NextLBR) { // Record fall-through trace. const uint64_t TraceFrom = LBR.To; - const uint64_t TraceTo = NextPC; + const uint64_t TraceTo = NextLBR->From; const BinaryFunction *TraceBF = getBinaryFunctionContainingAddress(TraceFrom); if (TraceBF && TraceBF->containsAddress(TraceTo)) { @@ -1524,7 +1435,7 @@ uint64_t DataAggregator::parseLBRSample(const PerfBranchSample &Sample, } ++NumTraces; } - NextPC = LBR.From; + NextLBR = &LBR; uint64_t From = getBinaryFunctionContainingAddress(LBR.From) ? LBR.From : 0; uint64_t To = getBinaryFunctionContainingAddress(LBR.To) ? LBR.To : 0; @@ -1561,8 +1472,6 @@ std::error_code DataAggregator::parseBranchEvents() { ++NumSamples; PerfBranchSample &Sample = SampleRes.get(); - if (opts::WriteAutoFDOData) - ++BasicSamples[Sample.PC]; if (Sample.LBR.empty()) { ++NumSamplesNoLBR; diff --git a/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp b/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp index 30bc8be1719d5..aeb7fe90f2175 100644 --- a/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp +++ b/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp @@ -118,6 +118,29 @@ findMembersUsedInInitExpr(const CXXCtorInitializer *Initializer, return Results; } +/// Returns the start of the leading comments before `Loc`. +static SourceLocation getStartOfLeadingComment(SourceLocation Loc, + const SourceManager &SM, + const LangOptions &LangOpts) { + // We consider any leading comment token that is on the same line or + // indented similarly to the first comment to be part of the leading comment. + const unsigned Line = SM.getPresumedLineNumber(Loc); + const unsigned Column = SM.getPresumedColumnNumber(Loc); + std::optional Tok = + Lexer::findPreviousToken(Loc, SM, LangOpts, /*IncludeComments=*/true); + while (Tok && Tok->is(tok::comment)) { + const SourceLocation CommentLoc = + Lexer::GetBeginningOfToken(Tok->getLocation(), SM, LangOpts); + if (SM.getPresumedLineNumber(CommentLoc) != Line && + SM.getPresumedColumnNumber(CommentLoc) != Column) { + break; + } + Loc = CommentLoc; + Tok = Lexer::findPreviousToken(Loc, SM, LangOpts, /*IncludeComments=*/true); + } + return Loc; +} + /// Returns the end of the trailing comments after `Loc`. static SourceLocation getEndOfTrailingComment(SourceLocation Loc, const SourceManager &SM, @@ -159,6 +182,7 @@ static SourceRange getFullFieldSourceRange(const FieldDecl &Field, if (CurrentToken->is(tok::semi)) break; } + Begin = getStartOfLeadingComment(Begin, SM, LangOpts); End = getEndOfTrailingComment(End, SM, LangOpts); return SourceRange(Begin, End); } diff --git a/clang-tools-extra/clang-tidy/utils/LexerUtils.cpp b/clang-tools-extra/clang-tidy/utils/LexerUtils.cpp index 50da196315d3b..c14d341caf779 100644 --- a/clang-tools-extra/clang-tidy/utils/LexerUtils.cpp +++ b/clang-tools-extra/clang-tidy/utils/LexerUtils.cpp @@ -17,25 +17,16 @@ namespace clang::tidy::utils::lexer { std::pair getPreviousTokenAndStart(SourceLocation Location, const SourceManager &SM, const LangOptions &LangOpts, bool SkipComments) { - Token Token; - Token.setKind(tok::unknown); + const std::optional Tok = + Lexer::findPreviousToken(Location, SM, LangOpts, !SkipComments); - Location = Location.getLocWithOffset(-1); - if (Location.isInvalid()) - return {Token, Location}; - - const auto StartOfFile = SM.getLocForStartOfFile(SM.getFileID(Location)); - while (Location != StartOfFile) { - Location = Lexer::GetBeginningOfToken(Location, SM, LangOpts); - if (!Lexer::getRawToken(Location, Token, SM, LangOpts) && - (!SkipComments || !Token.is(tok::comment))) { - break; - } - if (Location == StartOfFile) - return {Token, Location}; - Location = Location.getLocWithOffset(-1); + if (Tok.has_value()) { + return {*Tok, Lexer::GetBeginningOfToken(Tok->getLocation(), SM, LangOpts)}; } - return {Token, Location}; + + Token Token; + Token.setKind(tok::unknown); + return {Token, SourceLocation()}; } Token getPreviousToken(SourceLocation Location, const SourceManager &SM, diff --git a/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp b/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp index 71e97ac4efd67..2b1da4be5c1bd 100644 --- a/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp +++ b/clang-tools-extra/clangd/GlobalCompilationDatabase.cpp @@ -830,6 +830,16 @@ bool OverlayCDB::setCompileCommand(PathRef File, return true; } +std::unique_ptr +OverlayCDB::getProjectModules(PathRef File) const { + auto MDB = DelegatingCDB::getProjectModules(File); + MDB->setCommandMangler([&Mangler = Mangler](tooling::CompileCommand &Command, + PathRef CommandPath) { + Mangler(Command, CommandPath); + }); + return std::move(MDB); +} + DelegatingCDB::DelegatingCDB(const GlobalCompilationDatabase *Base) : Base(Base) { if (Base) diff --git a/clang-tools-extra/clangd/GlobalCompilationDatabase.h b/clang-tools-extra/clangd/GlobalCompilationDatabase.h index f8349c6efecb0..1d636d73664be 100644 --- a/clang-tools-extra/clangd/GlobalCompilationDatabase.h +++ b/clang-tools-extra/clangd/GlobalCompilationDatabase.h @@ -209,6 +209,9 @@ class OverlayCDB : public DelegatingCDB { setCompileCommand(PathRef File, std::optional CompilationCommand); + std::unique_ptr + getProjectModules(PathRef File) const override; + private: mutable std::mutex Mutex; llvm::StringMap Commands; /* GUARDED_BY(Mut) */ diff --git a/clang-tools-extra/clangd/Hover.cpp b/clang-tools-extra/clangd/Hover.cpp index 5e136d0e76ece..3ab3d89030520 100644 --- a/clang-tools-extra/clangd/Hover.cpp +++ b/clang-tools-extra/clangd/Hover.cpp @@ -1193,12 +1193,13 @@ void maybeAddSymbolProviders(ParsedAST &AST, HoverInfo &HI, include_cleaner::Symbol Sym) { trace::Span Tracer("Hover::maybeAddSymbolProviders"); - const SourceManager &SM = AST.getSourceManager(); llvm::SmallVector RankedProviders = - include_cleaner::headersForSymbol(Sym, SM, &AST.getPragmaIncludes()); + include_cleaner::headersForSymbol(Sym, AST.getPreprocessor(), + &AST.getPragmaIncludes()); if (RankedProviders.empty()) return; + const SourceManager &SM = AST.getSourceManager(); std::string Result; include_cleaner::Includes ConvertedIncludes = convertIncludes(AST); for (const auto &P : RankedProviders) { diff --git a/clang-tools-extra/clangd/ProjectModules.h b/clang-tools-extra/clangd/ProjectModules.h index 3b9b564a87da0..48d52ac9deb89 100644 --- a/clang-tools-extra/clangd/ProjectModules.h +++ b/clang-tools-extra/clangd/ProjectModules.h @@ -9,8 +9,10 @@ #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_PROJECTMODULES_H #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_PROJECTMODULES_H +#include "support/Function.h" #include "support/Path.h" #include "support/ThreadsafeFS.h" +#include "clang/Tooling/CompilationDatabase.h" #include @@ -36,11 +38,16 @@ namespace clangd { /// `[:partition-name]`. So module names covers partitions. class ProjectModules { public: + using CommandMangler = + llvm::unique_function; + virtual std::vector getRequiredModules(PathRef File) = 0; virtual PathRef getSourceForModuleName(llvm::StringRef ModuleName, PathRef RequiredSrcFile = PathRef()) = 0; + virtual void setCommandMangler(CommandMangler Mangler) {} + virtual ~ProjectModules() = default; }; diff --git a/clang-tools-extra/clangd/ScanningProjectModules.cpp b/clang-tools-extra/clangd/ScanningProjectModules.cpp index 92f75ef7d5c25..e4dc11c1c2895 100644 --- a/clang-tools-extra/clangd/ScanningProjectModules.cpp +++ b/clang-tools-extra/clangd/ScanningProjectModules.cpp @@ -48,7 +48,8 @@ class ModuleDependencyScanner { }; /// Scanning the single file specified by \param FilePath. - std::optional scan(PathRef FilePath); + std::optional + scan(PathRef FilePath, const ProjectModules::CommandMangler &Mangler); /// Scanning every source file in the current project to get the /// to map. @@ -57,7 +58,7 @@ class ModuleDependencyScanner { /// a global module dependency scanner to monitor every file. Or we /// can simply require the build systems (or even the end users) /// to provide the map. - void globalScan(); + void globalScan(const ProjectModules::CommandMangler &Mangler); /// Get the source file from the module name. Note that the language /// guarantees all the module names are unique in a valid program. @@ -69,7 +70,9 @@ class ModuleDependencyScanner { /// Return the direct required modules. Indirect required modules are not /// included. - std::vector getRequiredModules(PathRef File); + std::vector + getRequiredModules(PathRef File, + const ProjectModules::CommandMangler &Mangler); private: std::shared_ptr CDB; @@ -87,7 +90,8 @@ class ModuleDependencyScanner { }; std::optional -ModuleDependencyScanner::scan(PathRef FilePath) { +ModuleDependencyScanner::scan(PathRef FilePath, + const ProjectModules::CommandMangler &Mangler) { auto Candidates = CDB->getCompileCommands(FilePath); if (Candidates.empty()) return std::nullopt; @@ -97,10 +101,8 @@ ModuleDependencyScanner::scan(PathRef FilePath) { // DirectoryBasedGlobalCompilationDatabase::getCompileCommand. tooling::CompileCommand Cmd = std::move(Candidates.front()); - static int StaticForMainAddr; // Just an address in this process. - Cmd.CommandLine.push_back("-resource-dir=" + - CompilerInvocation::GetResourcesPath( - "clangd", (void *)&StaticForMainAddr)); + if (Mangler) + Mangler(Cmd, FilePath); using namespace clang::tooling::dependencies; @@ -130,9 +132,10 @@ ModuleDependencyScanner::scan(PathRef FilePath) { return Result; } -void ModuleDependencyScanner::globalScan() { +void ModuleDependencyScanner::globalScan( + const ProjectModules::CommandMangler &Mangler) { for (auto &File : CDB->getAllFiles()) - scan(File); + scan(File, Mangler); GlobalScanned = true; } @@ -150,9 +153,9 @@ PathRef ModuleDependencyScanner::getSourceForModuleName( return {}; } -std::vector -ModuleDependencyScanner::getRequiredModules(PathRef File) { - auto ScanningResult = scan(File); +std::vector ModuleDependencyScanner::getRequiredModules( + PathRef File, const ProjectModules::CommandMangler &Mangler) { + auto ScanningResult = scan(File, Mangler); if (!ScanningResult) return {}; @@ -177,7 +180,11 @@ class ScanningAllProjectModules : public ProjectModules { ~ScanningAllProjectModules() override = default; std::vector getRequiredModules(PathRef File) override { - return Scanner.getRequiredModules(File); + return Scanner.getRequiredModules(File, Mangler); + } + + void setCommandMangler(CommandMangler Mangler) override { + this->Mangler = std::move(Mangler); } /// RequiredSourceFile is not used intentionally. See the comments of @@ -185,12 +192,13 @@ class ScanningAllProjectModules : public ProjectModules { PathRef getSourceForModuleName(llvm::StringRef ModuleName, PathRef RequiredSourceFile = PathRef()) override { - Scanner.globalScan(); + Scanner.globalScan(Mangler); return Scanner.getSourceForModuleName(ModuleName); } private: ModuleDependencyScanner Scanner; + CommandMangler Mangler; }; std::unique_ptr scanningProjectModules( diff --git a/clang-tools-extra/clangd/index/SymbolCollector.cpp b/clang-tools-extra/clangd/index/SymbolCollector.cpp index 6d0af20e31260..1de7faf81746e 100644 --- a/clang-tools-extra/clangd/index/SymbolCollector.cpp +++ b/clang-tools-extra/clangd/index/SymbolCollector.cpp @@ -888,7 +888,7 @@ void SymbolCollector::setIncludeLocation(const Symbol &S, SourceLocation DefLoc, // might run while parsing, rather than at the end of a translation unit. // Hence we see more and more redecls over time. SymbolProviders[S.ID] = - include_cleaner::headersForSymbol(Sym, SM, Opts.PragmaIncludes); + include_cleaner::headersForSymbol(Sym, *PP, Opts.PragmaIncludes); } llvm::StringRef getStdHeader(const Symbol *S, const LangOptions &LangOpts) { diff --git a/clang-tools-extra/clangd/unittests/PrerequisiteModulesTest.cpp b/clang-tools-extra/clangd/unittests/PrerequisiteModulesTest.cpp index 1bb8e19cce23e..51723c797eabc 100644 --- a/clang-tools-extra/clangd/unittests/PrerequisiteModulesTest.cpp +++ b/clang-tools-extra/clangd/unittests/PrerequisiteModulesTest.cpp @@ -11,13 +11,14 @@ /// code mode. #ifndef _WIN32 -#include "ModulesBuilder.h" -#include "ScanningProjectModules.h" #include "Annotations.h" #include "CodeComplete.h" #include "Compiler.h" +#include "ModulesBuilder.h" +#include "ScanningProjectModules.h" #include "TestTU.h" #include "support/ThreadsafeFS.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/raw_ostream.h" #include "gmock/gmock.h" @@ -191,6 +192,41 @@ export module M; EXPECT_TRUE(MInfo->canReuse(*Invocation, FS.view(TestDir))); } +TEST_F(PrerequisiteModulesTests, ModuleWithArgumentPatch) { + MockDirectoryCompilationDatabase CDB(TestDir, FS); + + CDB.ExtraClangFlags.push_back("-invalid-unknown-flag"); + + CDB.addFile("Dep.cppm", R"cpp( +export module Dep; + )cpp"); + + CDB.addFile("M.cppm", R"cpp( +export module M; +import Dep; + )cpp"); + + // An invalid flag will break the module compilation and the + // getRequiredModules would return an empty array + auto ProjectModules = CDB.getProjectModules(getFullPath("M.cppm")); + EXPECT_TRUE( + ProjectModules->getRequiredModules(getFullPath("M.cppm")).empty()); + + // Set the mangler to filter out the invalid flag + ProjectModules->setCommandMangler( + [](tooling::CompileCommand &Command, PathRef) { + auto const It = + std::find(Command.CommandLine.begin(), Command.CommandLine.end(), + "-invalid-unknown-flag"); + Command.CommandLine.erase(It); + }); + + // And now it returns a non-empty list of required modules since the + // compilation succeeded + EXPECT_FALSE( + ProjectModules->getRequiredModules(getFullPath("M.cppm")).empty()); +} + TEST_F(PrerequisiteModulesTests, ModuleWithDepTest) { MockDirectoryCompilationDatabase CDB(TestDir, FS); @@ -435,7 +471,7 @@ void func() { /*Callback=*/nullptr); EXPECT_TRUE(Preamble); EXPECT_TRUE(Preamble->RequiredModules); - + auto Result = codeComplete(getFullPath("Use.cpp"), Test.point(), Preamble.get(), Use, {}); EXPECT_FALSE(Result.Completions.empty()); @@ -474,7 +510,7 @@ void func() { /*Callback=*/nullptr); EXPECT_TRUE(Preamble); EXPECT_TRUE(Preamble->RequiredModules); - + auto Result = signatureHelp(getFullPath("Use.cpp"), Test.point(), *Preamble.get(), Use, MarkupKind::PlainText); EXPECT_FALSE(Result.signatures.empty()); diff --git a/clang-tools-extra/include-cleaner/include/clang-include-cleaner/Analysis.h b/clang-tools-extra/include-cleaner/include/clang-include-cleaner/Analysis.h index 46ca3c9d08074..c3241763237d1 100644 --- a/clang-tools-extra/include-cleaner/include/clang-include-cleaner/Analysis.h +++ b/clang-tools-extra/include-cleaner/include/clang-include-cleaner/Analysis.h @@ -90,7 +90,7 @@ std::string fixIncludes(const AnalysisResults &Results, /// Returned headers are sorted by relevance, first element is the most /// likely provider for the symbol. llvm::SmallVector
headersForSymbol(const Symbol &S, - const SourceManager &SM, + const Preprocessor &PP, const PragmaIncludes *PI); } // namespace include_cleaner } // namespace clang diff --git a/clang-tools-extra/include-cleaner/lib/Analysis.cpp b/clang-tools-extra/include-cleaner/lib/Analysis.cpp index e3a4834cb19ae..a1781f4e24f2e 100644 --- a/clang-tools-extra/include-cleaner/lib/Analysis.cpp +++ b/clang-tools-extra/include-cleaner/lib/Analysis.cpp @@ -64,7 +64,7 @@ void walkUsed(llvm::ArrayRef ASTRoots, // FIXME: Most of the work done here is repetitive. It might be useful to // have a cache/batching. SymbolReference SymRef{ND, Loc, RT}; - return CB(SymRef, headersForSymbol(ND, SM, PI)); + return CB(SymRef, headersForSymbol(ND, PP, PI)); }); } for (const SymbolReference &MacroRef : MacroRefs) { @@ -72,7 +72,7 @@ void walkUsed(llvm::ArrayRef ASTRoots, if (!SM.isWrittenInMainFile(SM.getSpellingLoc(MacroRef.RefLocation)) || shouldIgnoreMacroReference(PP, MacroRef.Target.macro())) continue; - CB(MacroRef, headersForSymbol(MacroRef.Target, SM, PI)); + CB(MacroRef, headersForSymbol(MacroRef.Target, PP, PI)); } } diff --git a/clang-tools-extra/include-cleaner/lib/AnalysisInternal.h b/clang-tools-extra/include-cleaner/lib/AnalysisInternal.h index cd796c2da7b80..7d170fd15014d 100644 --- a/clang-tools-extra/include-cleaner/lib/AnalysisInternal.h +++ b/clang-tools-extra/include-cleaner/lib/AnalysisInternal.h @@ -25,6 +25,8 @@ #include "clang-include-cleaner/Analysis.h" #include "clang-include-cleaner/Record.h" #include "clang-include-cleaner/Types.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Lex/Preprocessor.h" #include "llvm/ADT/STLFunctionalExtras.h" #include @@ -57,13 +59,14 @@ llvm::SmallVector> findHeaders(const SymbolLocation &Loc, const PragmaIncludes *PI); /// A set of locations that provides the declaration. -std::vector> locateSymbol(const Symbol &S); +std::vector> locateSymbol(const Symbol &S, + const LangOptions &LO); /// Write an HTML summary of the analysis to the given stream. void writeHTMLReport(FileID File, const Includes &, llvm::ArrayRef Roots, llvm::ArrayRef MacroRefs, ASTContext &Ctx, - const HeaderSearch &HS, PragmaIncludes *PI, + const Preprocessor &PP, PragmaIncludes *PI, llvm::raw_ostream &OS); } // namespace include_cleaner diff --git a/clang-tools-extra/include-cleaner/lib/FindHeaders.cpp b/clang-tools-extra/include-cleaner/lib/FindHeaders.cpp index 7b28d1c252d71..b96d9a70728c2 100644 --- a/clang-tools-extra/include-cleaner/lib/FindHeaders.cpp +++ b/clang-tools-extra/include-cleaner/lib/FindHeaders.cpp @@ -18,6 +18,7 @@ #include "clang/Basic/FileEntry.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/SourceManager.h" +#include "clang/Lex/Preprocessor.h" #include "clang/Tooling/Inclusions/StandardLibrary.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/STLExtras.h" @@ -239,8 +240,9 @@ llvm::SmallVector> findHeaders(const SymbolLocation &Loc, } llvm::SmallVector
headersForSymbol(const Symbol &S, - const SourceManager &SM, + const Preprocessor &PP, const PragmaIncludes *PI) { + const auto &SM = PP.getSourceManager(); // Get headers for all the locations providing Symbol. Same header can be // reached through different traversals, deduplicate those into a single // Header by merging their hints. @@ -248,7 +250,7 @@ llvm::SmallVector
headersForSymbol(const Symbol &S, if (auto SpecialHeaders = headersForSpecialSymbol(S, SM, PI)) { Headers = std::move(*SpecialHeaders); } else { - for (auto &Loc : locateSymbol(S)) + for (auto &Loc : locateSymbol(S, PP.getLangOpts())) Headers.append(applyHints(findHeaders(Loc, SM, PI), Loc.Hint)); } // If two Headers probably refer to the same file (e.g. Verbatim(foo.h) and diff --git a/clang-tools-extra/include-cleaner/lib/HTMLReport.cpp b/clang-tools-extra/include-cleaner/lib/HTMLReport.cpp index bbe8bc230c6e2..92c7c554ca50c 100644 --- a/clang-tools-extra/include-cleaner/lib/HTMLReport.cpp +++ b/clang-tools-extra/include-cleaner/lib/HTMLReport.cpp @@ -21,6 +21,7 @@ #include "clang/Basic/SourceManager.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/Lexer.h" +#include "clang/Lex/Preprocessor.h" #include "clang/Tooling/Inclusions/StandardLibrary.h" #include "llvm/Support/ScopedPrinter.h" #include "llvm/Support/raw_ostream.h" @@ -135,7 +136,7 @@ class Reporter { llvm::raw_ostream &OS; const ASTContext &Ctx; const SourceManager &SM; - const HeaderSearch &HS; + const Preprocessor &PP; const include_cleaner::Includes &Includes; const PragmaIncludes *PI; FileID MainFile; @@ -170,9 +171,9 @@ class Reporter { void fillTarget(Ref &R) { // Duplicates logic from walkUsed(), which doesn't expose SymbolLocations. - for (auto &Loc : locateSymbol(R.Sym)) + for (auto &Loc : locateSymbol(R.Sym, Ctx.getLangOpts())) R.Locations.push_back(Loc); - R.Headers = headersForSymbol(R.Sym, SM, PI); + R.Headers = headersForSymbol(R.Sym, PP, PI); for (const auto &H : R.Headers) { R.Includes.append(Includes.match(H)); @@ -189,14 +190,15 @@ class Reporter { R.Includes.end()); if (!R.Headers.empty()) - R.Insert = spellHeader({R.Headers.front(), HS, MainFE}); + R.Insert = + spellHeader({R.Headers.front(), PP.getHeaderSearchInfo(), MainFE}); } public: - Reporter(llvm::raw_ostream &OS, ASTContext &Ctx, const HeaderSearch &HS, + Reporter(llvm::raw_ostream &OS, ASTContext &Ctx, const Preprocessor &PP, const include_cleaner::Includes &Includes, const PragmaIncludes *PI, FileID MainFile) - : OS(OS), Ctx(Ctx), SM(Ctx.getSourceManager()), HS(HS), + : OS(OS), Ctx(Ctx), SM(Ctx.getSourceManager()), PP(PP), Includes(Includes), PI(PI), MainFile(MainFile), MainFE(SM.getFileEntryForID(MainFile)) {} @@ -498,9 +500,9 @@ class Reporter { void writeHTMLReport(FileID File, const include_cleaner::Includes &Includes, llvm::ArrayRef Roots, llvm::ArrayRef MacroRefs, ASTContext &Ctx, - const HeaderSearch &HS, PragmaIncludes *PI, + const Preprocessor &PP, PragmaIncludes *PI, llvm::raw_ostream &OS) { - Reporter R(OS, Ctx, HS, Includes, PI, File); + Reporter R(OS, Ctx, PP, Includes, PI, File); const auto& SM = Ctx.getSourceManager(); for (Decl *Root : Roots) walkAST(*Root, [&](SourceLocation Loc, const NamedDecl &D, RefType T) { diff --git a/clang-tools-extra/include-cleaner/lib/LocateSymbol.cpp b/clang-tools-extra/include-cleaner/lib/LocateSymbol.cpp index 78e783a62eb27..b7433305152f9 100644 --- a/clang-tools-extra/include-cleaner/lib/LocateSymbol.cpp +++ b/clang-tools-extra/include-cleaner/lib/LocateSymbol.cpp @@ -54,20 +54,24 @@ std::vector> locateDecl(const Decl &D) { return Result; } -std::vector> locateMacro(const Macro &M) { +std::vector> locateMacro(const Macro &M, + const tooling::stdlib::Lang L) { // FIXME: Should we also provide physical locations? - if (auto SS = tooling::stdlib::Symbol::named("", M.Name->getName())) + if (auto SS = tooling::stdlib::Symbol::named("", M.Name->getName(), L)) return {{*SS, Hints::CompleteSymbol}}; return {{M.Definition, Hints::CompleteSymbol}}; } } // namespace -std::vector> locateSymbol(const Symbol &S) { +std::vector> locateSymbol(const Symbol &S, + const LangOptions &LO) { + const auto L = !LO.CPlusPlus && LO.C99 ? tooling::stdlib::Lang::C + : tooling::stdlib::Lang::CXX; switch (S.kind()) { case Symbol::Declaration: return locateDecl(S.declaration()); case Symbol::Macro: - return locateMacro(S.macro()); + return locateMacro(S.macro(), L); } llvm_unreachable("Unknown Symbol::Kind enum"); } diff --git a/clang-tools-extra/include-cleaner/tool/IncludeCleaner.cpp b/clang-tools-extra/include-cleaner/tool/IncludeCleaner.cpp index f85dbc0e0c31f..1d9458ffc4d32 100644 --- a/clang-tools-extra/include-cleaner/tool/IncludeCleaner.cpp +++ b/clang-tools-extra/include-cleaner/tool/IncludeCleaner.cpp @@ -216,10 +216,9 @@ class Action : public clang::ASTFrontendAction { ++Errors; return; } - writeHTMLReport( - AST.Ctx->getSourceManager().getMainFileID(), PP.Includes, AST.Roots, - PP.MacroReferences, *AST.Ctx, - getCompilerInstance().getPreprocessor().getHeaderSearchInfo(), &PI, OS); + writeHTMLReport(AST.Ctx->getSourceManager().getMainFileID(), PP.Includes, + AST.Roots, PP.MacroReferences, *AST.Ctx, + getCompilerInstance().getPreprocessor(), &PI, OS); } }; class ActionFactory : public tooling::FrontendActionFactory { diff --git a/clang-tools-extra/include-cleaner/unittests/FindHeadersTest.cpp b/clang-tools-extra/include-cleaner/unittests/FindHeadersTest.cpp index 84e02e1d0d621..0ac243937e6e4 100644 --- a/clang-tools-extra/include-cleaner/unittests/FindHeadersTest.cpp +++ b/clang-tools-extra/include-cleaner/unittests/FindHeadersTest.cpp @@ -306,7 +306,7 @@ class HeadersForSymbolTest : public FindHeadersTest { if (!V.Out) ADD_FAILURE() << "Couldn't find any decls named " << Name << "."; assert(V.Out); - return headersForSymbol(*V.Out, AST->sourceManager(), &PI); + return headersForSymbol(*V.Out, AST->preprocessor(), &PI); } llvm::SmallVector
headersForFoo() { return headersFor("foo"); } }; @@ -611,13 +611,12 @@ TEST_F(HeadersForSymbolTest, AmbiguousStdSymbolsUsingShadow) { Visitor V; V.TraverseDecl(AST->context().getTranslationUnitDecl()); ASSERT_TRUE(V.Out) << "Couldn't find a DeclRefExpr!"; - EXPECT_THAT(headersForSymbol(*(V.Out->getFoundDecl()), - AST->sourceManager(), &PI), - UnorderedElementsAre( - Header(*tooling::stdlib::Header::named("")))); + EXPECT_THAT( + headersForSymbol(*(V.Out->getFoundDecl()), AST->preprocessor(), &PI), + UnorderedElementsAre( + Header(*tooling::stdlib::Header::named("")))); } - TEST_F(HeadersForSymbolTest, StandardHeaders) { Inputs.Code = R"cpp( #include "stdlib_internal.h" @@ -636,6 +635,30 @@ TEST_F(HeadersForSymbolTest, StandardHeaders) { tooling::stdlib::Header::named(""))); } +TEST_F(HeadersForSymbolTest, StdlibLangForMacros) { + Inputs.Code = R"cpp( + #define EOF 0 + void foo() { EOF; } + )cpp"; + { + buildAST(); + const Macro Eof{AST->preprocessor().getIdentifierInfo("EOF"), {}}; + EXPECT_THAT( + headersForSymbol(Eof, AST->preprocessor(), nullptr), + UnorderedElementsAre(tooling::stdlib::Header::named(""), + tooling::stdlib::Header::named(""))); + } + + { + Inputs.ExtraArgs.push_back("-xc"); + buildAST(); + const Macro Eof{AST->preprocessor().getIdentifierInfo("EOF"), {}}; + EXPECT_THAT(headersForSymbol(Eof, AST->preprocessor(), nullptr), + UnorderedElementsAre(tooling::stdlib::Header::named( + "", tooling::stdlib::Lang::C))); + } +} + TEST_F(HeadersForSymbolTest, ExporterNoNameMatch) { Inputs.Code = R"cpp( #include "exporter/foo.h" diff --git a/clang-tools-extra/include-cleaner/unittests/LocateSymbolTest.cpp b/clang-tools-extra/include-cleaner/unittests/LocateSymbolTest.cpp index 756757cfd0f09..1e7baf142a75a 100644 --- a/clang-tools-extra/include-cleaner/unittests/LocateSymbolTest.cpp +++ b/clang-tools-extra/include-cleaner/unittests/LocateSymbolTest.cpp @@ -11,6 +11,7 @@ #include "clang/AST/Decl.h" #include "clang/AST/DeclBase.h" #include "clang/AST/RecursiveASTVisitor.h" +#include "clang/Basic/LangOptions.h" #include "clang/Basic/SourceLocation.h" #include "clang/Lex/Preprocessor.h" #include "clang/Testing/TestAST.h" @@ -96,6 +97,8 @@ struct LocateExample { Results.emplace_back(SM.getComposedLoc(FID, Offset)); return Results; } + + const LangOptions &langOpts() { return AST.preprocessor().getLangOpts(); } }; TEST(LocateSymbol, Decl) { @@ -110,7 +113,7 @@ TEST(LocateSymbol, Decl) { for (auto &Case : Cases) { SCOPED_TRACE(Case); LocateExample Test(Case); - EXPECT_THAT(locateSymbol(Test.findDecl("foo")), + EXPECT_THAT(locateSymbol(Test.findDecl("foo"), Test.langOpts()), ElementsAreArray(Test.points())); } } @@ -119,12 +122,12 @@ TEST(LocateSymbol, Stdlib) { { LocateExample Test("namespace std { struct vector; }"); EXPECT_THAT( - locateSymbol(Test.findDecl("vector")), + locateSymbol(Test.findDecl("vector"), Test.langOpts()), ElementsAre(*tooling::stdlib::Symbol::named("std::", "vector"))); } { LocateExample Test("#define assert(x)\nvoid foo() { assert(true); }"); - EXPECT_THAT(locateSymbol(Test.findMacro("assert")), + EXPECT_THAT(locateSymbol(Test.findMacro("assert"), Test.langOpts()), ElementsAre(*tooling::stdlib::Symbol::named("", "assert"))); } } @@ -132,7 +135,7 @@ TEST(LocateSymbol, Stdlib) { TEST(LocateSymbol, Macros) { // Make sure we preserve the last one. LocateExample Test("#define FOO\n#undef FOO\n#define ^FOO"); - EXPECT_THAT(locateSymbol(Test.findMacro("FOO")), + EXPECT_THAT(locateSymbol(Test.findMacro("FOO"), Test.langOpts()), ElementsAreArray(Test.points())); } @@ -143,7 +146,7 @@ TEST(LocateSymbol, CompleteSymbolHint) { { // stdlib symbols are always complete. LocateExample Test("namespace std { struct vector; }"); - EXPECT_THAT(locateSymbol(Test.findDecl("vector")), + EXPECT_THAT(locateSymbol(Test.findDecl("vector"), Test.langOpts()), ElementsAre(HintedSymbol( *tooling::stdlib::Symbol::named("std::", "vector"), Hints::CompleteSymbol))); @@ -151,7 +154,7 @@ TEST(LocateSymbol, CompleteSymbolHint) { { // macros are always complete. LocateExample Test("#define ^FOO"); - EXPECT_THAT(locateSymbol(Test.findMacro("FOO")), + EXPECT_THAT(locateSymbol(Test.findMacro("FOO"), Test.langOpts()), ElementsAre(HintedSymbol(Test.points().front(), Hints::CompleteSymbol))); } @@ -165,7 +168,7 @@ TEST(LocateSymbol, CompleteSymbolHint) { for (auto &Case : Cases) { SCOPED_TRACE(Case); LocateExample Test(Case); - EXPECT_THAT(locateSymbol(Test.findDecl("foo")), + EXPECT_THAT(locateSymbol(Test.findDecl("foo"), Test.langOpts()), ElementsAre(HintedSymbol(Test.points().front(), Hints::None), HintedSymbol(Test.points().back(), Hints::CompleteSymbol))); @@ -181,7 +184,7 @@ TEST(LocateSymbol, CompleteSymbolHint) { for (auto &Case : Cases) { SCOPED_TRACE(Case); LocateExample Test(Case); - EXPECT_THAT(locateSymbol(Test.findDecl("foo")), + EXPECT_THAT(locateSymbol(Test.findDecl("foo"), Test.langOpts()), Each(Field(&Hinted::Hint, Eq(Hints::CompleteSymbol)))); } diff --git a/clang-tools-extra/test/clang-reorder-fields/Comments.cpp b/clang-tools-extra/test/clang-reorder-fields/Comments.cpp index a31b6692c9ac7..8a81fbfc09313 100644 --- a/clang-tools-extra/test/clang-reorder-fields/Comments.cpp +++ b/clang-tools-extra/test/clang-reorder-fields/Comments.cpp @@ -1,4 +1,4 @@ -// RUN: clang-reorder-fields -record-name Foo -fields-order e1,e3,e2,a,c,b %s -- | FileCheck %s +// RUN: clang-reorder-fields -record-name Foo -fields-order c,e1,e3,e2,a,b %s -- | FileCheck %s class Foo { int a; // Trailing comment for a. @@ -12,12 +12,15 @@ class Foo { int e3 /*c-like*/; }; -// CHECK: /*c-like*/ int e1; +// Note: the position of the empty line is somewhat arbitrary. + +// CHECK: // Prefix comments for c. +// CHECK-NEXT: int c; +// CHECK-NEXT: /*c-like*/ int e1; // CHECK-NEXT: int e3 /*c-like*/; +// CHECK-EMPTY: // CHECK-NEXT: int /*c-like*/ e2; // CHECK-NEXT: int a; // Trailing comment for a. -// CHECK-NEXT: // Prefix comments for c. -// CHECK-NEXT: int c; // CHECK-NEXT: int b; // Multiline // CHECK-NEXT: // trailing for b. diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst index 511a967f66d10..30a2325949f48 100644 --- a/clang/docs/ClangFormatStyleOptions.rst +++ b/clang/docs/ClangFormatStyleOptions.rst @@ -3946,21 +3946,6 @@ the configuration (without a prefix: ``Auto``). This is an experimental flag, that might go away or be renamed. Do not use this in config files, etc. Use at your own risk. -.. _ExportBlockIndentation: - -**ExportBlockIndentation** (``Boolean``) :versionbadge:`clang-format 20` :ref:`¶ ` - If ``true``, clang-format will indent the body of an ``export { ... }`` - block. This doesn't affect the formatting of anything else related to - exported declarations. - - .. code-block:: c++ - - true: false: - export { vs. export { - void foo(); void foo(); - void bar(); void bar(); - } } - .. _FixNamespaceComments: **FixNamespaceComments** (``Boolean``) :versionbadge:`clang-format 5` :ref:`¶ ` @@ -4228,6 +4213,21 @@ the configuration (without a prefix: ``Auto``). plop(); plop(); } } +.. _IndentExportBlock: + +**IndentExportBlock** (``Boolean``) :versionbadge:`clang-format 20` :ref:`¶ ` + If ``true``, clang-format will indent the body of an ``export { ... }`` + block. This doesn't affect the formatting of anything else related to + exported declarations. + + .. code-block:: c++ + + true: false: + export { vs. export { + void foo(); void foo(); + void bar(); void bar(); + } } + .. _IndentExternBlock: **IndentExternBlock** (``IndentExternBlockStyle``) :versionbadge:`clang-format 11` :ref:`¶ ` diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst index bbeeefe82282b..c42b88015e269 100644 --- a/clang/docs/LanguageExtensions.rst +++ b/clang/docs/LanguageExtensions.rst @@ -5656,7 +5656,7 @@ The ``#pragma clang section`` directive obeys the following rules: * The pragma clang section is enabled automatically, without need of any flags. -* This feature is only defined to work sensibly for ELF and Mach-O targets. +* This feature is only defined to work sensibly for ELF, Mach-O and COFF targets. * If section name is specified through _attribute_((section("myname"))), then the attribute name gains precedence. diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index f75c726e2751c..cad17c1b3957b 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -318,6 +318,8 @@ C++23 Feature Support - ``__cpp_explicit_this_parameter`` is now defined. (#GH82780) +- Add support for `P2280R4 Using unknown pointers and references in constant expressions `_. (#GH63139) + C++20 Feature Support ^^^^^^^^^^^^^^^^^^^^^ @@ -800,6 +802,8 @@ Improvements to Clang's diagnostics - Fix false positives warning for non-std functions with name `infinity` (#123231). +- Clang now emits a ``-Wignored-qualifiers`` diagnostic when a base class includes cv-qualifiers (#GH55474). + Improvements to Clang's time-trace ---------------------------------- @@ -966,7 +970,7 @@ Bug Fixes to C++ Support constraints are applied. (#GH122134) - Fixed canonicalization of pack indexing types - Clang did not always recognized identical pack indexing. (#GH123033) - Fixed a nested lambda substitution issue for constraint evaluation. (#GH123441) - +- Fixed various false diagnostics related to the use of immediate functions. (#GH123472) Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1122,6 +1126,8 @@ Windows Support When `-fms-compatibility-version=18.00` or prior is set on the command line this Microsoft extension is still allowed as VS2013 and prior allow it. +- Clang now supports the ``#pragma clang section`` directive for COFF targets. + LoongArch Support ^^^^^^^^^^^^^^^^^ @@ -1235,7 +1241,7 @@ clang-format - Adds ``VariableTemplates`` option. - Adds support for bash globstar in ``.clang-format-ignore``. - Adds ``WrapNamespaceBodyWithEmptyLines`` option. -- Adds the ``ExportBlockIndentation`` option. +- Adds the ``IndentExportBlock`` option. libclang -------- diff --git a/clang/include/clang/AST/APValue.h b/clang/include/clang/AST/APValue.h index 4401f3a8ff482..833a78c77871d 100644 --- a/clang/include/clang/AST/APValue.h +++ b/clang/include/clang/AST/APValue.h @@ -247,6 +247,7 @@ class APValue { struct NoLValuePath {}; struct UninitArray {}; struct UninitStruct {}; + struct ConstexprUnknown {}; template friend class clang::serialization::BasicReaderBase; friend class ASTImporter; @@ -254,6 +255,7 @@ class APValue { private: ValueKind Kind; + bool AllowConstexprUnknown : 1; struct ComplexAPSInt { APSInt Real, Imag; @@ -312,32 +314,39 @@ class APValue { DataType Data; public: + bool allowConstexprUnknown() const { return AllowConstexprUnknown; } + + void setConstexprUnknown(bool IsConstexprUnknown = true) { + AllowConstexprUnknown = IsConstexprUnknown; + } + /// Creates an empty APValue of type None. - APValue() : Kind(None) {} + APValue() : Kind(None), AllowConstexprUnknown(false) {} /// Creates an integer APValue holding the given value. - explicit APValue(APSInt I) : Kind(None) { + explicit APValue(APSInt I) : Kind(None), AllowConstexprUnknown(false) { MakeInt(); setInt(std::move(I)); } /// Creates a float APValue holding the given value. - explicit APValue(APFloat F) : Kind(None) { + explicit APValue(APFloat F) : Kind(None), AllowConstexprUnknown(false) { MakeFloat(); setFloat(std::move(F)); } /// Creates a fixed-point APValue holding the given value. - explicit APValue(APFixedPoint FX) : Kind(None) { + explicit APValue(APFixedPoint FX) : Kind(None), AllowConstexprUnknown(false) { MakeFixedPoint(std::move(FX)); } /// Creates a vector APValue with \p N elements. The elements /// are read from \p E. - explicit APValue(const APValue *E, unsigned N) : Kind(None) { + explicit APValue(const APValue *E, unsigned N) + : Kind(None), AllowConstexprUnknown(false) { MakeVector(); setVector(E, N); } /// Creates an integer complex APValue with the given real and imaginary /// values. - APValue(APSInt R, APSInt I) : Kind(None) { + APValue(APSInt R, APSInt I) : Kind(None), AllowConstexprUnknown(false) { MakeComplexInt(); setComplexInt(std::move(R), std::move(I)); } /// Creates a float complex APValue with the given real and imaginary values. - APValue(APFloat R, APFloat I) : Kind(None) { + APValue(APFloat R, APFloat I) : Kind(None), AllowConstexprUnknown(false) { MakeComplexFloat(); setComplexFloat(std::move(R), std::move(I)); } APValue(const APValue &RHS); @@ -348,7 +357,7 @@ class APValue { /// \param IsNullPtr Whether this lvalue is a null pointer. APValue(LValueBase Base, const CharUnits &Offset, NoLValuePath, bool IsNullPtr = false) - : Kind(None) { + : Kind(None), AllowConstexprUnknown(false) { MakeLValue(); setLValue(Base, Offset, NoLValuePath{}, IsNullPtr); } @@ -362,23 +371,36 @@ class APValue { APValue(LValueBase Base, const CharUnits &Offset, ArrayRef Path, bool OnePastTheEnd, bool IsNullPtr = false) - : Kind(None) { + : Kind(None), AllowConstexprUnknown(false) { MakeLValue(); setLValue(Base, Offset, Path, OnePastTheEnd, IsNullPtr); } + /// Creates a constexpr unknown lvalue APValue. + /// \param Base The base of the lvalue. + /// \param Offset The offset of the lvalue. + /// \param IsNullPtr Whether this lvalue is a null pointer. + APValue(LValueBase Base, const CharUnits &Offset, ConstexprUnknown, + bool IsNullPtr = false) + : Kind(None), AllowConstexprUnknown(true) { + MakeLValue(); + setLValue(Base, Offset, NoLValuePath{}, IsNullPtr); + } + /// Creates a new array APValue. /// \param UninitArray Marker. Pass an empty UninitArray. /// \param InitElts Number of elements you're going to initialize in the /// array. /// \param Size Full size of the array. - APValue(UninitArray, unsigned InitElts, unsigned Size) : Kind(None) { + APValue(UninitArray, unsigned InitElts, unsigned Size) + : Kind(None), AllowConstexprUnknown(false) { MakeArray(InitElts, Size); } /// Creates a new struct APValue. /// \param UninitStruct Marker. Pass an empty UninitStruct. /// \param NumBases Number of bases. /// \param NumMembers Number of members. - APValue(UninitStruct, unsigned NumBases, unsigned NumMembers) : Kind(None) { + APValue(UninitStruct, unsigned NumBases, unsigned NumMembers) + : Kind(None), AllowConstexprUnknown(false) { MakeStruct(NumBases, NumMembers); } /// Creates a new union APValue. @@ -386,7 +408,7 @@ class APValue { /// \param ActiveValue The value of the active union member. explicit APValue(const FieldDecl *ActiveDecl, const APValue &ActiveValue = APValue()) - : Kind(None) { + : Kind(None), AllowConstexprUnknown(false) { MakeUnion(); setUnion(ActiveDecl, ActiveValue); } @@ -395,14 +417,15 @@ class APValue { /// \param IsDerivedMember Whether member is a derived one. /// \param Path The path of the member. APValue(const ValueDecl *Member, bool IsDerivedMember, - ArrayRef Path) : Kind(None) { + ArrayRef Path) + : Kind(None), AllowConstexprUnknown(false) { MakeMemberPointer(Member, IsDerivedMember, Path); } /// Creates a new address label diff APValue. /// \param LHSExpr The left-hand side of the difference. /// \param RHSExpr The right-hand side of the difference. - APValue(const AddrLabelExpr* LHSExpr, const AddrLabelExpr* RHSExpr) - : Kind(None) { + APValue(const AddrLabelExpr *LHSExpr, const AddrLabelExpr *RHSExpr) + : Kind(None), AllowConstexprUnknown(false) { MakeAddrLabelDiff(); setAddrLabelDiff(LHSExpr, RHSExpr); } static APValue IndeterminateValue() { diff --git a/clang/include/clang/Analysis/Analyses/ExprMutationAnalyzer.h b/clang/include/clang/Analysis/Analyses/ExprMutationAnalyzer.h index 7442f4aad531b..3344959072c22 100644 --- a/clang/include/clang/Analysis/Analyses/ExprMutationAnalyzer.h +++ b/clang/include/clang/Analysis/Analyses/ExprMutationAnalyzer.h @@ -71,6 +71,10 @@ class ExprMutationAnalyzer { const Stmt *findReferenceMutation(const Expr *Exp); const Stmt *findFunctionArgMutation(const Expr *Exp); + const Stmt *findPointeeValueMutation(const Expr *Exp); + const Stmt *findPointeeMemberMutation(const Expr *Exp); + const Stmt *findPointeeToNonConst(const Expr *Exp); + const Stmt &Stm; ASTContext &Context; Memoized &Memorized; diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index bbf4886b5cf05..60c360d4a9e07 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -1977,16 +1977,16 @@ def AtomicNandFetch : AtomicBuiltin { let Prototype = "void(...)"; } -def AtomicTestAndSet : Builtin { +def AtomicTestAndSet : AtomicBuiltin { let Spellings = ["__atomic_test_and_set"]; - let Attributes = [NoThrow]; - let Prototype = "bool(void volatile*, int)"; + let Attributes = [NoThrow, CustomTypeChecking]; + let Prototype = "bool(...)"; } -def AtomicClear : Builtin { +def AtomicClear : AtomicBuiltin { let Spellings = ["__atomic_clear"]; - let Attributes = [NoThrow]; - let Prototype = "void(void volatile*, int)"; + let Attributes = [NoThrow, CustomTypeChecking]; + let Prototype = "void(...)"; } def AtomicThreadFence : Builtin { diff --git a/clang/include/clang/Basic/BuiltinsNVPTX.def b/clang/include/clang/Basic/BuiltinsNVPTX.def index 969dd9e41ebfa..37b4e6ff77fda 100644 --- a/clang/include/clang/Basic/BuiltinsNVPTX.def +++ b/clang/include/clang/Basic/BuiltinsNVPTX.def @@ -28,7 +28,9 @@ #pragma push_macro("SM_90") #pragma push_macro("SM_90a") #pragma push_macro("SM_100") -#define SM_100 "sm_100" +#pragma push_macro("SM_100a") +#define SM_100a "sm_100a" +#define SM_100 "sm_100|" SM_100a #define SM_90a "sm_90a" #define SM_90 "sm_90|" SM_90a "|" SM_100 #define SM_89 "sm_89|" SM_90 @@ -1091,6 +1093,7 @@ TARGET_BUILTIN(__nvvm_getctarank_shared_cluster, "iv*3", "", AND(SM_90,PTX78)) #pragma pop_macro("SM_90") #pragma pop_macro("SM_90a") #pragma pop_macro("SM_100") +#pragma pop_macro("SM_100a") #pragma pop_macro("PTX42") #pragma pop_macro("PTX60") #pragma pop_macro("PTX61") diff --git a/clang/include/clang/Basic/BuiltinsX86.td b/clang/include/clang/Basic/BuiltinsX86.td index 18fc10eb85c02..a6c932967f528 100644 --- a/clang/include/clang/Basic/BuiltinsX86.td +++ b/clang/include/clang/Basic/BuiltinsX86.td @@ -4936,15 +4936,15 @@ let Features = "avx10.2-512,sm4", Attributes = [NoThrow, RequiredVectorWidth<512 } let Features = "avx10.2-256", Attributes = [NoThrow, RequiredVectorWidth<128>] in { - def vminmaxnepbf16128 : X86Builtin<"_Vector<8, __bf16>(_Vector<8, __bf16>, _Vector<8, __bf16>, _Constant int)">; + def vminmaxbf16128 : X86Builtin<"_Vector<8, __bf16>(_Vector<8, __bf16>, _Vector<8, __bf16>, _Constant int)">; } let Features = "avx10.2-256", Attributes = [NoThrow, RequiredVectorWidth<256>] in { - def vminmaxnepbf16256 : X86Builtin<"_Vector<16, __bf16>(_Vector<16, __bf16>, _Vector<16, __bf16>, _Constant int)">; + def vminmaxbf16256 : X86Builtin<"_Vector<16, __bf16>(_Vector<16, __bf16>, _Vector<16, __bf16>, _Constant int)">; } let Features = "avx10.2-512", Attributes = [NoThrow, RequiredVectorWidth<512>] in { - def vminmaxnepbf16512 : X86Builtin<"_Vector<32, __bf16>(_Vector<32, __bf16>, _Vector<32, __bf16>, _Constant int)">; + def vminmaxbf16512 : X86Builtin<"_Vector<32, __bf16>(_Vector<32, __bf16>, _Vector<32, __bf16>, _Constant int)">; } let Features = "avx10.2-256", Attributes = [NoThrow, RequiredVectorWidth<128>] in { diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def index 0f4ed13d5f3d8..1ab8c7fb4d3c3 100644 --- a/clang/include/clang/Basic/CodeGenOptions.def +++ b/clang/include/clang/Basic/CodeGenOptions.def @@ -413,9 +413,6 @@ CODEGENOPT(StrictReturn, 1, 1) /// Whether emit pseudo probes for sample pgo profile collection. CODEGENOPT(PseudoProbeForProfiling, 1, 0) -/// Whether 3-component vector type is preserved. -CODEGENOPT(PreserveVec3Type, 1, 0) - CODEGENOPT(NoPLT, 1, 0) /// Whether to emit all vtables diff --git a/clang/include/clang/Basic/Cuda.h b/clang/include/clang/Basic/Cuda.h index c2a4addf488df..f33ba46233a7a 100644 --- a/clang/include/clang/Basic/Cuda.h +++ b/clang/include/clang/Basic/Cuda.h @@ -44,9 +44,10 @@ enum class CudaVersion { CUDA_124, CUDA_125, CUDA_126, + CUDA_128, FULLY_SUPPORTED = CUDA_123, PARTIALLY_SUPPORTED = - CUDA_126, // Partially supported. Proceed with a warning. + CUDA_128, // Partially supported. Proceed with a warning. NEW = 10000, // Too new. Issue a warning, but allow using it. }; const char *CudaVersionToString(CudaVersion V); @@ -80,6 +81,7 @@ enum class OffloadArch { SM_90, SM_90a, SM_100, + SM_100a, GFX600, GFX601, GFX602, diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index db54312ad965e..0175c20daf241 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -487,6 +487,10 @@ def err_noreturn_non_function : Error< def warn_qual_return_type : Warning< "'%0' type qualifier%s1 on return type %plural{1:has|:have}1 no effect">, InGroup, DefaultIgnore; +def warn_qual_base_type : Warning< + "'%0' qualifier%s1 on base class type %2 have no effect">, + InGroup, DefaultIgnore; + def warn_deprecated_redundant_constexpr_static_def : Warning< "out-of-line definition of constexpr static data member is redundant " "in C++17 and is deprecated">, diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def index 3b833240e5b68..a980be853d53e 100644 --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -532,6 +532,8 @@ BENIGN_LANGOPT(CheckConstexprFunctionBodies, 1, 1, LANGOPT(BoundsSafety, 1, 0, "Bounds safety extension for C") +LANGOPT(PreserveVec3Type, 1, 0, "Preserve 3-component vector type") + #undef LANGOPT #undef COMPATIBLE_LANGOPT #undef BENIGN_LANGOPT diff --git a/clang/include/clang/Basic/arm_sve.td b/clang/include/clang/Basic/arm_sve.td index ac1c139b20943..e7001bac450e8 100644 --- a/clang/include/clang/Basic/arm_sve.td +++ b/clang/include/clang/Basic/arm_sve.td @@ -2280,15 +2280,15 @@ let SVETargetGuard = "sve2p1", SMETargetGuard = "sme2" in { let SVETargetGuard = "sve2p1", SMETargetGuard = InvalidMode in { // ZIPQ1, ZIPQ2, UZPQ1, UZPQ2 - def SVZIPQ1 : SInst<"svzipq1[_{d}]", "ddd", "cUcsUsiUilUlbhfd", MergeNone, "aarch64_sve_zipq1", [], []>; - def SVZIPQ2 : SInst<"svzipq2[_{d}]", "ddd", "cUcsUsiUilUlbhfd", MergeNone, "aarch64_sve_zipq2", [], []>; - def SVUZPQ1 : SInst<"svuzpq1[_{d}]", "ddd", "cUcsUsiUilUlbhfd", MergeNone, "aarch64_sve_uzpq1", [], []>; - def SVUZPQ2 : SInst<"svuzpq2[_{d}]", "ddd", "cUcsUsiUilUlbhfd", MergeNone, "aarch64_sve_uzpq2", [], []>; + def SVZIPQ1 : SInst<"svzipq1[_{d}]", "ddd", "cUcsUsiUilUlbhfdm", MergeNone, "aarch64_sve_zipq1", [], []>; + def SVZIPQ2 : SInst<"svzipq2[_{d}]", "ddd", "cUcsUsiUilUlbhfdm", MergeNone, "aarch64_sve_zipq2", [], []>; + def SVUZPQ1 : SInst<"svuzpq1[_{d}]", "ddd", "cUcsUsiUilUlbhfdm", MergeNone, "aarch64_sve_uzpq1", [], []>; + def SVUZPQ2 : SInst<"svuzpq2[_{d}]", "ddd", "cUcsUsiUilUlbhfdm", MergeNone, "aarch64_sve_uzpq2", [], []>; // TBLQ, TBXQ - def SVTBLQ : SInst<"svtblq[_{d}]", "ddu", "cUcsUsiUilUlbhfd", MergeNone, "aarch64_sve_tblq">; - def SVTBXQ : SInst<"svtbxq[_{d}]", "dddu", "cUcsUsiUilUlbhfd", MergeNone, "aarch64_sve_tbxq">; + def SVTBLQ : SInst<"svtblq[_{d}]", "ddu", "cUcsUsiUilUlbhfdm", MergeNone, "aarch64_sve_tblq">; + def SVTBXQ : SInst<"svtbxq[_{d}]", "dddu", "cUcsUsiUilUlbhfdm", MergeNone, "aarch64_sve_tbxq">; // EXTQ - def EXTQ : SInst<"svextq[_{d}]", "dddk", "cUcsUsiUilUlbhfd", MergeNone, "aarch64_sve_extq", [], [ImmCheck<2, ImmCheckLaneIndex, 0>]>; + def EXTQ : SInst<"svextq[_{d}]", "dddk", "cUcsUsiUilUlbhfdm", MergeNone, "aarch64_sve_extq", [], [ImmCheck<2, ImmCheckLaneIndex, 0>]>; // PMOV // Move to Pred @@ -2314,7 +2314,7 @@ let SVETargetGuard = "sve2p1", SMETargetGuard = InvalidMode in { let SVETargetGuard = "sve2p1", SMETargetGuard = "sme2p1" in { // DUPQ - def SVDUP_LANEQ_B : SInst<"svdup_laneq[_{d}]", "ddi", "cUc", MergeNone, "aarch64_sve_dup_laneq", [VerifyRuntimeMode], [ImmCheck<1, ImmCheck0_15>]>; + def SVDUP_LANEQ_B : SInst<"svdup_laneq[_{d}]", "ddi", "cUcm", MergeNone, "aarch64_sve_dup_laneq", [VerifyRuntimeMode], [ImmCheck<1, ImmCheck0_15>]>; def SVDUP_LANEQ_H : SInst<"svdup_laneq[_{d}]", "ddi", "sUsh", MergeNone, "aarch64_sve_dup_laneq", [VerifyRuntimeMode], [ImmCheck<1, ImmCheck0_7>]>; def SVDUP_LANEQ_S : SInst<"svdup_laneq[_{d}]", "ddi", "iUif", MergeNone, "aarch64_sve_dup_laneq", [VerifyRuntimeMode], [ImmCheck<1, ImmCheck0_3>]>; def SVDUP_LANEQ_D : SInst<"svdup_laneq[_{d}]", "ddi", "lUld", MergeNone, "aarch64_sve_dup_laneq", [VerifyRuntimeMode], [ImmCheck<1, ImmCheck0_1>]>; diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index c4b9743597bb2..852051e772fc1 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -8245,10 +8245,6 @@ def fhlsl_strict_availability : Flag<["-"], "fhlsl-strict-availability">, Group, MarshallingInfoFlag>; -def fpreserve_vec3_type : Flag<["-"], "fpreserve-vec3-type">, - HelpText<"Preserve 3-component vector type">, - MarshallingInfoFlag>, - ImpliedByAnyOf<[hlsl.KeyPath]>; def fwchar_type_EQ : Joined<["-"], "fwchar-type=">, HelpText<"Select underlying type for wchar_t">, Values<"char,short,int">, diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h index c31423841ec1a..fd526f189ec83 100644 --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -2676,19 +2676,6 @@ struct FormatStyle { /// \version 3.7 bool ExperimentalAutoDetectBinPacking; - /// If ``true``, clang-format will indent the body of an ``export { ... }`` - /// block. This doesn't affect the formatting of anything else related to - /// exported declarations. - /// \code - /// true: false: - /// export { vs. export { - /// void foo(); void foo(); - /// void bar(); void bar(); - /// } } - /// \endcode - /// \version 20 - bool ExportBlockIndentation; - /// If ``true``, clang-format adds missing namespace end comments for /// namespaces and fixes invalid existing ones. This doesn't affect short /// namespaces, which are controlled by ``ShortNamespaceLines``. @@ -2815,22 +2802,18 @@ struct FormatStyle { /// \version 3.3 bool IndentCaseLabels; - /// Indent goto labels. - /// - /// When ``false``, goto labels are flushed left. + /// If ``true``, clang-format will indent the body of an ``export { ... }`` + /// block. This doesn't affect the formatting of anything else related to + /// exported declarations. /// \code - /// true: false: - /// int f() { vs. int f() { - /// if (foo()) { if (foo()) { - /// label1: label1: - /// bar(); bar(); - /// } } - /// label2: label2: - /// return 1; return 1; - /// } } + /// true: false: + /// export { vs. export { + /// void foo(); void foo(); + /// void bar(); void bar(); + /// } } /// \endcode - /// \version 10 - bool IndentGotoLabels; + /// \version 20 + bool IndentExportBlock; /// Indents extern blocks enum IndentExternBlockStyle : int8_t { @@ -2872,6 +2855,23 @@ struct FormatStyle { /// \version 11 IndentExternBlockStyle IndentExternBlock; + /// Indent goto labels. + /// + /// When ``false``, goto labels are flushed left. + /// \code + /// true: false: + /// int f() { vs. int f() { + /// if (foo()) { if (foo()) { + /// label1: label1: + /// bar(); bar(); + /// } } + /// label2: label2: + /// return 1; return 1; + /// } } + /// \endcode + /// \version 10 + bool IndentGotoLabels; + /// Options for indenting preprocessor directives. enum PPDirectiveIndentStyle : int8_t { /// Does not indent any directives. @@ -5267,7 +5267,6 @@ struct FormatStyle { EmptyLineBeforeAccessModifier == R.EmptyLineBeforeAccessModifier && ExperimentalAutoDetectBinPacking == R.ExperimentalAutoDetectBinPacking && - ExportBlockIndentation == R.ExportBlockIndentation && FixNamespaceComments == R.FixNamespaceComments && ForEachMacros == R.ForEachMacros && IncludeStyle.IncludeBlocks == R.IncludeStyle.IncludeBlocks && @@ -5280,6 +5279,7 @@ struct FormatStyle { IndentAccessModifiers == R.IndentAccessModifiers && IndentCaseBlocks == R.IndentCaseBlocks && IndentCaseLabels == R.IndentCaseLabels && + IndentExportBlock == R.IndentExportBlock && IndentExternBlock == R.IndentExternBlock && IndentGotoLabels == R.IndentGotoLabels && IndentPPDirectives == R.IndentPPDirectives && diff --git a/clang/include/clang/Lex/Lexer.h b/clang/include/clang/Lex/Lexer.h index 82a041ea3f848..89c8ae354dafc 100644 --- a/clang/include/clang/Lex/Lexer.h +++ b/clang/include/clang/Lex/Lexer.h @@ -557,6 +557,12 @@ class Lexer : public PreprocessorLexer { const LangOptions &LangOpts, bool IncludeComments = false); + /// Finds the token that comes before the given location. + static std::optional findPreviousToken(SourceLocation Loc, + const SourceManager &SM, + const LangOptions &LangOpts, + bool IncludeComments); + /// Checks that the given token is the first token that occurs after /// the given location (this excludes comments and whitespace). Returns the /// location immediately after the specified token. If the token is not found diff --git a/clang/include/clang/Sema/SemaCodeCompletion.h b/clang/include/clang/Sema/SemaCodeCompletion.h index 50409439389b0..e931596c215d3 100644 --- a/clang/include/clang/Sema/SemaCodeCompletion.h +++ b/clang/include/clang/Sema/SemaCodeCompletion.h @@ -23,6 +23,7 @@ #include "clang/Sema/CodeCompleteConsumer.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/Designator.h" +#include "clang/Sema/HeuristicResolver.h" #include "clang/Sema/Ownership.h" #include "clang/Sema/SemaBase.h" #include "llvm/ADT/StringRef.h" @@ -43,6 +44,7 @@ class SemaCodeCompletion : public SemaBase { /// Code-completion consumer. CodeCompleteConsumer *CodeCompleter; + HeuristicResolver Resolver; /// Describes the context in which code completion occurs. enum ParserCompletionContext { diff --git a/clang/lib/AST/APValue.cpp b/clang/lib/AST/APValue.cpp index f9e08b70d6ab0..3b814be266330 100644 --- a/clang/lib/AST/APValue.cpp +++ b/clang/lib/AST/APValue.cpp @@ -308,7 +308,8 @@ APValue::UnionData::~UnionData () { delete Value; } -APValue::APValue(const APValue &RHS) : Kind(None) { +APValue::APValue(const APValue &RHS) + : Kind(None), AllowConstexprUnknown(RHS.AllowConstexprUnknown) { switch (RHS.getKind()) { case None: case Indeterminate: @@ -379,13 +380,17 @@ APValue::APValue(const APValue &RHS) : Kind(None) { } } -APValue::APValue(APValue &&RHS) : Kind(RHS.Kind), Data(RHS.Data) { +APValue::APValue(APValue &&RHS) + : Kind(RHS.Kind), AllowConstexprUnknown(RHS.AllowConstexprUnknown), + Data(RHS.Data) { RHS.Kind = None; } APValue &APValue::operator=(const APValue &RHS) { if (this != &RHS) *this = APValue(RHS); + + AllowConstexprUnknown = RHS.AllowConstexprUnknown; return *this; } @@ -395,6 +400,7 @@ APValue &APValue::operator=(APValue &&RHS) { DestroyDataAndMakeUninit(); Kind = RHS.Kind; Data = RHS.Data; + AllowConstexprUnknown = RHS.AllowConstexprUnknown; RHS.Kind = None; } return *this; @@ -426,6 +432,7 @@ void APValue::DestroyDataAndMakeUninit() { else if (Kind == AddrLabelDiff) ((AddrLabelDiffData *)(char *)&Data)->~AddrLabelDiffData(); Kind = None; + AllowConstexprUnknown = false; } bool APValue::needsCleanup() const { @@ -468,6 +475,10 @@ bool APValue::needsCleanup() const { void APValue::swap(APValue &RHS) { std::swap(Kind, RHS.Kind); std::swap(Data, RHS.Data); + // We can't use std::swap w/ bit-fields + bool tmp = AllowConstexprUnknown; + AllowConstexprUnknown = RHS.AllowConstexprUnknown; + RHS.AllowConstexprUnknown = tmp; } /// Profile the value of an APInt, excluding its bit-width. diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 155dbcfcaeed3..a4ba9fd055346 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -3503,6 +3503,34 @@ uint16_t ASTContext::getPointerAuthTypeDiscriminator(QualType T) { encodeTypeForFunctionPointerAuth(*this, Out, T); } else { T = T.getUnqualifiedType(); + // Calls to member function pointers don't need to worry about + // language interop or the laxness of the C type compatibility rules. + // We just mangle the member pointer type directly, which is + // implicitly much stricter about type matching. However, we do + // strip any top-level exception specification before this mangling. + // C++23 requires calls to work when the function type is convertible + // to the pointer type by a function pointer conversion, which can + // change the exception specification. This does not technically + // require the exception specification to not affect representation, + // because the function pointer conversion is still always a direct + // value conversion and therefore an opportunity to resign the + // pointer. (This is in contrast to e.g. qualification conversions, + // which can be applied in nested pointer positions, effectively + // requiring qualified and unqualified representations to match.) + // However, it is pragmatic to ignore exception specifications + // because it allows a certain amount of `noexcept` mismatching + // to not become a visible ODR problem. This also leaves some + // room for the committee to add laxness to function pointer + // conversions in future standards. + if (auto *MPT = T->getAs()) + if (MPT->isMemberFunctionPointer()) { + QualType PointeeType = MPT->getPointeeType(); + if (PointeeType->castAs()->getExceptionSpecType() != + EST_None) { + QualType FT = getFunctionTypeWithExceptionSpec(PointeeType, EST_None); + T = getMemberPointerType(FT, MPT->getClass()); + } + } std::unique_ptr MC(createMangleContext()); MC->mangleCanonicalTypeName(T, Out); } diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index f641a72ed2644..a1a51d38b93e1 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -4003,7 +4003,7 @@ const IdentifierInfo *FunctionDecl::getLiteralIdentifier() const { FunctionDecl::TemplatedKind FunctionDecl::getTemplatedKind() const { if (TemplateOrSpecialization.isNull()) return TK_NonTemplate; - if (const auto *ND = TemplateOrSpecialization.dyn_cast()) { + if (const auto *ND = dyn_cast(TemplateOrSpecialization)) { if (isa(ND)) return TK_DependentNonTemplate; assert(isa(ND) && diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index f6a4ed970cb23..31b95bca613c2 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -5077,6 +5077,8 @@ unsigned AtomicExpr::getNumSubExprs(AtomicOp Op) { case AO__opencl_atomic_init: case AO__c11_atomic_load: case AO__atomic_load_n: + case AO__atomic_test_and_set: + case AO__atomic_clear: return 2; case AO__scoped_atomic_load_n: diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 2e680d1569f60..734311e5d8b9a 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -572,6 +572,7 @@ namespace { typedef std::map MapTy; /// Temporaries - Temporary lvalues materialized within this stack frame. MapTy Temporaries; + MapTy ConstexprUnknownAPValues; /// CallRange - The source range of the call expression for this call. SourceRange CallRange; @@ -646,6 +647,9 @@ namespace { APValue &createTemporary(const KeyT *Key, QualType T, ScopeKind Scope, LValue &LV); + APValue &createConstexprUnknownAPValues(const VarDecl *Key, + APValue::LValueBase Base); + /// Allocate storage for a parameter of a function call made in this frame. APValue &createParam(CallRef Args, const ParmVarDecl *PVD, LValue &LV); @@ -1630,8 +1634,11 @@ namespace { SubobjectDesignator Designator; bool IsNullPtr : 1; bool InvalidBase : 1; + // P2280R4 track if we have an unknown reference or pointer. + bool AllowConstexprUnknown = false; const APValue::LValueBase getLValueBase() const { return Base; } + bool allowConstexprUnknown() const { return AllowConstexprUnknown; } CharUnits &getLValueOffset() { return Offset; } const CharUnits &getLValueOffset() const { return Offset; } SubobjectDesignator &getLValueDesignator() { return Designator; } @@ -1649,6 +1656,8 @@ namespace { V = APValue(Base, Offset, Designator.Entries, Designator.IsOnePastTheEnd, IsNullPtr); } + if (AllowConstexprUnknown) + V.setConstexprUnknown(); } void setFrom(ASTContext &Ctx, const APValue &V) { assert(V.isLValue() && "Setting LValue from a non-LValue?"); @@ -1657,6 +1666,7 @@ namespace { InvalidBase = false; Designator = SubobjectDesignator(Ctx, V); IsNullPtr = V.isNullPointer(); + AllowConstexprUnknown = V.allowConstexprUnknown(); } void set(APValue::LValueBase B, bool BInvalid = false) { @@ -1674,6 +1684,7 @@ namespace { InvalidBase = BInvalid; Designator = SubobjectDesignator(getType(B)); IsNullPtr = false; + AllowConstexprUnknown = false; } void setNull(ASTContext &Ctx, QualType PointerTy) { @@ -1683,6 +1694,7 @@ namespace { InvalidBase = false; Designator = SubobjectDesignator(PointerTy->getPointeeType()); IsNullPtr = true; + AllowConstexprUnknown = false; } void setInvalid(APValue::LValueBase B, unsigned I = 0) { @@ -1944,6 +1956,15 @@ APValue &CallStackFrame::createTemporary(const KeyT *Key, QualType T, return createLocal(Base, Key, T, Scope); } +APValue & +CallStackFrame::createConstexprUnknownAPValues(const VarDecl *Key, + APValue::LValueBase Base) { + APValue &Result = ConstexprUnknownAPValues[MapKeyTy(Key, Base.getVersion())]; + Result = APValue(Base, CharUnits::One(), APValue::ConstexprUnknown{}); + + return Result; +} + /// Allocate storage for a parameter of a function call made in this frame. APValue &CallStackFrame::createParam(CallRef Args, const ParmVarDecl *PVD, LValue &LV) { @@ -3446,6 +3467,11 @@ static bool HandleLValueVectorElement(EvalInfo &Info, const Expr *E, static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E, const VarDecl *VD, CallStackFrame *Frame, unsigned Version, APValue *&Result) { + // C++23 [expr.const]p8 If we have a reference type allow unknown references + // and pointers. + bool AllowConstexprUnknown = + Info.getLangOpts().CPlusPlus23 && VD->getType()->isReferenceType(); + APValue::LValueBase Base(VD, Frame ? Frame->Index : 0, Version); // If this is a local variable, dig out its value. @@ -3480,7 +3506,11 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E, return true; } - if (isa(VD)) { + // P2280R4 struck the restriction that variable of reference type lifetime + // should begin within the evaluation of E + // Used to be C++20 [expr.const]p5.12.2: + // ... its lifetime began within the evaluation of E; + if (isa(VD) && !AllowConstexprUnknown) { // Assume parameters of a potential constant expression are usable in // constant expressions. if (!Info.checkingPotentialConstantExpression() || @@ -3504,7 +3534,11 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E, // FIXME: We should eventually check whether the variable has a reachable // initializing declaration. const Expr *Init = VD->getAnyInitializer(VD); - if (!Init) { + // P2280R4 struck the restriction that variable of reference type should have + // a preceding initialization. + // Used to be C++20 [expr.const]p5.12: + // ... reference has a preceding initialization and either ... + if (!Init && !AllowConstexprUnknown) { // Don't diagnose during potential constant expression checking; an // initializer might be added later. if (!Info.checkingPotentialConstantExpression()) { @@ -3515,7 +3549,11 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E, return false; } - if (Init->isValueDependent()) { + // P2280R4 struck the initialization requirement for variables of reference + // type so we can no longer assume we have an Init. + // Used to be C++20 [expr.const]p5.12: + // ... reference has a preceding initialization and either ... + if (Init && Init->isValueDependent()) { // The DeclRefExpr is not value-dependent, but the variable it refers to // has a value-dependent initializer. This should only happen in // constant-folding cases, where the variable is not actually of a suitable @@ -3534,7 +3572,15 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E, // Check that we can fold the initializer. In C++, we will have already done // this in the cases where it matters for conformance. - if (!VD->evaluateValue()) { + // P2280R4 struck the initialization requirement for variables of reference + // type so we can no longer assume we have an Init. + // Used to be C++20 [expr.const]p5.12: + // ... reference has a preceding initialization and either ... + if (Init && !VD->evaluateValue()) { + if (AllowConstexprUnknown) { + Result = &Info.CurrentCall->createConstexprUnknownAPValues(VD, Base); + return true; + } Info.FFDiag(E, diag::note_constexpr_var_init_non_constant, 1) << VD; NoteLValueLocation(Info, Base); return false; @@ -3566,6 +3612,20 @@ static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E, } Result = VD->getEvaluatedValue(); + + // C++23 [expr.const]p8 + // ... For such an object that is not usable in constant expressions, the + // dynamic type of the object is constexpr-unknown. For such a reference that + // is not usable in constant expressions, the reference is treated as binding + // to an unspecified object of the referenced type whose lifetime and that of + // all subobjects includes the entire constant evaluation and whose dynamic + // type is constexpr-unknown. + if (AllowConstexprUnknown) { + if (!Result) + Result = &Info.CurrentCall->createConstexprUnknownAPValues(VD, Base); + else + Result->setConstexprUnknown(); + } return true; } @@ -3847,6 +3907,11 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj, const FieldDecl *LastField = nullptr; const FieldDecl *VolatileField = nullptr; + // C++23 [expr.const]p8 If we have an unknown reference or pointers and it + // does not have a value then bail out. + if (O->allowConstexprUnknown() && !O->hasValue()) + return false; + // Walk the designator's path to find the subobject. for (unsigned I = 0, N = Sub.Entries.size(); /**/; ++I) { // Reading an indeterminate value is undefined, but assigning over one is OK. @@ -5909,6 +5974,15 @@ struct CheckDynamicTypeHandler { /// dynamic type. static bool checkDynamicType(EvalInfo &Info, const Expr *E, const LValue &This, AccessKinds AK, bool Polymorphic) { + // We are not allowed to invoke a virtual function whose dynamic type + // is constexpr-unknown, so stop early and let this fail later on if we + // attempt to do so. + // C++23 [expr.const]p5.6 + // an invocation of a virtual function ([class.virtual]) for an object whose + // dynamic type is constexpr-unknown; + if (This.allowConstexprUnknown()) + return true; + if (This.Designator.Invalid) return false; @@ -5981,7 +6055,13 @@ static std::optional ComputeDynamicType(EvalInfo &Info, // If we don't have an lvalue denoting an object of class type, there is no // meaningful dynamic type. (We consider objects of non-class type to have no // dynamic type.) - if (!checkDynamicType(Info, E, This, AK, true)) + if (!checkDynamicType(Info, E, This, AK, + (AK == AK_TypeId + ? (E->getType()->isReferenceType() ? true : false) + : true))) + return std::nullopt; + + if (This.Designator.Invalid) return std::nullopt; // Refuse to compute a dynamic type in the presence of virtual bases. This @@ -8749,7 +8829,8 @@ static bool HandleLambdaCapture(EvalInfo &Info, const Expr *E, LValue &Result, const ParmVarDecl *Self = MD->getParamDecl(0); if (Self->getType()->isReferenceType()) { APValue *RefValue = Info.getParamSlot(Info.CurrentCall->Arguments, Self); - Result.setFrom(Info.Ctx, *RefValue); + if (!RefValue->allowConstexprUnknown() || RefValue->hasValue()) + Result.setFrom(Info.Ctx, *RefValue); } else { const ParmVarDecl *VD = Info.CurrentCall->Arguments.getOrigParam(Self); CallStackFrame *Frame = @@ -8805,7 +8886,10 @@ bool LValueExprEvaluator::VisitDeclRefExpr(const DeclRefExpr *E) { bool LValueExprEvaluator::VisitVarDecl(const Expr *E, const VarDecl *VD) { - + // C++23 [expr.const]p8 If we have a reference type allow unknown references + // and pointers. + bool AllowConstexprUnknown = + Info.getLangOpts().CPlusPlus23 && VD->getType()->isReferenceType(); // If we are within a lambda's call operator, check whether the 'VD' referred // to within 'E' actually represents a lambda-capture that maps to a // data-member/field within the closure object, and if so, evaluate to the @@ -8875,10 +8959,24 @@ bool LValueExprEvaluator::VisitVarDecl(const Expr *E, const VarDecl *VD) { if (!V->hasValue()) { // FIXME: Is it possible for V to be indeterminate here? If so, we should // adjust the diagnostic to say that. - if (!Info.checkingPotentialConstantExpression()) + // C++23 [expr.const]p8 If we have a variable that is unknown reference + // or pointer it may not have a value but still be usable later on so do not + // diagnose. + if (!Info.checkingPotentialConstantExpression() && !AllowConstexprUnknown) Info.FFDiag(E, diag::note_constexpr_use_uninit_reference); + + // C++23 [expr.const]p8 If we have a variable that is unknown reference or + // pointer try to recover it from the frame and set the result accordingly. + if (VD->getType()->isReferenceType() && AllowConstexprUnknown) { + if (Frame) { + Result.set({VD, Frame->Index, Version}); + return true; + } + return Success(VD); + } return false; } + return Success(*V, E); } @@ -11882,7 +11980,10 @@ class IntExprEvaluator } bool Success(const APValue &V, const Expr *E) { - if (V.isLValue() || V.isAddrLabelDiff() || V.isIndeterminate()) { + // C++23 [expr.const]p8 If we have a variable that is unknown reference or + // pointer allow further evaluation of the value. + if (V.isLValue() || V.isAddrLabelDiff() || V.isIndeterminate() || + V.allowConstexprUnknown()) { Result = V; return true; } @@ -12597,6 +12698,10 @@ static bool determineEndOffset(EvalInfo &Info, SourceLocation ExprLoc, auto CheckedHandleSizeof = [&](QualType Ty, CharUnits &Result) { if (Ty.isNull() || Ty->isIncompleteType() || Ty->isFunctionType()) return false; + + if (Ty->isReferenceType()) + Ty = Ty.getNonReferenceType(); + return HandleSizeof(Info, ExprLoc, Ty, Result); }; @@ -14266,6 +14371,12 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E, if (!EvaluatePointer(E->getRHS(), RHSValue, Info) || !LHSOK) return false; + // If we have Unknown pointers we should fail if they are not global values. + if (!(IsGlobalLValue(LHSValue.getLValueBase()) && + IsGlobalLValue(RHSValue.getLValueBase())) && + (LHSValue.AllowConstexprUnknown || RHSValue.AllowConstexprUnknown)) + return false; + // Reject differing bases from the normal codepath; we special-case // comparisons to null. if (!HasSameBase(LHSValue, RHSValue)) { @@ -17859,6 +17970,9 @@ std::optional EvaluateBuiltinIsWithinLifetime(IntExprEvaluator &IEE, if (!EvaluatePointer(Arg, Val, Info)) return std::nullopt; + if (Val.allowConstexprUnknown()) + return true; + auto Error = [&](int Diag) { bool CalledFromStd = false; const auto *Callee = Info.CurrentCall->getCallee(); diff --git a/clang/lib/Analysis/ExprMutationAnalyzer.cpp b/clang/lib/Analysis/ExprMutationAnalyzer.cpp index cefe64409c977..d7b44149d0fc4 100644 --- a/clang/lib/Analysis/ExprMutationAnalyzer.cpp +++ b/clang/lib/Analysis/ExprMutationAnalyzer.cpp @@ -8,8 +8,10 @@ #include "clang/Analysis/Analyses/ExprMutationAnalyzer.h" #include "clang/AST/Expr.h" #include "clang/AST/OperationKinds.h" +#include "clang/AST/Stmt.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/ASTMatchers/ASTMatchersMacros.h" #include "llvm/ADT/STLExtras.h" namespace clang { @@ -22,7 +24,6 @@ using namespace ast_matchers; // - ConditionalOperator // - BinaryConditionalOperator static bool canExprResolveTo(const Expr *Source, const Expr *Target) { - const auto IgnoreDerivedToBase = [](const Expr *E, auto Matcher) { if (Matcher(E)) return true; @@ -79,6 +80,8 @@ static bool canExprResolveTo(const Expr *Source, const Expr *Target) { namespace { +AST_MATCHER(Type, isDependentType) { return Node.isDependentType(); } + AST_MATCHER_P(LambdaExpr, hasCaptureInit, const Expr *, E) { return llvm::is_contained(Node.capture_inits(), E); } @@ -99,6 +102,59 @@ AST_MATCHER_P(Stmt, canResolveToExpr, const Stmt *, Inner) { return canExprResolveTo(Exp, Target); } +// use class member to store data can reduce stack usage to avoid stack overflow +// when recursive call. +class ExprPointeeResolve { + const Expr *T; + + bool resolveExpr(const Expr *E) { + if (E == nullptr) + return false; + if (E == T) + return true; + + if (const auto *BO = dyn_cast(E)) { + if (BO->isAdditiveOp()) + return (resolveExpr(BO->getLHS()) || resolveExpr(BO->getRHS())); + if (BO->isCommaOp()) + return resolveExpr(BO->getRHS()); + return false; + } + + if (const auto *PE = dyn_cast(E)) + return resolveExpr(PE->getSubExpr()); + + if (const auto *ICE = dyn_cast(E)) { + // only implicit cast needs to be treated as resolvable. + // explicit cast will be checked in `findPointeeToNonConst` + const CastKind kind = ICE->getCastKind(); + if (kind == CK_LValueToRValue || kind == CK_DerivedToBase || + kind == CK_UncheckedDerivedToBase) + return resolveExpr(ICE->getSubExpr()); + return false; + } + + if (const auto *ACE = dyn_cast(E)) + return resolve(ACE->getTrueExpr()) || resolve(ACE->getFalseExpr()); + + return false; + } + +public: + ExprPointeeResolve(const Expr *T) : T(T) {} + bool resolve(const Expr *S) { return resolveExpr(S); } +}; + +AST_MATCHER_P(Stmt, canResolveToExprPointee, const Stmt *, T) { + auto *Exp = dyn_cast(&Node); + if (!Exp) + return true; + auto *Target = dyn_cast(T); + if (!Target) + return false; + return ExprPointeeResolve{Target}.resolve(Exp); +} + // Similar to 'hasAnyArgument', but does not work because 'InitListExpr' does // not have the 'arguments()' method. AST_MATCHER_P(InitListExpr, hasAnyInit, ast_matchers::internal::Matcher, @@ -208,7 +264,14 @@ const Stmt *ExprMutationAnalyzer::Analyzer::findMutation(const Decl *Dec) { const Stmt * ExprMutationAnalyzer::Analyzer::findPointeeMutation(const Expr *Exp) { - return findMutationMemoized(Exp, {/*TODO*/}, Memorized.PointeeResults); + return findMutationMemoized( + Exp, + { + &ExprMutationAnalyzer::Analyzer::findPointeeValueMutation, + &ExprMutationAnalyzer::Analyzer::findPointeeMemberMutation, + &ExprMutationAnalyzer::Analyzer::findPointeeToNonConst, + }, + Memorized.PointeeResults); } const Stmt * @@ -377,7 +440,8 @@ ExprMutationAnalyzer::Analyzer::findDirectMutation(const Expr *Exp) { // references. const auto NonConstRefParam = forEachArgumentWithParamType( anyOf(canResolveToExpr(Exp), - memberExpr(hasObjectExpression(canResolveToExpr(Exp)))), + memberExpr( + hasObjectExpression(ignoringImpCasts(canResolveToExpr(Exp))))), nonConstReferenceType()); const auto NotInstantiated = unless(hasDeclaration(isInstantiated())); @@ -643,6 +707,83 @@ ExprMutationAnalyzer::Analyzer::findFunctionArgMutation(const Expr *Exp) { return nullptr; } +const Stmt * +ExprMutationAnalyzer::Analyzer::findPointeeValueMutation(const Expr *Exp) { + const auto Matches = match( + stmt(forEachDescendant( + expr(anyOf( + // deref by * + unaryOperator(hasOperatorName("*"), + hasUnaryOperand(canResolveToExprPointee(Exp))), + // deref by [] + arraySubscriptExpr(hasBase(canResolveToExprPointee(Exp))))) + .bind(NodeID::value))), + Stm, Context); + return findExprMutation(Matches); +} + +const Stmt * +ExprMutationAnalyzer::Analyzer::findPointeeMemberMutation(const Expr *Exp) { + const Stmt *MemberCallExpr = selectFirst( + "stmt", match(stmt(forEachDescendant( + cxxMemberCallExpr(on(canResolveToExprPointee(Exp)), + unless(isConstCallee())) + .bind("stmt"))), + Stm, Context)); + if (MemberCallExpr) + return MemberCallExpr; + const auto Matches = + match(stmt(forEachDescendant( + memberExpr(hasObjectExpression(canResolveToExprPointee(Exp))) + .bind(NodeID::value))), + Stm, Context); + return findExprMutation(Matches); +} + +const Stmt * +ExprMutationAnalyzer::Analyzer::findPointeeToNonConst(const Expr *Exp) { + const auto NonConstPointerOrDependentType = + type(anyOf(nonConstPointerType(), isDependentType())); + + // assign + const auto InitToNonConst = + varDecl(hasType(NonConstPointerOrDependentType), + hasInitializer(expr(canResolveToExprPointee(Exp)).bind("stmt"))); + const auto AssignToNonConst = + binaryOperation(hasOperatorName("="), + hasLHS(expr(hasType(NonConstPointerOrDependentType))), + hasRHS(canResolveToExprPointee(Exp))); + // arguments like + const auto ArgOfInstantiationDependent = allOf( + hasAnyArgument(canResolveToExprPointee(Exp)), isInstantiationDependent()); + const auto ArgOfNonConstParameter = forEachArgumentWithParamType( + canResolveToExprPointee(Exp), NonConstPointerOrDependentType); + const auto CallLikeMatcher = + anyOf(ArgOfNonConstParameter, ArgOfInstantiationDependent); + const auto PassAsNonConstArg = + expr(anyOf(cxxUnresolvedConstructExpr(ArgOfInstantiationDependent), + cxxConstructExpr(CallLikeMatcher), callExpr(CallLikeMatcher), + parenListExpr(has(canResolveToExprPointee(Exp))), + initListExpr(hasAnyInit(canResolveToExprPointee(Exp))))); + // cast + const auto CastToNonConst = + explicitCastExpr(hasSourceExpression(canResolveToExprPointee(Exp)), + hasDestinationType(NonConstPointerOrDependentType)); + + // capture + // FIXME: false positive if the pointee does not change in lambda + const auto CaptureNoConst = lambdaExpr(hasCaptureInit(Exp)); + + const auto Matches = + match(stmt(anyOf(forEachDescendant( + stmt(anyOf(AssignToNonConst, PassAsNonConstArg, + CastToNonConst, CaptureNoConst)) + .bind("stmt")), + forEachDescendant(InitToNonConst))), + Stm, Context); + return selectFirst("stmt", Matches); +} + FunctionParmMutationAnalyzer::FunctionParmMutationAnalyzer( const FunctionDecl &Func, ASTContext &Context, ExprMutationAnalyzer::Memoized &Memorized) diff --git a/clang/lib/Basic/Cuda.cpp b/clang/lib/Basic/Cuda.cpp index d56609a2a8f24..1bfec0b37c5ee 100644 --- a/clang/lib/Basic/Cuda.cpp +++ b/clang/lib/Basic/Cuda.cpp @@ -44,6 +44,7 @@ static const CudaVersionMapEntry CudaNameVersionMap[] = { CUDA_ENTRY(12, 4), CUDA_ENTRY(12, 5), CUDA_ENTRY(12, 6), + CUDA_ENTRY(12, 8), {"", CudaVersion::NEW, llvm::VersionTuple(std::numeric_limits::max())}, {"unknown", CudaVersion::UNKNOWN, {}} // End of list tombstone. }; @@ -98,6 +99,7 @@ static const OffloadArchToStringMap arch_names[] = { SM(90), // Hopper SM(90a), // Hopper SM(100), // Blackwell + SM(100a), // Blackwell GFX(600), // gfx600 GFX(601), // gfx601 GFX(602), // gfx602 @@ -227,8 +229,8 @@ CudaVersion MinVersionForOffloadArch(OffloadArch A) { case OffloadArch::SM_90a: return CudaVersion::CUDA_120; case OffloadArch::SM_100: - return CudaVersion::NEW; // TODO: use specific CUDA version once it's - // public. + case OffloadArch::SM_100a: + return CudaVersion::CUDA_128; default: llvm_unreachable("invalid enum"); } diff --git a/clang/lib/Basic/DiagnosticIDs.cpp b/clang/lib/Basic/DiagnosticIDs.cpp index 81194bbf2538e..de1de6f61f3a1 100644 --- a/clang/lib/Basic/DiagnosticIDs.cpp +++ b/clang/lib/Basic/DiagnosticIDs.cpp @@ -16,6 +16,7 @@ #include "clang/Basic/SourceManager.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringTable.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Path.h" #include @@ -576,11 +577,7 @@ namespace { uint16_t SubGroups; StringRef Documentation; - // String is stored with a pascal-style length byte. - StringRef getName() const { - return StringRef(DiagGroupNames + NameOffset + 1, - DiagGroupNames[NameOffset]); - } + StringRef getName() const { return DiagGroupNames[NameOffset]; } }; } @@ -627,11 +624,12 @@ StringRef DiagnosticIDs::getWarningOptionForDiag(unsigned DiagID) { std::vector DiagnosticIDs::getDiagnosticFlags() { std::vector Res{"-W", "-Wno-"}; - for (size_t I = 1; DiagGroupNames[I] != '\0';) { - std::string Diag(DiagGroupNames + I + 1, DiagGroupNames[I]); - I += DiagGroupNames[I] + 1; - Res.push_back("-W" + Diag); - Res.push_back("-Wno-" + Diag); + for (StringRef Name : DiagGroupNames) { + if (Name.empty()) + continue; + + Res.push_back((Twine("-W") + Name).str()); + Res.push_back((Twine("-Wno-") + Name).str()); } return Res; diff --git a/clang/lib/Basic/LangOptions.cpp b/clang/lib/Basic/LangOptions.cpp index 94caf6a3897bc..e3037ec819add 100644 --- a/clang/lib/Basic/LangOptions.cpp +++ b/clang/lib/Basic/LangOptions.cpp @@ -208,6 +208,8 @@ void LangOptions::setLangDefaults(LangOptions &Opts, Language Lang, // OpenCL and HLSL have half keyword Opts.Half = Opts.OpenCL || Opts.HLSL; + + Opts.PreserveVec3Type = Opts.HLSL; } FPOptions FPOptions::defaultWithoutTrailingStorage(const LangOptions &LO) { diff --git a/clang/lib/Basic/Targets/NVPTX.cpp b/clang/lib/Basic/Targets/NVPTX.cpp index dbc3fec365761..56efad90cb7c8 100644 --- a/clang/lib/Basic/Targets/NVPTX.cpp +++ b/clang/lib/Basic/Targets/NVPTX.cpp @@ -285,6 +285,7 @@ void NVPTXTargetInfo::getTargetDefines(const LangOptions &Opts, case OffloadArch::SM_90a: return "900"; case OffloadArch::SM_100: + case OffloadArch::SM_100a: return "1000"; } llvm_unreachable("unhandled OffloadArch"); @@ -292,6 +293,8 @@ void NVPTXTargetInfo::getTargetDefines(const LangOptions &Opts, Builder.defineMacro("__CUDA_ARCH__", CUDAArchCode); if (GPU == OffloadArch::SM_90a) Builder.defineMacro("__CUDA_ARCH_FEAT_SM90_ALL", "1"); + if (GPU == OffloadArch::SM_100a) + Builder.defineMacro("__CUDA_ARCH_FEAT_SM100_ALL", "1"); } } diff --git a/clang/lib/CodeGen/ABIInfo.cpp b/clang/lib/CodeGen/ABIInfo.cpp index 642bca9e8b76d..cda8a494f6c27 100644 --- a/clang/lib/CodeGen/ABIInfo.cpp +++ b/clang/lib/CodeGen/ABIInfo.cpp @@ -236,6 +236,14 @@ void ABIInfo::appendAttributeMangling(StringRef AttrStr, } } +llvm::FixedVectorType * +ABIInfo::getOptimalVectorMemoryType(llvm::FixedVectorType *T, + const LangOptions &Opt) const { + if (T->getNumElements() == 3 && !Opt.PreserveVec3Type) + return llvm::FixedVectorType::get(T->getElementType(), 4); + return T; +} + // Pin the vtable to this file. SwiftABIInfo::~SwiftABIInfo() = default; diff --git a/clang/lib/CodeGen/ABIInfo.h b/clang/lib/CodeGen/ABIInfo.h index b8a8de57e5b97..213e7879c3162 100644 --- a/clang/lib/CodeGen/ABIInfo.h +++ b/clang/lib/CodeGen/ABIInfo.h @@ -20,6 +20,7 @@ class Value; class LLVMContext; class DataLayout; class Type; +class FixedVectorType; } // namespace llvm namespace clang { @@ -123,6 +124,13 @@ class ABIInfo { raw_ostream &Out) const; virtual void appendAttributeMangling(StringRef AttrStr, raw_ostream &Out) const; + + /// Returns the optimal vector memory type based on the given vector type. For + /// example, on certain targets, a vector with 3 elements might be promoted to + /// one with 4 elements to improve performance. + virtual llvm::FixedVectorType * + getOptimalVectorMemoryType(llvm::FixedVectorType *T, + const LangOptions &Opt) const; }; /// Target specific hooks for defining how a type should be passed or returned diff --git a/clang/lib/CodeGen/CGAtomic.cpp b/clang/lib/CodeGen/CGAtomic.cpp index f6cb2ad421e90..3adb2a7ad207f 100644 --- a/clang/lib/CodeGen/CGAtomic.cpp +++ b/clang/lib/CodeGen/CGAtomic.cpp @@ -723,6 +723,24 @@ static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, Address Dest, case AtomicExpr::AO__scoped_atomic_fetch_nand: Op = llvm::AtomicRMWInst::Nand; break; + + case AtomicExpr::AO__atomic_test_and_set: { + llvm::AtomicRMWInst *RMWI = + CGF.emitAtomicRMWInst(llvm::AtomicRMWInst::Xchg, Ptr, + CGF.Builder.getInt8(1), Order, Scope, E); + RMWI->setVolatile(E->isVolatile()); + llvm::Value *Result = CGF.Builder.CreateIsNotNull(RMWI, "tobool"); + CGF.Builder.CreateStore(Result, Dest); + return; + } + + case AtomicExpr::AO__atomic_clear: { + llvm::StoreInst *Store = + CGF.Builder.CreateStore(CGF.Builder.getInt8(0), Ptr); + Store->setAtomic(Order, Scope); + Store->setVolatile(E->isVolatile()); + return; + } } llvm::Value *LoadVal1 = CGF.Builder.CreateLoad(Val1); @@ -878,6 +896,8 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { case AtomicExpr::AO__c11_atomic_load: case AtomicExpr::AO__opencl_atomic_load: case AtomicExpr::AO__hip_atomic_load: + case AtomicExpr::AO__atomic_test_and_set: + case AtomicExpr::AO__atomic_clear: break; case AtomicExpr::AO__atomic_load: @@ -1200,6 +1220,8 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { case AtomicExpr::AO__opencl_atomic_fetch_max: case AtomicExpr::AO__scoped_atomic_fetch_max: case AtomicExpr::AO__scoped_atomic_max_fetch: + case AtomicExpr::AO__atomic_test_and_set: + case AtomicExpr::AO__atomic_clear: llvm_unreachable("Integral atomic operations always become atomicrmw!"); } @@ -1239,7 +1261,8 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { E->getOp() == AtomicExpr::AO__atomic_store || E->getOp() == AtomicExpr::AO__atomic_store_n || E->getOp() == AtomicExpr::AO__scoped_atomic_store || - E->getOp() == AtomicExpr::AO__scoped_atomic_store_n; + E->getOp() == AtomicExpr::AO__scoped_atomic_store_n || + E->getOp() == AtomicExpr::AO__atomic_clear; bool IsLoad = E->getOp() == AtomicExpr::AO__c11_atomic_load || E->getOp() == AtomicExpr::AO__opencl_atomic_load || E->getOp() == AtomicExpr::AO__hip_atomic_load || diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 28d9a981d29e5..f1515347fb816 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -68,6 +68,7 @@ #include "llvm/TargetParser/RISCVISAInfo.h" #include "llvm/TargetParser/RISCVTargetParser.h" #include "llvm/TargetParser/X86TargetParser.h" +#include #include #include @@ -5127,147 +5128,6 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, ReturnValueSlot(), Args); } - case Builtin::BI__atomic_test_and_set: { - // Look at the argument type to determine whether this is a volatile - // operation. The parameter type is always volatile. - QualType PtrTy = E->getArg(0)->IgnoreImpCasts()->getType(); - bool Volatile = - PtrTy->castAs()->getPointeeType().isVolatileQualified(); - - Address Ptr = - EmitPointerWithAlignment(E->getArg(0)).withElementType(Int8Ty); - - Value *NewVal = Builder.getInt8(1); - Value *Order = EmitScalarExpr(E->getArg(1)); - if (isa(Order)) { - int ord = cast(Order)->getZExtValue(); - AtomicRMWInst *Result = nullptr; - switch (ord) { - case 0: // memory_order_relaxed - default: // invalid order - Result = Builder.CreateAtomicRMW(llvm::AtomicRMWInst::Xchg, Ptr, NewVal, - llvm::AtomicOrdering::Monotonic); - break; - case 1: // memory_order_consume - case 2: // memory_order_acquire - Result = Builder.CreateAtomicRMW(llvm::AtomicRMWInst::Xchg, Ptr, NewVal, - llvm::AtomicOrdering::Acquire); - break; - case 3: // memory_order_release - Result = Builder.CreateAtomicRMW(llvm::AtomicRMWInst::Xchg, Ptr, NewVal, - llvm::AtomicOrdering::Release); - break; - case 4: // memory_order_acq_rel - - Result = Builder.CreateAtomicRMW(llvm::AtomicRMWInst::Xchg, Ptr, NewVal, - llvm::AtomicOrdering::AcquireRelease); - break; - case 5: // memory_order_seq_cst - Result = Builder.CreateAtomicRMW( - llvm::AtomicRMWInst::Xchg, Ptr, NewVal, - llvm::AtomicOrdering::SequentiallyConsistent); - break; - } - Result->setVolatile(Volatile); - return RValue::get(Builder.CreateIsNotNull(Result, "tobool")); - } - - llvm::BasicBlock *ContBB = createBasicBlock("atomic.continue", CurFn); - - llvm::BasicBlock *BBs[5] = { - createBasicBlock("monotonic", CurFn), - createBasicBlock("acquire", CurFn), - createBasicBlock("release", CurFn), - createBasicBlock("acqrel", CurFn), - createBasicBlock("seqcst", CurFn) - }; - llvm::AtomicOrdering Orders[5] = { - llvm::AtomicOrdering::Monotonic, llvm::AtomicOrdering::Acquire, - llvm::AtomicOrdering::Release, llvm::AtomicOrdering::AcquireRelease, - llvm::AtomicOrdering::SequentiallyConsistent}; - - Order = Builder.CreateIntCast(Order, Builder.getInt32Ty(), false); - llvm::SwitchInst *SI = Builder.CreateSwitch(Order, BBs[0]); - - Builder.SetInsertPoint(ContBB); - PHINode *Result = Builder.CreatePHI(Int8Ty, 5, "was_set"); - - for (unsigned i = 0; i < 5; ++i) { - Builder.SetInsertPoint(BBs[i]); - AtomicRMWInst *RMW = Builder.CreateAtomicRMW(llvm::AtomicRMWInst::Xchg, - Ptr, NewVal, Orders[i]); - RMW->setVolatile(Volatile); - Result->addIncoming(RMW, BBs[i]); - Builder.CreateBr(ContBB); - } - - SI->addCase(Builder.getInt32(0), BBs[0]); - SI->addCase(Builder.getInt32(1), BBs[1]); - SI->addCase(Builder.getInt32(2), BBs[1]); - SI->addCase(Builder.getInt32(3), BBs[2]); - SI->addCase(Builder.getInt32(4), BBs[3]); - SI->addCase(Builder.getInt32(5), BBs[4]); - - Builder.SetInsertPoint(ContBB); - return RValue::get(Builder.CreateIsNotNull(Result, "tobool")); - } - - case Builtin::BI__atomic_clear: { - QualType PtrTy = E->getArg(0)->IgnoreImpCasts()->getType(); - bool Volatile = - PtrTy->castAs()->getPointeeType().isVolatileQualified(); - - Address Ptr = EmitPointerWithAlignment(E->getArg(0)); - Ptr = Ptr.withElementType(Int8Ty); - Value *NewVal = Builder.getInt8(0); - Value *Order = EmitScalarExpr(E->getArg(1)); - if (isa(Order)) { - int ord = cast(Order)->getZExtValue(); - StoreInst *Store = Builder.CreateStore(NewVal, Ptr, Volatile); - switch (ord) { - case 0: // memory_order_relaxed - default: // invalid order - Store->setOrdering(llvm::AtomicOrdering::Monotonic); - break; - case 3: // memory_order_release - Store->setOrdering(llvm::AtomicOrdering::Release); - break; - case 5: // memory_order_seq_cst - Store->setOrdering(llvm::AtomicOrdering::SequentiallyConsistent); - break; - } - return RValue::get(nullptr); - } - - llvm::BasicBlock *ContBB = createBasicBlock("atomic.continue", CurFn); - - llvm::BasicBlock *BBs[3] = { - createBasicBlock("monotonic", CurFn), - createBasicBlock("release", CurFn), - createBasicBlock("seqcst", CurFn) - }; - llvm::AtomicOrdering Orders[3] = { - llvm::AtomicOrdering::Monotonic, llvm::AtomicOrdering::Release, - llvm::AtomicOrdering::SequentiallyConsistent}; - - Order = Builder.CreateIntCast(Order, Builder.getInt32Ty(), false); - llvm::SwitchInst *SI = Builder.CreateSwitch(Order, BBs[0]); - - for (unsigned i = 0; i < 3; ++i) { - Builder.SetInsertPoint(BBs[i]); - StoreInst *Store = Builder.CreateStore(NewVal, Ptr, Volatile); - Store->setOrdering(Orders[i]); - Builder.CreateBr(ContBB); - } - - SI->addCase(Builder.getInt32(0), BBs[0]); - SI->addCase(Builder.getInt32(3), BBs[1]); - SI->addCase(Builder.getInt32(5), BBs[2]); - - Builder.SetInsertPoint(ContBB); - return RValue::get(nullptr); - } - case Builtin::BI__atomic_thread_fence: case Builtin::BI__atomic_signal_fence: case Builtin::BI__c11_atomic_thread_fence: @@ -19332,9 +19192,9 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID, assert(T0->isVectorTy() && T1->isVectorTy() && "Dot product of vector and scalar is not supported."); - auto *VecTy0 = E->getArg(0)->getType()->getAs(); + auto *VecTy0 = E->getArg(0)->getType()->castAs(); [[maybe_unused]] auto *VecTy1 = - E->getArg(1)->getType()->getAs(); + E->getArg(1)->getType()->castAs(); assert(VecTy0->getElementType() == VecTy1->getElementType() && "Dot product of vectors need the same element types."); @@ -19427,7 +19287,7 @@ case Builtin::BI__builtin_hlsl_elementwise_isinf: { llvm::Type *Xty = Op0->getType(); llvm::Type *retType = llvm::Type::getInt1Ty(this->getLLVMContext()); if (Xty->isVectorTy()) { - auto *XVecTy = E->getArg(0)->getType()->getAs(); + auto *XVecTy = E->getArg(0)->getType()->castAs(); retType = llvm::VectorType::get( retType, ElementCount::getFixed(XVecTy->getNumElements())); } @@ -19613,7 +19473,7 @@ case Builtin::BI__builtin_hlsl_elementwise_isinf: { llvm::Type *Xty = Op0->getType(); llvm::Type *retType = llvm::Type::getInt32Ty(this->getLLVMContext()); if (Xty->isVectorTy()) { - auto *XVecTy = Arg0->getType()->getAs(); + auto *XVecTy = Arg0->getType()->castAs(); retType = llvm::VectorType::get( retType, ElementCount::getFixed(XVecTy->getNumElements())); } diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 9a9a8c7f6eae0..054f8d1eadb8c 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -46,6 +46,7 @@ #include "llvm/Support/xxhash.h" #include "llvm/Transforms/Utils/SanitizerStats.h" +#include #include #include @@ -2002,20 +2003,19 @@ llvm::Value *CodeGenFunction::EmitLoadOfScalar(Address Addr, bool Volatile, return EmitFromMemory(V, Ty); } - // Handle vectors of size 3 like size 4 for better performance. - const llvm::Type *EltTy = Addr.getElementType(); - const auto *VTy = cast(EltTy); - - if (!CGM.getCodeGenOpts().PreserveVec3Type && VTy->getNumElements() == 3) { - - llvm::VectorType *vec4Ty = - llvm::FixedVectorType::get(VTy->getElementType(), 4); - Address Cast = Addr.withElementType(vec4Ty); - // Now load value. - llvm::Value *V = Builder.CreateLoad(Cast, Volatile, "loadVec4"); - - // Shuffle vector to get vec3. - V = Builder.CreateShuffleVector(V, ArrayRef{0, 1, 2}, "extractVec"); + // Handles vectors of sizes that are likely to be expanded to a larger size + // to optimize performance. + auto *VTy = cast(Addr.getElementType()); + auto *NewVecTy = + CGM.getABIInfo().getOptimalVectorMemoryType(VTy, getLangOpts()); + + if (VTy != NewVecTy) { + Address Cast = Addr.withElementType(NewVecTy); + llvm::Value *V = Builder.CreateLoad(Cast, Volatile, "loadVecN"); + unsigned OldNumElements = VTy->getNumElements(); + SmallVector Mask(OldNumElements); + std::iota(Mask.begin(), Mask.end(), 0); + V = Builder.CreateShuffleVector(V, Mask, "extractVec"); return EmitFromMemory(V, Ty); } } @@ -2145,21 +2145,21 @@ void CodeGenFunction::EmitStoreOfScalar(llvm::Value *Value, Address Addr, Addr = Addr.withPointer(Builder.CreateThreadLocalAddress(GV), NotKnownNonNull); + // Handles vectors of sizes that are likely to be expanded to a larger size + // to optimize performance. llvm::Type *SrcTy = Value->getType(); if (const auto *ClangVecTy = Ty->getAs()) { - auto *VecTy = dyn_cast(SrcTy); - if (!CGM.getCodeGenOpts().PreserveVec3Type) { - // Handle vec3 special. - if (VecTy && !ClangVecTy->isExtVectorBoolType() && - cast(VecTy)->getNumElements() == 3) { - // Our source is a vec3, do a shuffle vector to make it a vec4. - Value = Builder.CreateShuffleVector(Value, ArrayRef{0, 1, 2, -1}, - "extractVec"); - SrcTy = llvm::FixedVectorType::get(VecTy->getElementType(), 4); + if (auto *VecTy = dyn_cast(SrcTy)) { + auto *NewVecTy = + CGM.getABIInfo().getOptimalVectorMemoryType(VecTy, getLangOpts()); + if (!ClangVecTy->isExtVectorBoolType() && VecTy != NewVecTy) { + SmallVector Mask(NewVecTy->getNumElements(), -1); + std::iota(Mask.begin(), Mask.begin() + VecTy->getNumElements(), 0); + Value = Builder.CreateShuffleVector(Value, Mask, "extractVec"); + SrcTy = NewVecTy; } - if (Addr.getElementType() != SrcTy) { + if (Addr.getElementType() != SrcTy) Addr = Addr.withElementType(SrcTy); - } } } diff --git a/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp b/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp index 87c3635ed3f70..c13928f61a748 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp +++ b/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp @@ -2277,6 +2277,7 @@ void CGOpenMPRuntimeGPU::processRequiresDirective(const OMPRequiresDecl *D) { case OffloadArch::SM_90: case OffloadArch::SM_90a: case OffloadArch::SM_100: + case OffloadArch::SM_100a: case OffloadArch::GFX600: case OffloadArch::GFX601: case OffloadArch::GFX602: diff --git a/clang/lib/CodeGen/Targets/AMDGPU.cpp b/clang/lib/CodeGen/Targets/AMDGPU.cpp index fa07e68c55835..788eac5f28231 100644 --- a/clang/lib/CodeGen/Targets/AMDGPU.cpp +++ b/clang/lib/CodeGen/Targets/AMDGPU.cpp @@ -52,6 +52,17 @@ class AMDGPUABIInfo final : public DefaultABIInfo { void computeInfo(CGFunctionInfo &FI) const override; RValue EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty, AggValueSlot Slot) const override; + + llvm::FixedVectorType * + getOptimalVectorMemoryType(llvm::FixedVectorType *T, + const LangOptions &Opt) const override { + // We have legal instructions for 96-bit so 3x32 can be supported. + // FIXME: This check should be a subtarget feature as technically SI doesn't + // support it. + if (T->getNumElements() == 3 && getDataLayout().getTypeSizeInBits(T) == 96) + return T; + return DefaultABIInfo::getOptimalVectorMemoryType(T, Opt); + } }; bool AMDGPUABIInfo::isHomogeneousAggregateBaseType(QualType Ty) const { diff --git a/clang/lib/Driver/ToolChains/Arch/LoongArch.cpp b/clang/lib/Driver/ToolChains/Arch/LoongArch.cpp index bbd9397aa2378..c9b45ce58bd4c 100644 --- a/clang/lib/Driver/ToolChains/Arch/LoongArch.cpp +++ b/clang/lib/Driver/ToolChains/Arch/LoongArch.cpp @@ -181,10 +181,6 @@ void loongarch::getLoongArchTargetFeatures(const Driver &D, } } - // Select the `ual` feature determined by -m[no-]strict-align. - AddTargetFeature(Args, Features, options::OPT_mno_strict_align, - options::OPT_mstrict_align, "ual"); - // Accept but warn about these TargetSpecific options. if (Arg *A = Args.getLastArgNoClaim(options::OPT_mabi_EQ)) A->ignoreTargetSpecific(); @@ -257,50 +253,20 @@ void loongarch::getLoongArchTargetFeatures(const Driver &D, Features.push_back("-lasx"); } - // Select frecipe feature determined by -m[no-]frecipe. - if (const Arg *A = - Args.getLastArg(options::OPT_mfrecipe, options::OPT_mno_frecipe)) { - if (A->getOption().matches(options::OPT_mfrecipe)) - Features.push_back("+frecipe"); - else - Features.push_back("-frecipe"); - } - - // Select lam-bh feature determined by -m[no-]lam-bh. - if (const Arg *A = - Args.getLastArg(options::OPT_mlam_bh, options::OPT_mno_lam_bh)) { - if (A->getOption().matches(options::OPT_mlam_bh)) - Features.push_back("+lam-bh"); - else - Features.push_back("-lam-bh"); - } - - // Select lamcas feature determined by -m[no-]lamcas. - if (const Arg *A = - Args.getLastArg(options::OPT_mlamcas, options::OPT_mno_lamcas)) { - if (A->getOption().matches(options::OPT_mlamcas)) - Features.push_back("+lamcas"); - else - Features.push_back("-lamcas"); - } - - // Select ld-seq-sa feature determined by -m[no-]ld-seq-sa. - if (const Arg *A = Args.getLastArg(options::OPT_mld_seq_sa, - options::OPT_mno_ld_seq_sa)) { - if (A->getOption().matches(options::OPT_mld_seq_sa)) - Features.push_back("+ld-seq-sa"); - else - Features.push_back("-ld-seq-sa"); - } - - // Select div32 feature determined by -m[no-]div32. - if (const Arg *A = - Args.getLastArg(options::OPT_mdiv32, options::OPT_mno_div32)) { - if (A->getOption().matches(options::OPT_mdiv32)) - Features.push_back("+div32"); - else - Features.push_back("-div32"); - } + AddTargetFeature(Args, Features, options::OPT_mno_strict_align, + options::OPT_mstrict_align, "ual"); + AddTargetFeature(Args, Features, options::OPT_mno_strict_align, + options::OPT_mstrict_align, "ual"); + AddTargetFeature(Args, Features, options::OPT_mfrecipe, + options::OPT_mno_frecipe, "frecipe"); + AddTargetFeature(Args, Features, options::OPT_mlam_bh, + options::OPT_mno_lam_bh, "lam-bh"); + AddTargetFeature(Args, Features, options::OPT_mlamcas, + options::OPT_mno_lamcas, "lamcas"); + AddTargetFeature(Args, Features, options::OPT_mld_seq_sa, + options::OPT_mno_ld_seq_sa, "ld-seq-sa"); + AddTargetFeature(Args, Features, options::OPT_mdiv32, + options::OPT_mno_div32, "div32"); } std::string loongarch::postProcessTargetCPUString(const std::string &CPU, diff --git a/clang/lib/Driver/ToolChains/Arch/Mips.cpp b/clang/lib/Driver/ToolChains/Arch/Mips.cpp index 6a2f7936fca39..ca0745fc2b32d 100644 --- a/clang/lib/Driver/ToolChains/Arch/Mips.cpp +++ b/clang/lib/Driver/ToolChains/Arch/Mips.cpp @@ -366,9 +366,6 @@ void mips::getMIPSTargetFeatures(const Driver &D, const llvm::Triple &Triple, } else if (mips::shouldUseFPXX(Args, Triple, CPUName, ABIName, FloatABI)) { Features.push_back("+fpxx"); Features.push_back("+nooddspreg"); - } else if (mips::isFP64ADefault(Triple, CPUName)) { - Features.push_back("+fp64"); - Features.push_back("+nooddspreg"); } else if (Arg *A = Args.getLastArg(options::OPT_mmsa)) { if (A->getOption().matches(options::OPT_mmsa)) Features.push_back("+fp64"); @@ -465,16 +462,6 @@ bool mips::isNaN2008(const Driver &D, const ArgList &Args, .Default(false); } -bool mips::isFP64ADefault(const llvm::Triple &Triple, StringRef CPUName) { - if (!Triple.isAndroid()) - return false; - - // Android MIPS32R6 defaults to FP64A. - return llvm::StringSwitch(CPUName) - .Case("mips32r6", true) - .Default(false); -} - bool mips::isFPXXDefault(const llvm::Triple &Triple, StringRef CPUName, StringRef ABIName, mips::FloatABI FloatABI) { if (ABIName != "32") diff --git a/clang/lib/Driver/ToolChains/Arch/Mips.h b/clang/lib/Driver/ToolChains/Arch/Mips.h index 674c21744b523..058e82b09831a 100644 --- a/clang/lib/Driver/ToolChains/Arch/Mips.h +++ b/clang/lib/Driver/ToolChains/Arch/Mips.h @@ -46,7 +46,6 @@ bool hasMipsAbiArg(const llvm::opt::ArgList &Args, const char *Value); bool isUCLibc(const llvm::opt::ArgList &Args); bool isNaN2008(const Driver &D, const llvm::opt::ArgList &Args, const llvm::Triple &Triple); -bool isFP64ADefault(const llvm::Triple &Triple, StringRef CPUName); bool isFPXXDefault(const llvm::Triple &Triple, StringRef CPUName, StringRef ABIName, mips::FloatABI FloatABI); bool shouldUseFPXX(const llvm::opt::ArgList &Args, const llvm::Triple &Triple, diff --git a/clang/lib/Driver/ToolChains/Cuda.cpp b/clang/lib/Driver/ToolChains/Cuda.cpp index 8967115bcc73d..d4099216c81ba 100644 --- a/clang/lib/Driver/ToolChains/Cuda.cpp +++ b/clang/lib/Driver/ToolChains/Cuda.cpp @@ -89,6 +89,8 @@ CudaVersion getCudaVersion(uint32_t raw_version) { return CudaVersion::CUDA_125; if (raw_version < 12070) return CudaVersion::CUDA_126; + if (raw_version < 12090) + return CudaVersion::CUDA_128; return CudaVersion::NEW; } @@ -682,6 +684,7 @@ void NVPTX::getNVPTXTargetFeatures(const Driver &D, const llvm::Triple &Triple, case CudaVersion::CUDA_##CUDA_VER: \ PtxFeature = "+ptx" #PTX_VER; \ break; + CASE_CUDA_VERSION(128, 87); CASE_CUDA_VERSION(126, 85); CASE_CUDA_VERSION(125, 85); CASE_CUDA_VERSION(124, 84); diff --git a/clang/lib/Driver/ToolChains/Darwin.cpp b/clang/lib/Driver/ToolChains/Darwin.cpp index 84ef8199de049..55c55bad73934 100644 --- a/clang/lib/Driver/ToolChains/Darwin.cpp +++ b/clang/lib/Driver/ToolChains/Darwin.cpp @@ -2164,7 +2164,8 @@ inferDeploymentTargetFromArch(DerivedArgList &Args, const Darwin &Toolchain, StringRef MachOArchName = Toolchain.getMachOArchName(Args); if (MachOArchName == "arm64" || MachOArchName == "arm64e") OSTy = llvm::Triple::MacOSX; - else if (MachOArchName == "armv7" || MachOArchName == "armv7s") + else if (MachOArchName == "armv7" || MachOArchName == "armv7s" || + MachOArchName == "armv6") OSTy = llvm::Triple::IOS; else if (MachOArchName == "armv7k" || MachOArchName == "arm64_32") OSTy = llvm::Triple::WatchOS; diff --git a/clang/lib/Driver/ToolChains/Gnu.cpp b/clang/lib/Driver/ToolChains/Gnu.cpp index e5db1b2f1550b..6dfa94bf2123b 100644 --- a/clang/lib/Driver/ToolChains/Gnu.cpp +++ b/clang/lib/Driver/ToolChains/Gnu.cpp @@ -1146,53 +1146,6 @@ static bool findMipsCsMultilibs(const Driver &D, return false; } -static bool findMipsAndroidMultilibs(const Driver &D, - llvm::vfs::FileSystem &VFS, StringRef Path, - const Multilib::flags_list &Flags, - FilterNonExistent &NonExistent, - DetectedMultilibs &Result) { - - MultilibSet AndroidMipsMultilibs = - MultilibSetBuilder() - .Maybe(MultilibBuilder("/mips-r2", {}, {}).flag("-march=mips32r2")) - .Maybe(MultilibBuilder("/mips-r6", {}, {}).flag("-march=mips32r6")) - .makeMultilibSet() - .FilterOut(NonExistent); - - MultilibSet AndroidMipselMultilibs = - MultilibSetBuilder() - .Either(MultilibBuilder().flag("-march=mips32"), - MultilibBuilder("/mips-r2", "", "/mips-r2") - .flag("-march=mips32r2"), - MultilibBuilder("/mips-r6", "", "/mips-r6") - .flag("-march=mips32r6")) - .makeMultilibSet() - .FilterOut(NonExistent); - - MultilibSet AndroidMips64elMultilibs = - MultilibSetBuilder() - .Either(MultilibBuilder().flag("-march=mips64r6"), - MultilibBuilder("/32/mips-r1", "", "/mips-r1") - .flag("-march=mips32"), - MultilibBuilder("/32/mips-r2", "", "/mips-r2") - .flag("-march=mips32r2"), - MultilibBuilder("/32/mips-r6", "", "/mips-r6") - .flag("-march=mips32r6")) - .makeMultilibSet() - .FilterOut(NonExistent); - - MultilibSet *MS = &AndroidMipsMultilibs; - if (VFS.exists(Path + "/mips-r6")) - MS = &AndroidMipselMultilibs; - else if (VFS.exists(Path + "/32")) - MS = &AndroidMips64elMultilibs; - if (MS->select(D, Flags, Result.SelectedMultilibs)) { - Result.Multilibs = *MS; - return true; - } - return false; -} - static bool findMipsMuslMultilibs(const Driver &D, const Multilib::flags_list &Flags, FilterNonExistent &NonExistent, @@ -1560,10 +1513,6 @@ bool clang::driver::findMIPSMultilibs(const Driver &D, addMultilibFlag(isMipsEL(TargetArch), "-EL", Flags); addMultilibFlag(!isMipsEL(TargetArch), "-EB", Flags); - if (TargetTriple.isAndroid()) - return findMipsAndroidMultilibs(D, D.getVFS(), Path, Flags, NonExistent, - Result); - if (TargetTriple.getVendor() == llvm::Triple::MipsTechnologies && TargetTriple.getOS() == llvm::Triple::Linux && TargetTriple.getEnvironment() == llvm::Triple::UnknownEnvironment) diff --git a/clang/lib/Driver/ToolChains/HIPUtility.cpp b/clang/lib/Driver/ToolChains/HIPUtility.cpp index bfb6ec7a01058..dfe9acc1ec795 100644 --- a/clang/lib/Driver/ToolChains/HIPUtility.cpp +++ b/clang/lib/Driver/ToolChains/HIPUtility.cpp @@ -466,11 +466,11 @@ void HIP::constructGenerateObjFileFromHIPFatBinary( Objf << ObjBuffer; - ArgStringList McArgs{"-target", Args.MakeArgString(HostTriple.normalize()), + ArgStringList ClangArgs{"-target", Args.MakeArgString(HostTriple.normalize()), "-o", Output.getFilename(), "-x", "assembler", ObjinFile, "-c"}; C.addCommand(std::make_unique(JA, T, ResponseFileSupport::None(), - D.getClangProgramPath(), McArgs, + D.getClangProgramPath(), ClangArgs, Inputs, Output, D.getPrependArg())); } diff --git a/clang/lib/Driver/ToolChains/PS4CPU.cpp b/clang/lib/Driver/ToolChains/PS4CPU.cpp index fd4c2f9bf68cd..e1187ce48c3e4 100644 --- a/clang/lib/Driver/ToolChains/PS4CPU.cpp +++ b/clang/lib/Driver/ToolChains/PS4CPU.cpp @@ -490,7 +490,7 @@ toolchains::PS4PS5Base::PS4PS5Base(const Driver &D, const llvm::Triple &Triple, bool Linking = !Args.hasArg(options::OPT_E, options::OPT_c, options::OPT_S, options::OPT_emit_ast); - if (!CustomSysroot && Linking) { + if (Linking) { SmallString<128> Dir(SDKLibraryRootDir); llvm::sys::path::append(Dir, "target/lib"); if (CheckSDKPartExists(Dir, "system libraries")) diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index 6826fa76662cf..c25d9bf7c2251 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -1040,7 +1040,6 @@ template <> struct MappingTraits { Style.EmptyLineBeforeAccessModifier); IO.mapOptional("ExperimentalAutoDetectBinPacking", Style.ExperimentalAutoDetectBinPacking); - IO.mapOptional("ExportBlockIndentation", Style.ExportBlockIndentation); IO.mapOptional("FixNamespaceComments", Style.FixNamespaceComments); IO.mapOptional("ForEachMacros", Style.ForEachMacros); IO.mapOptional("IfMacros", Style.IfMacros); @@ -1052,6 +1051,7 @@ template <> struct MappingTraits { IO.mapOptional("IndentAccessModifiers", Style.IndentAccessModifiers); IO.mapOptional("IndentCaseBlocks", Style.IndentCaseBlocks); IO.mapOptional("IndentCaseLabels", Style.IndentCaseLabels); + IO.mapOptional("IndentExportBlock", Style.IndentExportBlock); IO.mapOptional("IndentExternBlock", Style.IndentExternBlock); IO.mapOptional("IndentGotoLabels", Style.IndentGotoLabels); IO.mapOptional("IndentPPDirectives", Style.IndentPPDirectives); @@ -1551,7 +1551,6 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.EmptyLineAfterAccessModifier = FormatStyle::ELAAMS_Never; LLVMStyle.EmptyLineBeforeAccessModifier = FormatStyle::ELBAMS_LogicalBlock; LLVMStyle.ExperimentalAutoDetectBinPacking = false; - LLVMStyle.ExportBlockIndentation = true; LLVMStyle.FixNamespaceComments = true; LLVMStyle.ForEachMacros.push_back("foreach"); LLVMStyle.ForEachMacros.push_back("Q_FOREACH"); @@ -1567,6 +1566,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.IndentAccessModifiers = false; LLVMStyle.IndentCaseBlocks = false; LLVMStyle.IndentCaseLabels = false; + LLVMStyle.IndentExportBlock = true; LLVMStyle.IndentExternBlock = FormatStyle::IEBS_AfterExternBlock; LLVMStyle.IndentGotoLabels = true; LLVMStyle.IndentPPDirectives = FormatStyle::PPDIS_None; diff --git a/clang/lib/Format/QualifierAlignmentFixer.cpp b/clang/lib/Format/QualifierAlignmentFixer.cpp index 530b2dd538cee..21fb5074b4928 100644 --- a/clang/lib/Format/QualifierAlignmentFixer.cpp +++ b/clang/lib/Format/QualifierAlignmentFixer.cpp @@ -386,7 +386,8 @@ const FormatToken *LeftRightQualifierAlignmentFixer::analyzeLeft( // For left qualifiers preceeded by nothing, a template declaration, or *,&,&& // we only perform sorting. if (!TypeToken || TypeToken->isPointerOrReference() || - TypeToken->ClosesRequiresClause || TypeToken->ClosesTemplateDeclaration) { + TypeToken->ClosesRequiresClause || TypeToken->ClosesTemplateDeclaration || + TypeToken->is(tok::r_square)) { // Don't sort past a non-configured qualifier token. const FormatToken *FirstQual = Tok; diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp index 834693e2ecf0c..4258329136348 100644 --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -3167,8 +3167,7 @@ void UnwrappedLineParser::parseNamespace() { } void UnwrappedLineParser::parseCppExportBlock() { - parseNamespaceOrExportBlock(/*AddLevels=*/Style.ExportBlockIndentation ? 1 - : 0); + parseNamespaceOrExportBlock(/*AddLevels=*/Style.IndentExportBlock ? 1 : 0); } void UnwrappedLineParser::parseNew() { diff --git a/clang/lib/Headers/avx10_2_512minmaxintrin.h b/clang/lib/Headers/avx10_2_512minmaxintrin.h index e175365d11df8..fbc7fbadbc6b2 100644 --- a/clang/lib/Headers/avx10_2_512minmaxintrin.h +++ b/clang/lib/Headers/avx10_2_512minmaxintrin.h @@ -14,22 +14,22 @@ #ifndef __AVX10_2_512MINMAXINTRIN_H #define __AVX10_2_512MINMAXINTRIN_H -#define _mm512_minmaxne_pbh(A, B, C) \ - ((__m512bh)__builtin_ia32_vminmaxnepbf16512( \ - (__v32bf)(__m512bh)(A), (__v32bf)(__m512bh)(A), (int)(C))) +#define _mm512_minmax_pbh(A, B, C) \ + ((__m512bh)__builtin_ia32_vminmaxbf16512((__v32bf)(__m512bh)(A), \ + (__v32bf)(__m512bh)(A), (int)(C))) -#define _mm512_mask_minmaxne_pbh(W, U, A, B, C) \ +#define _mm512_mask_minmax_pbh(W, U, A, B, C) \ ((__m512bh)__builtin_ia32_selectpbf_512( \ (__mmask32)(U), \ - (__v32bf)_mm512_minmaxne_pbh((__v32bf)(__m512bh)(A), \ - (__v32bf)(__m512bh)(B), (int)(C)), \ + (__v32bf)_mm512_minmax_pbh((__v32bf)(__m512bh)(A), \ + (__v32bf)(__m512bh)(B), (int)(C)), \ (__v32bf)(__m512bh)(W))) -#define _mm512_maskz_minmaxne_pbh(U, A, B, C) \ +#define _mm512_maskz_minmax_pbh(U, A, B, C) \ ((__m512bh)__builtin_ia32_selectpbf_512( \ (__mmask32)(U), \ - (__v32bf)_mm512_minmaxne_pbh((__v32bf)(__m512bh)(A), \ - (__v32bf)(__m512bh)(B), (int)(C)), \ + (__v32bf)_mm512_minmax_pbh((__v32bf)(__m512bh)(A), \ + (__v32bf)(__m512bh)(B), (int)(C)), \ (__v32bf) __builtin_bit_cast(__m512bh, _mm512_setzero_ps()))) #define _mm512_minmax_pd(A, B, C) \ diff --git a/clang/lib/Headers/avx10_2minmaxintrin.h b/clang/lib/Headers/avx10_2minmaxintrin.h index a9367e7424658..8164d49d89f1f 100644 --- a/clang/lib/Headers/avx10_2minmaxintrin.h +++ b/clang/lib/Headers/avx10_2minmaxintrin.h @@ -14,40 +14,40 @@ #ifndef __AVX10_2MINMAXINTRIN_H #define __AVX10_2MINMAXINTRIN_H -#define _mm_minmaxne_pbh(A, B, C) \ - ((__m128bh)__builtin_ia32_vminmaxnepbf16128( \ - (__m128bh)(__v8bf)(A), (__m128bh)(__v8bf)(B), (int)(C))) +#define _mm_minmax_pbh(A, B, C) \ + ((__m128bh)__builtin_ia32_vminmaxbf16128((__m128bh)(__v8bf)(A), \ + (__m128bh)(__v8bf)(B), (int)(C))) -#define _mm_mask_minmaxne_pbh(W, U, A, B, C) \ +#define _mm_mask_minmax_pbh(W, U, A, B, C) \ ((__m128bh)__builtin_ia32_selectpbf_128( \ (__mmask8)(U), \ - (__v8bf)_mm_minmaxne_pbh((__m128bh)(__v8bf)(A), (__m128bh)(__v8bf)(B), \ - (int)(C)), \ + (__v8bf)_mm_minmax_pbh((__m128bh)(__v8bf)(A), (__m128bh)(__v8bf)(B), \ + (int)(C)), \ (__v8bf)(W))) -#define _mm_maskz_minmaxne_pbh(U, A, B, C) \ +#define _mm_maskz_minmax_pbh(U, A, B, C) \ ((__m128bh)__builtin_ia32_selectpbf_128( \ (__mmask8)(U), \ - (__v8bf)_mm_minmaxne_pbh((__m128bh)(__v8bf)(A), (__m128bh)(__v8bf)(B), \ - (int)(C)), \ + (__v8bf)_mm_minmax_pbh((__m128bh)(__v8bf)(A), (__m128bh)(__v8bf)(B), \ + (int)(C)), \ (__v8bf) __builtin_bit_cast(__m128bh, _mm_setzero_ps()))) -#define _mm256_minmaxne_pbh(A, B, C) \ - ((__m256bh)__builtin_ia32_vminmaxnepbf16256( \ - (__m256bh)(__v16bf)(A), (__m256bh)(__v16bf)(B), (int)(C))) +#define _mm256_minmax_pbh(A, B, C) \ + ((__m256bh)__builtin_ia32_vminmaxbf16256((__m256bh)(__v16bf)(A), \ + (__m256bh)(__v16bf)(B), (int)(C))) -#define _mm256_mask_minmaxne_pbh(W, U, A, B, C) \ +#define _mm256_mask_minmax_pbh(W, U, A, B, C) \ ((__m256bh)__builtin_ia32_selectpbf_256( \ (__mmask16)(U), \ - (__v16bf)_mm256_minmaxne_pbh((__m256bh)(__v16bf)(A), \ - (__m256bh)(__v16bf)(B), (int)(C)), \ + (__v16bf)_mm256_minmax_pbh((__m256bh)(__v16bf)(A), \ + (__m256bh)(__v16bf)(B), (int)(C)), \ (__v16bf)(W))) -#define _mm256_maskz_minmaxne_pbh(U, A, B, C) \ +#define _mm256_maskz_minmax_pbh(U, A, B, C) \ ((__m256bh)__builtin_ia32_selectpbf_256( \ (__mmask16)(U), \ - (__v16bf)_mm256_minmaxne_pbh((__m256bh)(__v16bf)(A), \ - (__m256bh)(__v16bf)(B), (int)(C)), \ + (__v16bf)_mm256_minmax_pbh((__m256bh)(__v16bf)(A), \ + (__m256bh)(__v16bf)(B), (int)(C)), \ (__v16bf) __builtin_bit_cast(__m256bh, _mm256_setzero_ps()))) #define _mm_minmax_pd(A, B, C) \ diff --git a/clang/lib/Lex/Lexer.cpp b/clang/lib/Lex/Lexer.cpp index 115b6c1606a02..087c6f13aea66 100644 --- a/clang/lib/Lex/Lexer.cpp +++ b/clang/lib/Lex/Lexer.cpp @@ -1352,6 +1352,27 @@ std::optional Lexer::findNextToken(SourceLocation Loc, return Tok; } +std::optional Lexer::findPreviousToken(SourceLocation Loc, + const SourceManager &SM, + const LangOptions &LangOpts, + bool IncludeComments) { + const auto StartOfFile = SM.getLocForStartOfFile(SM.getFileID(Loc)); + while (Loc != StartOfFile) { + Loc = Loc.getLocWithOffset(-1); + if (Loc.isInvalid()) + return std::nullopt; + + Loc = GetBeginningOfToken(Loc, SM, LangOpts); + Token Tok; + if (getRawToken(Loc, Tok, SM, LangOpts)) + continue; // Not a token, go to prev location. + if (!Tok.is(tok::comment) || IncludeComments) { + return Tok; + } + } + return std::nullopt; +} + /// Checks that the given token is the first token that occurs after the /// given location (this excludes comments and whitespace). Returns the location /// immediately after the specified token. If the token is not found or the diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index 8dd72db8f5b4a..aa8b3870a188c 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -248,6 +248,25 @@ ExprResult Parser::ParseArrayBoundExpression() { // If we parse the bound of a VLA... we parse a non-constant // constant-expression! Actions.ExprEvalContexts.back().InConditionallyConstantEvaluateContext = true; + // For a VLA type inside an unevaluated operator like: + // + // sizeof(typeof(*(int (*)[N])array)) + // + // N and array are supposed to be ODR-used. + // Initially when encountering `array`, it is deemed unevaluated and non-ODR + // used because that occurs before parsing the type cast. Therefore we use + // Sema::TransformToPotentiallyEvaluated() to rebuild the expression to ensure + // it's actually ODR-used. + // + // However, in other unevaluated contexts as in constraint substitution, it + // would end up rebuilding the type twice which is unnecessary. So we push up + // a flag to help distinguish these cases. + for (auto Iter = Actions.ExprEvalContexts.rbegin() + 1; + Iter != Actions.ExprEvalContexts.rend(); ++Iter) { + if (!Iter->isUnevaluated()) + break; + Iter->InConditionallyConstantEvaluateContext = true; + } return ParseConstantExpressionInExprEvalContext(NotTypeCast); } diff --git a/clang/lib/Sema/CheckExprLifetime.cpp b/clang/lib/Sema/CheckExprLifetime.cpp index 27e6b5b2cb393..8963cad86dbca 100644 --- a/clang/lib/Sema/CheckExprLifetime.cpp +++ b/clang/lib/Sema/CheckExprLifetime.cpp @@ -200,6 +200,7 @@ struct IndirectLocalPathEntry { LifetimeBoundCall, TemporaryCopy, LambdaCaptureInit, + MemberExpr, GslReferenceInit, GslPointerInit, GslPointerAssignment, @@ -593,19 +594,6 @@ static void visitFunctionCallArguments(IndirectLocalPath &Path, Expr *Call, Path.pop_back(); }; auto VisitGSLPointerArg = [&](const FunctionDecl *Callee, Expr *Arg) { - // We are not interested in the temporary base objects of gsl Pointers: - // Temp().ptr; // Here ptr might not dangle. - if (isa(Arg->IgnoreImpCasts())) - return; - // Avoid false positives when the object is constructed from a conditional - // operator argument. A common case is: - // // 'ptr' might not be owned by the Owner object. - // std::string_view s = cond() ? Owner().ptr : sv; - if (const auto *Cond = - dyn_cast(Arg->IgnoreImpCasts()); - Cond && isPointerLikeType(Cond->getType())) - return; - auto ReturnType = Callee->getReturnType(); // Once we initialized a value with a non gsl-owner reference, it can no @@ -726,6 +714,9 @@ static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path, Init = ILE->getInit(0); } + if (MemberExpr *ME = dyn_cast(Init->IgnoreImpCasts())) + Path.push_back( + {IndirectLocalPathEntry::MemberExpr, ME, ME->getMemberDecl()}); // Step over any subobject adjustments; we may have a materialized // temporary inside them. Init = const_cast(Init->skipRValueSubobjectAdjustments()); @@ -1117,10 +1108,12 @@ enum PathLifetimeKind { static PathLifetimeKind shouldLifetimeExtendThroughPath(const IndirectLocalPath &Path) { for (auto Elem : Path) { - if (Elem.Kind == IndirectLocalPathEntry::DefaultInit) - return PathLifetimeKind::Extend; - if (Elem.Kind != IndirectLocalPathEntry::LambdaCaptureInit) - return PathLifetimeKind::NoExtend; + if (Elem.Kind == IndirectLocalPathEntry::MemberExpr || + Elem.Kind == IndirectLocalPathEntry::LambdaCaptureInit) + continue; + return Elem.Kind == IndirectLocalPathEntry::DefaultInit + ? PathLifetimeKind::Extend + : PathLifetimeKind::NoExtend; } return PathLifetimeKind::Extend; } @@ -1138,6 +1131,7 @@ static SourceRange nextPathEntryRange(const IndirectLocalPath &Path, unsigned I, case IndirectLocalPathEntry::GslPointerInit: case IndirectLocalPathEntry::GslPointerAssignment: case IndirectLocalPathEntry::ParenAggInit: + case IndirectLocalPathEntry::MemberExpr: // These exist primarily to mark the path as not permitting or // supporting lifetime extension. break; @@ -1167,6 +1161,7 @@ static bool pathOnlyHandlesGslPointer(const IndirectLocalPath &Path) { case IndirectLocalPathEntry::VarInit: case IndirectLocalPathEntry::AddressOf: case IndirectLocalPathEntry::LifetimeBoundCall: + case IndirectLocalPathEntry::MemberExpr: continue; case IndirectLocalPathEntry::GslPointerInit: case IndirectLocalPathEntry::GslReferenceInit: @@ -1193,13 +1188,34 @@ enum AnalysisResult { // Analyze cases where a GSLPointer is initialized or assigned from a // temporary owner object. static AnalysisResult analyzePathForGSLPointer(const IndirectLocalPath &Path, - Local L) { + Local L, LifetimeKind LK) { if (!pathOnlyHandlesGslPointer(Path)) return NotGSLPointer; // At this point, Path represents a series of operations involving a // GSLPointer, either in the process of initialization or assignment. + // Process temporary base objects for MemberExpr cases, e.g. Temp().field. + for (const auto &E : Path) { + if (E.Kind == IndirectLocalPathEntry::MemberExpr) { + // Avoid interfering with the local base object. + if (pathContainsInit(Path)) + return Abandon; + + // We are not interested in the temporary base objects of gsl Pointers: + // auto p1 = Temp().ptr; // Here p1 might not dangle. + // However, we want to diagnose for gsl owner fields: + // auto p2 = Temp().owner; // Here p2 is dangling. + if (const auto *FD = llvm::dyn_cast_or_null(E.D); + FD && !FD->getType()->isReferenceType() && + isRecordWithAttr(FD->getType()) && + LK != LK_MemInitializer) { + return Report; + } + return Abandon; + } + } + // Note: A LifetimeBoundCall can appear interleaved in this sequence. // For example: // const std::string& Ref(const std::string& a [[clang::lifetimebound]]); @@ -1297,7 +1313,7 @@ checkExprLifetimeImpl(Sema &SemaRef, const InitializedEntity *InitEntity, auto *MTE = dyn_cast(L); bool IsGslPtrValueFromGslTempOwner = true; - switch (analyzePathForGSLPointer(Path, L)) { + switch (analyzePathForGSLPointer(Path, L, LK)) { case Abandon: return false; case Skip: @@ -1429,6 +1445,7 @@ checkExprLifetimeImpl(Sema &SemaRef, const InitializedEntity *InitEntity, auto *DRE = dyn_cast(L); // Suppress false positives for code like the one below: // Ctor(unique_ptr up) : pointer(up.get()), owner(move(up)) {} + // FIXME: move this logic to analyzePathForGSLPointer. if (DRE && isRecordWithAttr(DRE->getType())) return false; @@ -1527,6 +1544,7 @@ checkExprLifetimeImpl(Sema &SemaRef, const InitializedEntity *InitEntity, case IndirectLocalPathEntry::LifetimeBoundCall: case IndirectLocalPathEntry::TemporaryCopy: + case IndirectLocalPathEntry::MemberExpr: case IndirectLocalPathEntry::GslPointerInit: case IndirectLocalPathEntry::GslReferenceInit: case IndirectLocalPathEntry::GslPointerAssignment: diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index c41164a2f1af1..e440f60526bb3 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -3634,6 +3634,7 @@ static bool isValidOrderingForOp(int64_t Ordering, AtomicExpr::AtomicOp Op) { case AtomicExpr::AO__atomic_store_n: case AtomicExpr::AO__scoped_atomic_store: case AtomicExpr::AO__scoped_atomic_store_n: + case AtomicExpr::AO__atomic_clear: return OrderingCABI != llvm::AtomicOrderingCABI::consume && OrderingCABI != llvm::AtomicOrderingCABI::acquire && OrderingCABI != llvm::AtomicOrderingCABI::acq_rel; @@ -3686,12 +3687,18 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange, C11CmpXchg, // bool __atomic_compare_exchange(A *, C *, CP, bool, int, int) - GNUCmpXchg + GNUCmpXchg, + + // bool __atomic_test_and_set(A *, int) + TestAndSetByte, + + // void __atomic_clear(A *, int) + ClearByte, } Form = Init; - const unsigned NumForm = GNUCmpXchg + 1; - const unsigned NumArgs[] = { 2, 2, 3, 3, 3, 3, 4, 5, 6 }; - const unsigned NumVals[] = { 1, 0, 1, 1, 1, 1, 2, 2, 3 }; + const unsigned NumForm = ClearByte + 1; + const unsigned NumArgs[] = {2, 2, 3, 3, 3, 3, 4, 5, 6, 2, 2}; + const unsigned NumVals[] = {1, 0, 1, 1, 1, 1, 2, 2, 3, 0, 0}; // where: // C is an appropriate type, // A is volatile _Atomic(C) for __c11 builtins and is C for GNU builtins, @@ -3852,6 +3859,14 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange, case AtomicExpr::AO__scoped_atomic_compare_exchange_n: Form = GNUCmpXchg; break; + + case AtomicExpr::AO__atomic_test_and_set: + Form = TestAndSetByte; + break; + + case AtomicExpr::AO__atomic_clear: + Form = ClearByte; + break; } unsigned AdjustedNumArgs = NumArgs[Form]; @@ -3911,14 +3926,28 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange, } } - // Pointer to object of size zero is not allowed. - if (RequireCompleteType(Ptr->getBeginLoc(), AtomTy, - diag::err_incomplete_type)) - return ExprError(); - if (Context.getTypeInfoInChars(AtomTy).Width.isZero()) { - Diag(ExprRange.getBegin(), diag::err_atomic_builtin_must_be_pointer) - << Ptr->getType() << 1 << Ptr->getSourceRange(); - return ExprError(); + if (Form != TestAndSetByte && Form != ClearByte) { + // Pointer to object of size zero is not allowed. + if (RequireCompleteType(Ptr->getBeginLoc(), AtomTy, + diag::err_incomplete_type)) + return ExprError(); + + if (Context.getTypeInfoInChars(AtomTy).Width.isZero()) { + Diag(ExprRange.getBegin(), diag::err_atomic_builtin_must_be_pointer) + << Ptr->getType() << 1 << Ptr->getSourceRange(); + return ExprError(); + } + } else { + // The __atomic_clear and __atomic_test_and_set intrinsics accept any + // non-const pointer type, including void* and pointers to incomplete + // structs, but only access the first byte. + AtomTy = Context.CharTy; + AtomTy = AtomTy.withCVRQualifiers( + pointerType->getPointeeType().getCVRQualifiers()); + QualType PointerQT = Context.getPointerType(AtomTy); + pointerType = PointerQT->getAs(); + Ptr = ImpCastExprToType(Ptr, PointerQT, CK_BitCast).get(); + ValType = AtomTy; } // For an arithmetic operation, the implied arithmetic must be well-formed. @@ -3997,10 +4026,10 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange, ValType.removeLocalVolatile(); ValType.removeLocalConst(); QualType ResultType = ValType; - if (Form == Copy || Form == LoadCopy || Form == GNUXchg || - Form == Init) + if (Form == Copy || Form == LoadCopy || Form == GNUXchg || Form == Init || + Form == ClearByte) ResultType = Context.VoidTy; - else if (Form == C11CmpXchg || Form == GNUCmpXchg) + else if (Form == C11CmpXchg || Form == GNUCmpXchg || Form == TestAndSetByte) ResultType = Context.BoolTy; // The type of a parameter passed 'by value'. In the GNU atomics, such @@ -4045,6 +4074,10 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange, APIOrderedArgs.push_back(Args[1]); // Order APIOrderedArgs.push_back(Args[3]); // OrderFail break; + case TestAndSetByte: + case ClearByte: + APIOrderedArgs.push_back(Args[1]); // Order + break; } } else APIOrderedArgs.append(Args.begin(), Args.end()); @@ -4130,6 +4163,8 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange, SubExprs.push_back(APIOrderedArgs[1]); // Val1 break; case Load: + case TestAndSetByte: + case ClearByte: SubExprs.push_back(APIOrderedArgs[1]); // Order break; case LoadCopy: diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp index 8a848df70cc5a..69cda6e68bd36 100644 --- a/clang/lib/Sema/SemaCodeComplete.cpp +++ b/clang/lib/Sema/SemaCodeComplete.cpp @@ -34,6 +34,7 @@ #include "clang/Sema/CodeCompleteConsumer.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/Designator.h" +#include "clang/Sema/HeuristicResolver.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/Overload.h" #include "clang/Sema/ParsedAttr.h" @@ -5861,8 +5862,10 @@ void SemaCodeCompletion::CodeCompleteMemberReferenceExpr( enum CodeCompletionContext::Kind contextKind; if (IsArrow) { - if (const auto *Ptr = ConvertedBaseType->getAs()) - ConvertedBaseType = Ptr->getPointeeType(); + if (QualType PointeeType = Resolver.getPointeeType(ConvertedBaseType); + !PointeeType.isNull()) { + ConvertedBaseType = PointeeType; + } } if (IsArrow) { @@ -5899,8 +5902,9 @@ void SemaCodeCompletion::CodeCompleteMemberReferenceExpr( ExprValueKind BaseKind = Base->getValueKind(); if (IsArrow) { - if (const PointerType *Ptr = BaseType->getAs()) { - BaseType = Ptr->getPointeeType(); + if (QualType PointeeType = Resolver.getPointeeType(BaseType); + !PointeeType.isNull()) { + BaseType = PointeeType; BaseKind = VK_LValue; } else if (BaseType->isObjCObjectPointerType() || BaseType->isTemplateTypeParmType()) { @@ -10472,4 +10476,5 @@ void SemaCodeCompletion::GatherGlobalCodeCompletions( SemaCodeCompletion::SemaCodeCompletion(Sema &S, CodeCompleteConsumer *CompletionConsumer) - : SemaBase(S), CodeCompleter(CompletionConsumer) {} + : SemaBase(S), CodeCompleter(CompletionConsumer), + Resolver(S.getASTContext()) {} diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp index 6a40a59c977d7..8a77cbf8c9477 100644 --- a/clang/lib/Sema/SemaConcept.cpp +++ b/clang/lib/Sema/SemaConcept.cpp @@ -1027,6 +1027,9 @@ static const Expr *SubstituteConstraintExpressionWithoutSatisfaction( ContextScope.emplace(S, const_cast(cast(RD)), /*NewThisContext=*/false); } + EnterExpressionEvaluationContext UnevaluatedContext( + S, Sema::ExpressionEvaluationContext::Unevaluated, + Sema::ReuseLambdaContextDecl); ExprResult SubstConstr = S.SubstConstraintExprWithoutSatisfaction( const_cast(ConstrExpr), MLTAL); if (SFINAE.hasErrorOccurred() || !SubstConstr.isUsable()) diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index a867ed73bd403..839b3a1cccdcc 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -2655,6 +2655,15 @@ CXXBaseSpecifier *Sema::CheckBaseSpecifier(CXXRecordDecl *Class, return nullptr; } + if (BaseType.hasQualifiers()) { + std::string Quals = + BaseType.getQualifiers().getAsString(Context.getPrintingPolicy()); + Diag(BaseLoc, diag::warn_qual_base_type) + << Quals << std::count(Quals.begin(), Quals.end(), ' ') + 1 + << BaseType; + Diag(BaseLoc, diag::note_base_class_specified_here) << BaseType; + } + // For the MS ABI, propagate DLL attributes to base class templates. if (Context.getTargetInfo().getCXXABI().isMicrosoft() || Context.getTargetInfo().getTriple().isPS()) { diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index ae40895980d90..d5273d463d7c0 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -4630,8 +4630,9 @@ ExprResult Sema::CreateUnaryExprOrTypeTraitExpr(TypeSourceInfo *TInfo, // Adds overload of TransformToPotentiallyEvaluated for TypeSourceInfo to // properly deal with VLAs in nested calls of sizeof and typeof. - if (isUnevaluatedContext() && ExprKind == UETT_SizeOf && - TInfo->getType()->isVariablyModifiedType()) + if (currentEvaluationContext().isUnevaluated() && + currentEvaluationContext().InConditionallyConstantEvaluateContext && + ExprKind == UETT_SizeOf && TInfo->getType()->isVariablyModifiedType()) TInfo = TransformToPotentiallyEvaluated(TInfo); // C99 6.5.3.4p4: the type (an unsigned integer type) is size_t. @@ -8387,6 +8388,11 @@ OpenCLCheckVectorConditional(Sema &S, ExprResult &Cond, /// Return true if the Expr is block type static bool checkBlockType(Sema &S, const Expr *E) { + if (E->getType()->isBlockPointerType()) { + S.Diag(E->getExprLoc(), diag::err_opencl_ternary_with_block); + return true; + } + if (const CallExpr *CE = dyn_cast(E)) { QualType Ty = CE->getCallee()->getType(); if (Ty->isBlockPointerType()) { diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index 9d8cdc9c08525..e18e3c197383e 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -1614,7 +1614,7 @@ bool Sema::isUsableModule(const Module *M) { // Otherwise, the global module fragment from other translation unit is not // directly usable. - if (M->isGlobalModule()) + if (M->isExplicitGlobalModule()) return false; Module *Current = getCurrentModule(); @@ -1628,6 +1628,8 @@ bool Sema::isUsableModule(const Module *M) { // module should be visible to the decls in the implicit global module. if (Current->isImplicitGlobalModule()) Current = Current->getTopLevelModule(); + if (M->isImplicitGlobalModule()) + M = M->getTopLevelModule(); // If M is the module we're parsing or M and the current module unit lives in // the same module, M should be usable. diff --git a/clang/lib/Sema/SemaOpenACCClause.cpp b/clang/lib/Sema/SemaOpenACCClause.cpp index 27da14de4c04f..000934225402a 100644 --- a/clang/lib/Sema/SemaOpenACCClause.cpp +++ b/clang/lib/Sema/SemaOpenACCClause.cpp @@ -1360,7 +1360,6 @@ ExprResult CheckGangKernelsExpr(SemaOpenACC &S, } case OpenACCGangKind::Static: return CheckGangStaticExpr(S, E); - return ExprError(); } llvm_unreachable("Unknown gang kind in gang kernels check"); } diff --git a/clang/lib/Sema/SemaX86.cpp b/clang/lib/Sema/SemaX86.cpp index fd1a6017712d2..7feca138e3e2c 100644 --- a/clang/lib/Sema/SemaX86.cpp +++ b/clang/lib/Sema/SemaX86.cpp @@ -1045,9 +1045,9 @@ bool SemaX86::CheckBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, case X86::BI__builtin_ia32_vpshrdw128: case X86::BI__builtin_ia32_vpshrdw256: case X86::BI__builtin_ia32_vpshrdw512: - case X86::BI__builtin_ia32_vminmaxnepbf16128: - case X86::BI__builtin_ia32_vminmaxnepbf16256: - case X86::BI__builtin_ia32_vminmaxnepbf16512: + case X86::BI__builtin_ia32_vminmaxbf16128: + case X86::BI__builtin_ia32_vminmaxbf16256: + case X86::BI__builtin_ia32_vminmaxbf16512: case X86::BI__builtin_ia32_vminmaxpd128_mask: case X86::BI__builtin_ia32_vminmaxpd256_round_mask: case X86::BI__builtin_ia32_vminmaxph128_mask: diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index c7c17e09a30e0..066c4b1533552 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -7198,6 +7198,8 @@ void ASTRecordWriter::AddCXXDefinitionData(const CXXRecordDecl *D) { bool ModulesCodegen = !D->isDependentType() && + D->getTemplateSpecializationKind() != + TSK_ExplicitInstantiationDeclaration && (Writer->getLangOpts().ModulesDebugInfo || D->isInNamedModule()); Record->push_back(ModulesCodegen); if (ModulesCodegen) diff --git a/clang/test/AST/ByteCode/cxx2a.cpp b/clang/test/AST/ByteCode/cxx2a.cpp index f6006881cee4d..e478a0ddc4c14 100644 --- a/clang/test/AST/ByteCode/cxx2a.cpp +++ b/clang/test/AST/ByteCode/cxx2a.cpp @@ -139,8 +139,8 @@ namespace TypeId { static_assert(&B2().ti1 == &typeid(B)); static_assert(&B2().ti2 == &typeid(B2)); extern B2 extern_b2; - static_assert(&typeid(extern_b2) == &typeid(B2)); // both-error {{constant expression}} \ - // both-note{{typeid applied to object 'extern_b2' whose dynamic type is not constant}} + static_assert(&typeid(extern_b2) == &typeid(B2)); // expected-error {{constant expression}} \ + // expected-note{{typeid applied to object 'extern_b2' whose dynamic type is not constant}} constexpr B2 b2; diff --git a/clang/test/CodeCompletion/member-access.cpp b/clang/test/CodeCompletion/member-access.cpp index 912f269db6c1a..ab6dc69bf2923 100644 --- a/clang/test/CodeCompletion/member-access.cpp +++ b/clang/test/CodeCompletion/member-access.cpp @@ -384,3 +384,20 @@ void Foo() { // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:382:5 %s -o - | FileCheck -check-prefix=CHECK-DEREF-DEPENDENT %s // CHECK-DEREF-DEPENDENT: [#void#]Add() } + +namespace dependent_smart_pointer { +template +struct smart_pointer { + T* operator->(); +}; + +template +struct node { + smart_pointer> next; + void foo() { + next->next; + // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:398:11 %s -o - | FileCheck -check-prefix=CHECK-DEPENDENT-SMARTPTR %s + // CHECK-DEPENDENT-SMARTPTR: [#smart_pointer>#]next + } +}; +} diff --git a/clang/test/CodeGen/AArch64/sve2p1-intrinsics/acle_sve2p1_dupq.c b/clang/test/CodeGen/AArch64/sve2p1-intrinsics/acle_sve2p1_dupq.c index b1f404c0ec8c0..cf1c00cdd56b2 100644 --- a/clang/test/CodeGen/AArch64/sve2p1-intrinsics/acle_sve2p1_dupq.c +++ b/clang/test/CodeGen/AArch64/sve2p1-intrinsics/acle_sve2p1_dupq.c @@ -211,3 +211,19 @@ svfloat64_t test_svdup_laneq_f64(svfloat64_t zn) { svbfloat16_t test_svdup_laneq_bf16(svbfloat16_t zn) { return SVE_ACLE_FUNC(svdup_laneq, _bf16)(zn, 3); } + +// CHECK-LABEL: define dso_local @test_svdup_laneq_mf8 +// CHECK-SAME: ( [[ZN:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.dup.laneq.nxv16i8( [[ZN]], i32 1) +// CHECK-NEXT: ret [[TMP0]] +// +// CPP-CHECK-LABEL: define dso_local @_Z20test_svdup_laneq_mf8u13__SVMfloat8_t +// CPP-CHECK-SAME: ( [[ZN:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.dup.laneq.nxv16i8( [[ZN]], i32 1) +// CPP-CHECK-NEXT: ret [[TMP0]] +// +svmfloat8_t test_svdup_laneq_mf8(svmfloat8_t zn) { + return SVE_ACLE_FUNC(svdup_laneq, _mf8)(zn, 1); +} diff --git a/clang/test/CodeGen/AArch64/sve2p1-intrinsics/acle_sve2p1_extq.c b/clang/test/CodeGen/AArch64/sve2p1-intrinsics/acle_sve2p1_extq.c index 06eec1e00900c..d46e67b9918aa 100644 --- a/clang/test/CodeGen/AArch64/sve2p1-intrinsics/acle_sve2p1_extq.c +++ b/clang/test/CodeGen/AArch64/sve2p1-intrinsics/acle_sve2p1_extq.c @@ -211,3 +211,19 @@ svfloat64_t test_svextq_f64(svfloat64_t zn, svfloat64_t zm) { svbfloat16_t test_svextq_bf16(svbfloat16_t zn, svbfloat16_t zm) { return SVE_ACLE_FUNC(svextq, _bf16,,)(zn, zm, 6); } + +// CHECK-LABEL: define dso_local @test_svextq_mf8 +// CHECK-SAME: ( [[ZN:%.*]], [[ZM:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.extq.nxv16i8( [[ZN]], [[ZM]], i32 6) +// CHECK-NEXT: ret [[TMP0]] +// +// CPP-CHECK-LABEL: define dso_local @_Z15test_svextq_mf8u13__SVMfloat8_tS_ +// CPP-CHECK-SAME: ( [[ZN:%.*]], [[ZM:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.extq.nxv16i8( [[ZN]], [[ZM]], i32 6) +// CPP-CHECK-NEXT: ret [[TMP0]] +// +svmfloat8_t test_svextq_mf8(svmfloat8_t zn, svmfloat8_t zm) { + return SVE_ACLE_FUNC(svextq, _mf8,,)(zn, zm, 6); +} diff --git a/clang/test/CodeGen/AArch64/sve2p1-intrinsics/acle_sve2p1_tblq.c b/clang/test/CodeGen/AArch64/sve2p1-intrinsics/acle_sve2p1_tblq.c index 7a19cde9abd87..3d3bb0d17a50c 100644 --- a/clang/test/CodeGen/AArch64/sve2p1-intrinsics/acle_sve2p1_tblq.c +++ b/clang/test/CodeGen/AArch64/sve2p1-intrinsics/acle_sve2p1_tblq.c @@ -212,3 +212,19 @@ svfloat64_t test_svtblq_f64(svfloat64_t zn, svuint64_t zm) { svbfloat16_t test_svtblq_bf16(svbfloat16_t zn, svuint16_t zm) { return SVE_ACLE_FUNC(svtblq, _bf16,,)(zn, zm); } + +// CHECK-LABEL: define dso_local @test_svtblq_mf8 +// CHECK-SAME: ( [[ZN:%.*]], [[ZM:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.tblq.nxv16i8( [[ZN]], [[ZM]]) +// CHECK-NEXT: ret [[TMP0]] +// +// CPP-CHECK-LABEL: define dso_local @_Z15test_svtblq_mf8u13__SVMfloat8_tu11__SVUint8_t +// CPP-CHECK-SAME: ( [[ZN:%.*]], [[ZM:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.tblq.nxv16i8( [[ZN]], [[ZM]]) +// CPP-CHECK-NEXT: ret [[TMP0]] +// +svmfloat8_t test_svtblq_mf8(svmfloat8_t zn, svuint8_t zm) { + return SVE_ACLE_FUNC(svtblq, _mf8,,)(zn, zm); +} diff --git a/clang/test/CodeGen/AArch64/sve2p1-intrinsics/acle_sve2p1_tbxq.c b/clang/test/CodeGen/AArch64/sve2p1-intrinsics/acle_sve2p1_tbxq.c index f4aaed586c731..674bd9cbb083b 100644 --- a/clang/test/CodeGen/AArch64/sve2p1-intrinsics/acle_sve2p1_tbxq.c +++ b/clang/test/CodeGen/AArch64/sve2p1-intrinsics/acle_sve2p1_tbxq.c @@ -212,3 +212,19 @@ svfloat64_t test_svtbxq_f64(svfloat64_t passthru, svfloat64_t zn, svuint64_t zm) svbfloat16_t test_svtbxq_bf16(svbfloat16_t passthru, svbfloat16_t zn, svuint16_t zm) { return SVE_ACLE_FUNC(svtbxq, _bf16,,)(passthru, zn, zm); } + +// CHECK-LABEL: define dso_local @test_svtbxq_mf8 +// CHECK-SAME: ( [[PASSTHRU:%.*]], [[ZN:%.*]], [[ZM:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.tbxq.nxv16i8( [[PASSTHRU]], [[ZN]], [[ZM]]) +// CHECK-NEXT: ret [[TMP0]] +// +// CPP-CHECK-LABEL: define dso_local @_Z15test_svtbxq_mf8u13__SVMfloat8_tS_u11__SVUint8_t +// CPP-CHECK-SAME: ( [[PASSTHRU:%.*]], [[ZN:%.*]], [[ZM:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.tbxq.nxv16i8( [[PASSTHRU]], [[ZN]], [[ZM]]) +// CPP-CHECK-NEXT: ret [[TMP0]] +// +svmfloat8_t test_svtbxq_mf8(svmfloat8_t passthru, svmfloat8_t zn, svuint8_t zm) { + return SVE_ACLE_FUNC(svtbxq, _mf8,,)(passthru, zn, zm); +} diff --git a/clang/test/CodeGen/AArch64/sve2p1-intrinsics/acle_sve2p1_uzpq1.c b/clang/test/CodeGen/AArch64/sve2p1-intrinsics/acle_sve2p1_uzpq1.c index 8c639120409ec..35878d61f9549 100644 --- a/clang/test/CodeGen/AArch64/sve2p1-intrinsics/acle_sve2p1_uzpq1.c +++ b/clang/test/CodeGen/AArch64/sve2p1-intrinsics/acle_sve2p1_uzpq1.c @@ -214,4 +214,19 @@ svbfloat16_t test_svuzpq1_bf16(svbfloat16_t zn, svbfloat16_t zm) { return SVE_ACLE_FUNC(svuzpq1,_bf16)(zn, zm); } +// CHECK-LABEL: define dso_local @test_svuzpq1_mf8 +// CHECK-SAME: ( [[ZN:%.*]], [[ZM:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.uzpq1.nxv16i8( [[ZN]], [[ZM]]) +// CHECK-NEXT: ret [[TMP0]] +// +// CPP-CHECK-LABEL: define dso_local @_Z16test_svuzpq1_mf8u13__SVMfloat8_tS_ +// CPP-CHECK-SAME: ( [[ZN:%.*]], [[ZM:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.uzpq1.nxv16i8( [[ZN]], [[ZM]]) +// CPP-CHECK-NEXT: ret [[TMP0]] +// +svmfloat8_t test_svuzpq1_mf8(svmfloat8_t zn, svmfloat8_t zm) { + return SVE_ACLE_FUNC(svuzpq1,_mf8)(zn, zm); +} diff --git a/clang/test/CodeGen/AArch64/sve2p1-intrinsics/acle_sve2p1_uzpq2.c b/clang/test/CodeGen/AArch64/sve2p1-intrinsics/acle_sve2p1_uzpq2.c index 756d2538317e0..a22f20f30039f 100644 --- a/clang/test/CodeGen/AArch64/sve2p1-intrinsics/acle_sve2p1_uzpq2.c +++ b/clang/test/CodeGen/AArch64/sve2p1-intrinsics/acle_sve2p1_uzpq2.c @@ -214,4 +214,18 @@ svbfloat16_t test_svuzpq2_bf16(svbfloat16_t zn, svbfloat16_t zm) { return SVE_ACLE_FUNC(svuzpq2,_bf16)(zn, zm); } - +// CHECK-LABEL: define dso_local @test_svuzpq2_mf8 +// CHECK-SAME: ( [[ZN:%.*]], [[ZM:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.uzpq2.nxv16i8( [[ZN]], [[ZM]]) +// CHECK-NEXT: ret [[TMP0]] +// +// CPP-CHECK-LABEL: define dso_local @_Z16test_svuzpq2_mf8u13__SVMfloat8_tS_ +// CPP-CHECK-SAME: ( [[ZN:%.*]], [[ZM:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.uzpq2.nxv16i8( [[ZN]], [[ZM]]) +// CPP-CHECK-NEXT: ret [[TMP0]] +// +svmfloat8_t test_svuzpq2_mf8(svmfloat8_t zn, svmfloat8_t zm) { + return SVE_ACLE_FUNC(svuzpq2,_mf8)(zn, zm); +} diff --git a/clang/test/CodeGen/AArch64/sve2p1-intrinsics/acle_sve2p1_zipq1.c b/clang/test/CodeGen/AArch64/sve2p1-intrinsics/acle_sve2p1_zipq1.c index 6684bb2cf2d99..4366973062697 100644 --- a/clang/test/CodeGen/AArch64/sve2p1-intrinsics/acle_sve2p1_zipq1.c +++ b/clang/test/CodeGen/AArch64/sve2p1-intrinsics/acle_sve2p1_zipq1.c @@ -214,4 +214,18 @@ svbfloat16_t test_svzipq1_bf16(svbfloat16_t zn, svbfloat16_t zm) { return SVE_ACLE_FUNC(svzipq1,_bf16)(zn, zm); } - +// CHECK-LABEL: define dso_local @test_svzipq1_mf8 +// CHECK-SAME: ( [[ZN:%.*]], [[ZM:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.zipq1.nxv16i8( [[ZN]], [[ZM]]) +// CHECK-NEXT: ret [[TMP0]] +// +// CPP-CHECK-LABEL: define dso_local @_Z16test_svzipq1_mf8u13__SVMfloat8_tS_ +// CPP-CHECK-SAME: ( [[ZN:%.*]], [[ZM:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.zipq1.nxv16i8( [[ZN]], [[ZM]]) +// CPP-CHECK-NEXT: ret [[TMP0]] +// +svmfloat8_t test_svzipq1_mf8(svmfloat8_t zn, svmfloat8_t zm) { + return SVE_ACLE_FUNC(svzipq1,_mf8)(zn, zm); +} diff --git a/clang/test/CodeGen/AArch64/sve2p1-intrinsics/acle_sve2p1_zipq2.c b/clang/test/CodeGen/AArch64/sve2p1-intrinsics/acle_sve2p1_zipq2.c index 2bfd72b32d1cc..4e27ec463c08e 100644 --- a/clang/test/CodeGen/AArch64/sve2p1-intrinsics/acle_sve2p1_zipq2.c +++ b/clang/test/CodeGen/AArch64/sve2p1-intrinsics/acle_sve2p1_zipq2.c @@ -214,4 +214,18 @@ svbfloat16_t test_svzipq2_bf16(svbfloat16_t zn, svbfloat16_t zm) { return SVE_ACLE_FUNC(svzipq2,_bf16)(zn, zm); } - +// CHECK-LABEL: define dso_local @test_svzipq2_mf8 +// CHECK-SAME: ( [[ZN:%.*]], [[ZM:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.zipq2.nxv16i8( [[ZN]], [[ZM]]) +// CHECK-NEXT: ret [[TMP0]] +// +// CPP-CHECK-LABEL: define dso_local @_Z16test_svzipq2_mf8u13__SVMfloat8_tS_ +// CPP-CHECK-SAME: ( [[ZN:%.*]], [[ZM:%.*]]) #[[ATTR0]] { +// CPP-CHECK-NEXT: entry: +// CPP-CHECK-NEXT: [[TMP0:%.*]] = tail call @llvm.aarch64.sve.zipq2.nxv16i8( [[ZN]], [[ZM]]) +// CPP-CHECK-NEXT: ret [[TMP0]] +// +svmfloat8_t test_svzipq2_mf8(svmfloat8_t zn, svmfloat8_t zm) { + return SVE_ACLE_FUNC(svzipq2,_mf8)(zn, zm); +} diff --git a/clang/test/CodeGen/AArch64/targetattr.c b/clang/test/CodeGen/AArch64/targetattr.c index f8d5f9912c0d7..cfe115bf97ed3 100644 --- a/clang/test/CodeGen/AArch64/targetattr.c +++ b/clang/test/CodeGen/AArch64/targetattr.c @@ -218,7 +218,7 @@ void applem4() {} // CHECK: attributes #[[ATTR15]] = { noinline nounwind optnone "branch-target-enforcement" "guarded-control-stack" "no-trapping-math"="true" "sign-return-address"="non-leaf" "sign-return-address-key"="a_key" "stack-protector-buffer-size"="8" "target-cpu"="neoverse-n1" "target-features"="+aes,+bf16,+bti,+ccidx,+complxnum,+crc,+dit,+dotprod,+flagm,+fp-armv8,+fullfp16,+i8mm,+jsconv,+lse,+neon,+pauth,+perfmon,+predres,+ras,+rcpc,+rdm,+sb,+sha2,+spe,+ssbs,+sve,+sve2,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8.6a,+v8a" "tune-cpu"="cortex-a710" } // CHECK: attributes #[[ATTR16]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" } // CHECK: attributes #[[ATTR17]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-features"="-v9.3a" } -// CHECK: attributes #[[ATTR18]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m4" "target-features"="+aes,+bf16,+bti,+ccidx,+complxnum,+crc,+dit,+dotprod,+flagm,+fp-armv8,+fp16fml,+fpac,+fullfp16,+i8mm,+jsconv,+lse,+neon,+pauth,+perfmon,+predres,+ras,+rcpc,+rdm,+sb,+sha2,+sha3,+sme,+sme-f64f64,+sme-i16i64,+sme2,+ssbs,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8.6a,+v8.7a,+v8a,+wfxt" } +// CHECK: attributes #[[ATTR18]] = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m4" "target-features"="+aes,+bf16,+bti,+ccidx,+complxnum,+crc,+dit,+dotprod,+flagm,+fp-armv8,+fp16fml,+fpac,+fullfp16,+i8mm,+jsconv,+lse,+neon,+pauth,+perfmon,+predres,+ras,+rcpc,+rdm,+sb,+sha2,+sha3,+sme,+sme-f64f64,+sme-i16i64,+sme2,+spe-eef,+ssbs,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8.6a,+v8.7a,+v8a,+wfxt" } //. // CHECK: [[META0:![0-9]+]] = !{i32 1, !"wchar_size", i32 4} // CHECK: [[META1:![0-9]+]] = !{!"{{.*}}clang version {{.*}}"} diff --git a/clang/test/CodeGen/X86/avx10_2_512minmax-builtins.c b/clang/test/CodeGen/X86/avx10_2_512minmax-builtins.c index 4e80d8b36e194..4e467b36b2348 100644 --- a/clang/test/CodeGen/X86/avx10_2_512minmax-builtins.c +++ b/clang/test/CodeGen/X86/avx10_2_512minmax-builtins.c @@ -5,25 +5,25 @@ #include -__m512bh test_mm512_minmaxne_pbh(__m512bh __A, __m512bh __B) { - // CHECK-LABEL: @test_mm512_minmaxne_pbh( - // CHECK: call <32 x bfloat> @llvm.x86.avx10.vminmaxnepbf16512( - return _mm512_minmaxne_pbh(__A, __B, 127); +__m512bh test_mm512_minmax_pbh(__m512bh __A, __m512bh __B) { + // CHECK-LABEL: @test_mm512_minmax_pbh( + // CHECK: call <32 x bfloat> @llvm.x86.avx10.vminmaxbf16512( + return _mm512_minmax_pbh(__A, __B, 127); } -__m512bh test_mm512_mask_minmaxne_pbh(__m512bh __A, __mmask32 __B, __m512bh __C, __m512bh __D) { - // CHECK-LABEL: @test_mm512_mask_minmaxne_pbh( - // CHECK: call <32 x bfloat> @llvm.x86.avx10.vminmaxnepbf16512( +__m512bh test_mm512_mask_minmax_pbh(__m512bh __A, __mmask32 __B, __m512bh __C, __m512bh __D) { + // CHECK-LABEL: @test_mm512_mask_minmax_pbh( + // CHECK: call <32 x bfloat> @llvm.x86.avx10.vminmaxbf16512( // CHECK: select <32 x i1> %{{.*}}, <32 x bfloat> %{{.*}}, <32 x bfloat> %{{.*}} - return _mm512_mask_minmaxne_pbh(__A, __B, __C, __D, 127); + return _mm512_mask_minmax_pbh(__A, __B, __C, __D, 127); } -__m512bh test_mm512_maskz_minmaxne_pbh(__mmask32 __A, __m512bh __B, __m512bh __C) { - // CHECK-LABEL: @test_mm512_maskz_minmaxne_pbh( - // CHECK: call <32 x bfloat> @llvm.x86.avx10.vminmaxnepbf16512( +__m512bh test_mm512_maskz_minmax_pbh(__mmask32 __A, __m512bh __B, __m512bh __C) { + // CHECK-LABEL: @test_mm512_maskz_minmax_pbh( + // CHECK: call <32 x bfloat> @llvm.x86.avx10.vminmaxbf16512( // CHECK: zeroinitializer // CHECK: select <32 x i1> %{{.*}}, <32 x bfloat> %{{.*}}, <32 x bfloat> %{{.*}} - return _mm512_maskz_minmaxne_pbh(__A, __B, __C, 127); + return _mm512_maskz_minmax_pbh(__A, __B, __C, 127); } __m512d test_mm512_minmax_pd(__m512d __A, __m512d __B) { diff --git a/clang/test/CodeGen/X86/avx10_2_512minmax-error.c b/clang/test/CodeGen/X86/avx10_2_512minmax-error.c index e487c3fad49dd..6db7801eb0040 100644 --- a/clang/test/CodeGen/X86/avx10_2_512minmax-error.c +++ b/clang/test/CodeGen/X86/avx10_2_512minmax-error.c @@ -5,20 +5,20 @@ #include -__m128bh test_mm_minmaxne_pbh(__m128bh __A, __m128bh __B) { - return _mm_minmaxne_pbh(__A, __B, 256); // expected-error {{argument value 256 is outside the valid range [0, 255]}} +__m128bh test_mm_minmax_pbh(__m128bh __A, __m128bh __B) { + return _mm_minmax_pbh(__A, __B, 256); // expected-error {{argument value 256 is outside the valid range [0, 255]}} } -__m128bh test_mm_mask_minmaxne_pbh(__m128bh __A, __mmask8 __B, __m128bh __C, __m128bh __D) { - return _mm_mask_minmaxne_pbh(__A, __B, __C, __D, 256); // expected-error {{argument value 256 is outside the valid range [0, 255]}} +__m128bh test_mm_mask_minmax_pbh(__m128bh __A, __mmask8 __B, __m128bh __C, __m128bh __D) { + return _mm_mask_minmax_pbh(__A, __B, __C, __D, 256); // expected-error {{argument value 256 is outside the valid range [0, 255]}} } -__m256bh test_mm256_minmaxne_pbh(__m256bh __A, __m256bh __B) { - return _mm256_minmaxne_pbh(__A, __B, 256); // expected-error {{argument value 256 is outside the valid range [0, 255]}} +__m256bh test_mm256_minmax_pbh(__m256bh __A, __m256bh __B) { + return _mm256_minmax_pbh(__A, __B, 256); // expected-error {{argument value 256 is outside the valid range [0, 255]}} } -__m256bh test_mm256_mask_minmaxne_pbh(__m256bh __A, __mmask16 __B, __m256bh __C, __m256bh __D) { - return _mm256_mask_minmaxne_pbh(__A, __B, __C, __D, 256); // expected-error {{argument value 256 is outside the valid range [0, 255]}} +__m256bh test_mm256_mask_minmax_pbh(__m256bh __A, __mmask16 __B, __m256bh __C, __m256bh __D) { + return _mm256_mask_minmax_pbh(__A, __B, __C, __D, 256); // expected-error {{argument value 256 is outside the valid range [0, 255]}} } __m128d test_mm_minmax_pd(__m128d __A, __m128d __B) { @@ -69,12 +69,12 @@ __m256 test_mm256_mask_minmax_ps(__m256 __A, __mmask8 __B, __m256 __C, __m256 __ return _mm256_mask_minmax_ps(__A, __B, __C, __D, 256); // expected-error {{argument value 256 is outside the valid range [0, 255]}} } -__m512bh test_mm512_minmaxne_pbh(__m512bh __A, __m512bh __B) { - return _mm512_minmaxne_pbh(__A, __B, 256); // expected-error {{argument value 256 is outside the valid range [0, 255]}} +__m512bh test_mm512_minmax_pbh(__m512bh __A, __m512bh __B) { + return _mm512_minmax_pbh(__A, __B, 256); // expected-error {{argument value 256 is outside the valid range [0, 255]}} } -__m512bh test_mm512_mask_minmaxne_pbh(__m512bh __A, __mmask32 __B, __m512bh __C, __m512bh __D) { - return _mm512_mask_minmaxne_pbh(__A, __B, __C, __D, 256); // expected-error {{argument value 256 is outside the valid range [0, 255]}} +__m512bh test_mm512_mask_minmax_pbh(__m512bh __A, __mmask32 __B, __m512bh __C, __m512bh __D) { + return _mm512_mask_minmax_pbh(__A, __B, __C, __D, 256); // expected-error {{argument value 256 is outside the valid range [0, 255]}} } __m512d test_mm512_minmax_pd(__m512d __A, __m512d __B) { diff --git a/clang/test/CodeGen/X86/avx10_2minmax-builtins.c b/clang/test/CodeGen/X86/avx10_2minmax-builtins.c index 1efafe24ab125..7e21858c71834 100644 --- a/clang/test/CodeGen/X86/avx10_2minmax-builtins.c +++ b/clang/test/CodeGen/X86/avx10_2minmax-builtins.c @@ -5,46 +5,46 @@ #include -__m128bh test_mm_minmaxne_pbh(__m128bh __A, __m128bh __B) { - // CHECK-LABEL: @test_mm_minmaxne_pbh( - // CHECK: call <8 x bfloat> @llvm.x86.avx10.vminmaxnepbf16128( - return _mm_minmaxne_pbh(__A, __B, 127); +__m128bh test_mm_minmax_pbh(__m128bh __A, __m128bh __B) { + // CHECK-LABEL: @test_mm_minmax_pbh( + // CHECK: call <8 x bfloat> @llvm.x86.avx10.vminmaxbf16128( + return _mm_minmax_pbh(__A, __B, 127); } -__m128bh test_mm_mask_minmaxne_pbh(__m128bh __A, __mmask8 __B, __m128bh __C, __m128bh __D) { - // CHECK-LABEL: @test_mm_mask_minmaxne_pbh( - // CHECK: call <8 x bfloat> @llvm.x86.avx10.vminmaxnepbf16128( +__m128bh test_mm_mask_minmax_pbh(__m128bh __A, __mmask8 __B, __m128bh __C, __m128bh __D) { + // CHECK-LABEL: @test_mm_mask_minmax_pbh( + // CHECK: call <8 x bfloat> @llvm.x86.avx10.vminmaxbf16128( // CHECK: select <8 x i1> %{{.*}}, <8 x bfloat> %{{.*}}, <8 x bfloat> %{{.*}} - return _mm_mask_minmaxne_pbh(__A, __B, __C, __D, 127); + return _mm_mask_minmax_pbh(__A, __B, __C, __D, 127); } -__m128bh test_mm_maskz_minmaxne_pbh(__mmask8 __A, __m128bh __B, __m128bh __C) { - // CHECK-LABEL: @test_mm_maskz_minmaxne_pbh( - // CHECK: call <8 x bfloat> @llvm.x86.avx10.vminmaxnepbf16128( +__m128bh test_mm_maskz_minmax_pbh(__mmask8 __A, __m128bh __B, __m128bh __C) { + // CHECK-LABEL: @test_mm_maskz_minmax_pbh( + // CHECK: call <8 x bfloat> @llvm.x86.avx10.vminmaxbf16128( // CHECK: zeroinitializer // CHECK: select <8 x i1> %{{.*}}, <8 x bfloat> %{{.*}}, <8 x bfloat> %{{.*}} - return _mm_maskz_minmaxne_pbh(__A, __B, __C, 127); + return _mm_maskz_minmax_pbh(__A, __B, __C, 127); } -__m256bh test_mm256_minmaxne_pbh(__m256bh __A, __m256bh __B) { - // CHECK-LABEL: @test_mm256_minmaxne_pbh( - // CHECK: call <16 x bfloat> @llvm.x86.avx10.vminmaxnepbf16256( - return _mm256_minmaxne_pbh(__A, __B, 127); +__m256bh test_mm256_minmax_pbh(__m256bh __A, __m256bh __B) { + // CHECK-LABEL: @test_mm256_minmax_pbh( + // CHECK: call <16 x bfloat> @llvm.x86.avx10.vminmaxbf16256( + return _mm256_minmax_pbh(__A, __B, 127); } -__m256bh test_mm256_mask_minmaxne_pbh(__m256bh __A, __mmask16 __B, __m256bh __C, __m256bh __D) { - // CHECK-LABEL: @test_mm256_mask_minmaxne_pbh( - // CHECK: call <16 x bfloat> @llvm.x86.avx10.vminmaxnepbf16256( +__m256bh test_mm256_mask_minmax_pbh(__m256bh __A, __mmask16 __B, __m256bh __C, __m256bh __D) { + // CHECK-LABEL: @test_mm256_mask_minmax_pbh( + // CHECK: call <16 x bfloat> @llvm.x86.avx10.vminmaxbf16256( // CHECK: select <16 x i1> %{{.*}}, <16 x bfloat> %{{.*}}, <16 x bfloat> %{{.*}} - return _mm256_mask_minmaxne_pbh(__A, __B, __C, __D, 127); + return _mm256_mask_minmax_pbh(__A, __B, __C, __D, 127); } -__m256bh test_mm256_maskz_minmaxne_pbh(__mmask16 __A, __m256bh __B, __m256bh __C) { - // CHECK-LABEL: @test_mm256_maskz_minmaxne_pbh( - // CHECK: call <16 x bfloat> @llvm.x86.avx10.vminmaxnepbf16256( +__m256bh test_mm256_maskz_minmax_pbh(__mmask16 __A, __m256bh __B, __m256bh __C) { + // CHECK-LABEL: @test_mm256_maskz_minmax_pbh( + // CHECK: call <16 x bfloat> @llvm.x86.avx10.vminmaxbf16256( // CHECK: zeroinitializer // CHECK: select <16 x i1> %{{.*}}, <16 x bfloat> %{{.*}}, <16 x bfloat> %{{.*}} - return _mm256_maskz_minmaxne_pbh(__A, __B, __C, 127); + return _mm256_maskz_minmax_pbh(__A, __B, __C, 127); } __m128d test_mm_minmax_pd(__m128d __A, __m128d __B) { diff --git a/clang/test/CodeGen/atomic-test-and-set.c b/clang/test/CodeGen/atomic-test-and-set.c new file mode 100644 index 0000000000000..39d4cef16b21d --- /dev/null +++ b/clang/test/CodeGen/atomic-test-and-set.c @@ -0,0 +1,345 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5 +// RUN: %clang_cc1 %s -emit-llvm -o - -triple=aarch64-none-elf | FileCheck %s +// REQUIRES: aarch64-registered-target + +#include + +// CHECK-LABEL: define dso_local void @clear_relaxed( +// CHECK-SAME: ptr noundef [[PTR:%.*]]) #[[ATTR0:[0-9]+]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[PTR_ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8 +// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[PTR_ADDR]], align 8 +// CHECK-NEXT: store atomic i8 0, ptr [[TMP0]] monotonic, align 1 +// CHECK-NEXT: ret void +// +void clear_relaxed(char *ptr) { + __atomic_clear(ptr, memory_order_relaxed); +} + +// CHECK-LABEL: define dso_local void @clear_seq_cst( +// CHECK-SAME: ptr noundef [[PTR:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[PTR_ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8 +// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[PTR_ADDR]], align 8 +// CHECK-NEXT: store atomic i8 0, ptr [[TMP0]] seq_cst, align 1 +// CHECK-NEXT: ret void +// +void clear_seq_cst(char *ptr) { + __atomic_clear(ptr, memory_order_seq_cst); +} + +// CHECK-LABEL: define dso_local void @clear_release( +// CHECK-SAME: ptr noundef [[PTR:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[PTR_ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8 +// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[PTR_ADDR]], align 8 +// CHECK-NEXT: store atomic i8 0, ptr [[TMP0]] release, align 1 +// CHECK-NEXT: ret void +// +void clear_release(char *ptr) { + __atomic_clear(ptr, memory_order_release); +} + +// CHECK-LABEL: define dso_local void @clear_dynamic( +// CHECK-SAME: ptr noundef [[PTR:%.*]], i32 noundef [[ORDER:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[PTR_ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[ORDER_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8 +// CHECK-NEXT: store i32 [[ORDER]], ptr [[ORDER_ADDR]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[PTR_ADDR]], align 8 +// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[ORDER_ADDR]], align 4 +// CHECK-NEXT: switch i32 [[TMP1]], label %[[MONOTONIC:.*]] [ +// CHECK-NEXT: i32 3, label %[[RELEASE:.*]] +// CHECK-NEXT: i32 5, label %[[SEQCST:.*]] +// CHECK-NEXT: ] +// CHECK: [[MONOTONIC]]: +// CHECK-NEXT: store atomic i8 0, ptr [[TMP0]] monotonic, align 1 +// CHECK-NEXT: br label %[[ATOMIC_CONTINUE:.*]] +// CHECK: [[RELEASE]]: +// CHECK-NEXT: store atomic i8 0, ptr [[TMP0]] release, align 1 +// CHECK-NEXT: br label %[[ATOMIC_CONTINUE]] +// CHECK: [[SEQCST]]: +// CHECK-NEXT: store atomic i8 0, ptr [[TMP0]] seq_cst, align 1 +// CHECK-NEXT: br label %[[ATOMIC_CONTINUE]] +// CHECK: [[ATOMIC_CONTINUE]]: +// CHECK-NEXT: ret void +// +void clear_dynamic(char *ptr, int order) { + __atomic_clear(ptr, order); +} + +// CHECK-LABEL: define dso_local void @test_and_set_relaxed( +// CHECK-SAME: ptr noundef [[PTR:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[PTR_ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[ATOMIC_TEMP:%.*]] = alloca i8, align 1 +// CHECK-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8 +// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[PTR_ADDR]], align 8 +// CHECK-NEXT: [[TMP1:%.*]] = atomicrmw xchg ptr [[TMP0]], i8 1 monotonic, align 1 +// CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i8 [[TMP1]], 0 +// CHECK-NEXT: store i1 [[TOBOOL]], ptr [[ATOMIC_TEMP]], align 1 +// CHECK-NEXT: [[TMP2:%.*]] = load i8, ptr [[ATOMIC_TEMP]], align 1 +// CHECK-NEXT: [[LOADEDV:%.*]] = trunc i8 [[TMP2]] to i1 +// CHECK-NEXT: ret void +// +void test_and_set_relaxed(char *ptr) { + __atomic_test_and_set(ptr, memory_order_relaxed); +} + +// CHECK-LABEL: define dso_local void @test_and_set_consume( +// CHECK-SAME: ptr noundef [[PTR:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[PTR_ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[ATOMIC_TEMP:%.*]] = alloca i8, align 1 +// CHECK-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8 +// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[PTR_ADDR]], align 8 +// CHECK-NEXT: [[TMP1:%.*]] = atomicrmw xchg ptr [[TMP0]], i8 1 acquire, align 1 +// CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i8 [[TMP1]], 0 +// CHECK-NEXT: store i1 [[TOBOOL]], ptr [[ATOMIC_TEMP]], align 1 +// CHECK-NEXT: [[TMP2:%.*]] = load i8, ptr [[ATOMIC_TEMP]], align 1 +// CHECK-NEXT: [[LOADEDV:%.*]] = trunc i8 [[TMP2]] to i1 +// CHECK-NEXT: ret void +// +void test_and_set_consume(char *ptr) { + __atomic_test_and_set(ptr, memory_order_consume); +} + +// CHECK-LABEL: define dso_local void @test_and_set_acquire( +// CHECK-SAME: ptr noundef [[PTR:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[PTR_ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[ATOMIC_TEMP:%.*]] = alloca i8, align 1 +// CHECK-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8 +// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[PTR_ADDR]], align 8 +// CHECK-NEXT: [[TMP1:%.*]] = atomicrmw xchg ptr [[TMP0]], i8 1 acquire, align 1 +// CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i8 [[TMP1]], 0 +// CHECK-NEXT: store i1 [[TOBOOL]], ptr [[ATOMIC_TEMP]], align 1 +// CHECK-NEXT: [[TMP2:%.*]] = load i8, ptr [[ATOMIC_TEMP]], align 1 +// CHECK-NEXT: [[LOADEDV:%.*]] = trunc i8 [[TMP2]] to i1 +// CHECK-NEXT: ret void +// +void test_and_set_acquire(char *ptr) { + __atomic_test_and_set(ptr, memory_order_acquire); +} + +// CHECK-LABEL: define dso_local void @test_and_set_release( +// CHECK-SAME: ptr noundef [[PTR:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[PTR_ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[ATOMIC_TEMP:%.*]] = alloca i8, align 1 +// CHECK-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8 +// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[PTR_ADDR]], align 8 +// CHECK-NEXT: [[TMP1:%.*]] = atomicrmw xchg ptr [[TMP0]], i8 1 release, align 1 +// CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i8 [[TMP1]], 0 +// CHECK-NEXT: store i1 [[TOBOOL]], ptr [[ATOMIC_TEMP]], align 1 +// CHECK-NEXT: [[TMP2:%.*]] = load i8, ptr [[ATOMIC_TEMP]], align 1 +// CHECK-NEXT: [[LOADEDV:%.*]] = trunc i8 [[TMP2]] to i1 +// CHECK-NEXT: ret void +// +void test_and_set_release(char *ptr) { + __atomic_test_and_set(ptr, memory_order_release); +} + +// CHECK-LABEL: define dso_local void @test_and_set_acq_rel( +// CHECK-SAME: ptr noundef [[PTR:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[PTR_ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[ATOMIC_TEMP:%.*]] = alloca i8, align 1 +// CHECK-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8 +// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[PTR_ADDR]], align 8 +// CHECK-NEXT: [[TMP1:%.*]] = atomicrmw xchg ptr [[TMP0]], i8 1 acq_rel, align 1 +// CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i8 [[TMP1]], 0 +// CHECK-NEXT: store i1 [[TOBOOL]], ptr [[ATOMIC_TEMP]], align 1 +// CHECK-NEXT: [[TMP2:%.*]] = load i8, ptr [[ATOMIC_TEMP]], align 1 +// CHECK-NEXT: [[LOADEDV:%.*]] = trunc i8 [[TMP2]] to i1 +// CHECK-NEXT: ret void +// +void test_and_set_acq_rel(char *ptr) { + __atomic_test_and_set(ptr, memory_order_acq_rel); +} + +// CHECK-LABEL: define dso_local void @test_and_set_seq_cst( +// CHECK-SAME: ptr noundef [[PTR:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[PTR_ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[ATOMIC_TEMP:%.*]] = alloca i8, align 1 +// CHECK-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8 +// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[PTR_ADDR]], align 8 +// CHECK-NEXT: [[TMP1:%.*]] = atomicrmw xchg ptr [[TMP0]], i8 1 seq_cst, align 1 +// CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i8 [[TMP1]], 0 +// CHECK-NEXT: store i1 [[TOBOOL]], ptr [[ATOMIC_TEMP]], align 1 +// CHECK-NEXT: [[TMP2:%.*]] = load i8, ptr [[ATOMIC_TEMP]], align 1 +// CHECK-NEXT: [[LOADEDV:%.*]] = trunc i8 [[TMP2]] to i1 +// CHECK-NEXT: ret void +// +void test_and_set_seq_cst(char *ptr) { + __atomic_test_and_set(ptr, memory_order_seq_cst); +} + +// CHECK-LABEL: define dso_local void @test_and_set_dynamic( +// CHECK-SAME: ptr noundef [[PTR:%.*]], i32 noundef [[ORDER:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[PTR_ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[ORDER_ADDR:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[ATOMIC_TEMP:%.*]] = alloca i8, align 1 +// CHECK-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8 +// CHECK-NEXT: store i32 [[ORDER]], ptr [[ORDER_ADDR]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[PTR_ADDR]], align 8 +// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[ORDER_ADDR]], align 4 +// CHECK-NEXT: switch i32 [[TMP1]], label %[[MONOTONIC:.*]] [ +// CHECK-NEXT: i32 1, label %[[ACQUIRE:.*]] +// CHECK-NEXT: i32 2, label %[[ACQUIRE]] +// CHECK-NEXT: i32 3, label %[[RELEASE:.*]] +// CHECK-NEXT: i32 4, label %[[ACQREL:.*]] +// CHECK-NEXT: i32 5, label %[[SEQCST:.*]] +// CHECK-NEXT: ] +// CHECK: [[MONOTONIC]]: +// CHECK-NEXT: [[TMP2:%.*]] = atomicrmw xchg ptr [[TMP0]], i8 1 monotonic, align 1 +// CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i8 [[TMP2]], 0 +// CHECK-NEXT: store i1 [[TOBOOL]], ptr [[ATOMIC_TEMP]], align 1 +// CHECK-NEXT: br label %[[ATOMIC_CONTINUE:.*]] +// CHECK: [[ACQUIRE]]: +// CHECK-NEXT: [[TMP3:%.*]] = atomicrmw xchg ptr [[TMP0]], i8 1 acquire, align 1 +// CHECK-NEXT: [[TOBOOL1:%.*]] = icmp ne i8 [[TMP3]], 0 +// CHECK-NEXT: store i1 [[TOBOOL1]], ptr [[ATOMIC_TEMP]], align 1 +// CHECK-NEXT: br label %[[ATOMIC_CONTINUE]] +// CHECK: [[RELEASE]]: +// CHECK-NEXT: [[TMP4:%.*]] = atomicrmw xchg ptr [[TMP0]], i8 1 release, align 1 +// CHECK-NEXT: [[TOBOOL2:%.*]] = icmp ne i8 [[TMP4]], 0 +// CHECK-NEXT: store i1 [[TOBOOL2]], ptr [[ATOMIC_TEMP]], align 1 +// CHECK-NEXT: br label %[[ATOMIC_CONTINUE]] +// CHECK: [[ACQREL]]: +// CHECK-NEXT: [[TMP5:%.*]] = atomicrmw xchg ptr [[TMP0]], i8 1 acq_rel, align 1 +// CHECK-NEXT: [[TOBOOL3:%.*]] = icmp ne i8 [[TMP5]], 0 +// CHECK-NEXT: store i1 [[TOBOOL3]], ptr [[ATOMIC_TEMP]], align 1 +// CHECK-NEXT: br label %[[ATOMIC_CONTINUE]] +// CHECK: [[SEQCST]]: +// CHECK-NEXT: [[TMP6:%.*]] = atomicrmw xchg ptr [[TMP0]], i8 1 seq_cst, align 1 +// CHECK-NEXT: [[TOBOOL4:%.*]] = icmp ne i8 [[TMP6]], 0 +// CHECK-NEXT: store i1 [[TOBOOL4]], ptr [[ATOMIC_TEMP]], align 1 +// CHECK-NEXT: br label %[[ATOMIC_CONTINUE]] +// CHECK: [[ATOMIC_CONTINUE]]: +// CHECK-NEXT: [[TMP7:%.*]] = load i8, ptr [[ATOMIC_TEMP]], align 1 +// CHECK-NEXT: [[LOADEDV:%.*]] = trunc i8 [[TMP7]] to i1 +// CHECK-NEXT: ret void +// +void test_and_set_dynamic(char *ptr, int order) { + __atomic_test_and_set(ptr, order); +} + +// CHECK-LABEL: define dso_local void @test_and_set_array( +// CHECK-SAME: ) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[X:%.*]] = alloca [10 x i32], align 4 +// CHECK-NEXT: [[ATOMIC_TEMP:%.*]] = alloca i8, align 1 +// CHECK-NEXT: [[ARRAYDECAY:%.*]] = getelementptr inbounds [10 x i32], ptr [[X]], i64 0, i64 0 +// CHECK-NEXT: [[TMP0:%.*]] = atomicrmw volatile xchg ptr [[ARRAYDECAY]], i8 1 seq_cst, align 4 +// CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i8 [[TMP0]], 0 +// CHECK-NEXT: store i1 [[TOBOOL]], ptr [[ATOMIC_TEMP]], align 1 +// CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr [[ATOMIC_TEMP]], align 1 +// CHECK-NEXT: [[LOADEDV:%.*]] = trunc i8 [[TMP1]] to i1 +// CHECK-NEXT: ret void +// +void test_and_set_array() { + volatile int x[10]; + __atomic_test_and_set(x, memory_order_seq_cst); +} + +// These intrinsics accept any pointer type, including void and incomplete +// structs, and always access the first byte regardless of the actual type +// size. + +struct incomplete; + +// CHECK-LABEL: define dso_local void @clear_int( +// CHECK-SAME: ptr noundef [[PTR:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[PTR_ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8 +// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[PTR_ADDR]], align 8 +// CHECK-NEXT: store atomic i8 0, ptr [[TMP0]] monotonic, align 4 +// CHECK-NEXT: ret void +// +void clear_int(int *ptr) { + __atomic_clear(ptr, memory_order_relaxed); +} +// CHECK-LABEL: define dso_local void @clear_void( +// CHECK-SAME: ptr noundef [[PTR:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[PTR_ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8 +// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[PTR_ADDR]], align 8 +// CHECK-NEXT: store atomic i8 0, ptr [[TMP0]] monotonic, align 1 +// CHECK-NEXT: ret void +// +void clear_void(void *ptr) { + __atomic_clear(ptr, memory_order_relaxed); +} +// CHECK-LABEL: define dso_local void @clear_incomplete( +// CHECK-SAME: ptr noundef [[PTR:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[PTR_ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8 +// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[PTR_ADDR]], align 8 +// CHECK-NEXT: store atomic i8 0, ptr [[TMP0]] monotonic, align 1 +// CHECK-NEXT: ret void +// +void clear_incomplete(struct incomplete *ptr) { + __atomic_clear(ptr, memory_order_relaxed); +} + +// CHECK-LABEL: define dso_local void @test_and_set_int( +// CHECK-SAME: ptr noundef [[PTR:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[PTR_ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[ATOMIC_TEMP:%.*]] = alloca i8, align 1 +// CHECK-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8 +// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[PTR_ADDR]], align 8 +// CHECK-NEXT: [[TMP1:%.*]] = atomicrmw xchg ptr [[TMP0]], i8 1 monotonic, align 4 +// CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i8 [[TMP1]], 0 +// CHECK-NEXT: store i1 [[TOBOOL]], ptr [[ATOMIC_TEMP]], align 1 +// CHECK-NEXT: [[TMP2:%.*]] = load i8, ptr [[ATOMIC_TEMP]], align 1 +// CHECK-NEXT: [[LOADEDV:%.*]] = trunc i8 [[TMP2]] to i1 +// CHECK-NEXT: ret void +// +void test_and_set_int(int *ptr) { + __atomic_test_and_set(ptr, memory_order_relaxed); +} +// CHECK-LABEL: define dso_local void @test_and_set_void( +// CHECK-SAME: ptr noundef [[PTR:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[PTR_ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[ATOMIC_TEMP:%.*]] = alloca i8, align 1 +// CHECK-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8 +// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[PTR_ADDR]], align 8 +// CHECK-NEXT: [[TMP1:%.*]] = atomicrmw xchg ptr [[TMP0]], i8 1 monotonic, align 1 +// CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i8 [[TMP1]], 0 +// CHECK-NEXT: store i1 [[TOBOOL]], ptr [[ATOMIC_TEMP]], align 1 +// CHECK-NEXT: [[TMP2:%.*]] = load i8, ptr [[ATOMIC_TEMP]], align 1 +// CHECK-NEXT: [[LOADEDV:%.*]] = trunc i8 [[TMP2]] to i1 +// CHECK-NEXT: ret void +// +void test_and_set_void(void *ptr) { + __atomic_test_and_set(ptr, memory_order_relaxed); +} +// CHECK-LABEL: define dso_local void @test_and_set_incomplete( +// CHECK-SAME: ptr noundef [[PTR:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[PTR_ADDR:%.*]] = alloca ptr, align 8 +// CHECK-NEXT: [[ATOMIC_TEMP:%.*]] = alloca i8, align 1 +// CHECK-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8 +// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[PTR_ADDR]], align 8 +// CHECK-NEXT: [[TMP1:%.*]] = atomicrmw xchg ptr [[TMP0]], i8 1 monotonic, align 1 +// CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i8 [[TMP1]], 0 +// CHECK-NEXT: store i1 [[TOBOOL]], ptr [[ATOMIC_TEMP]], align 1 +// CHECK-NEXT: [[TMP2:%.*]] = load i8, ptr [[ATOMIC_TEMP]], align 1 +// CHECK-NEXT: [[LOADEDV:%.*]] = trunc i8 [[TMP2]] to i1 +// CHECK-NEXT: ret void +// +void test_and_set_incomplete(struct incomplete *ptr) { + __atomic_test_and_set(ptr, memory_order_relaxed); +} diff --git a/clang/test/CodeGenCXX/matrix-vector-bit-int.cpp b/clang/test/CodeGenCXX/matrix-vector-bit-int.cpp index ffbce9ff8d6f4..7dc3b6bd59822 100644 --- a/clang/test/CodeGenCXX/matrix-vector-bit-int.cpp +++ b/clang/test/CodeGenCXX/matrix-vector-bit-int.cpp @@ -15,14 +15,14 @@ using i512x3x3 = _BitInt(512) __attribute__((matrix_type(3, 3))); // CHECK-NEXT: [[A:%.*]] = alloca <3 x i8>, align 4 // CHECK-NEXT: [[A_ADDR:%.*]] = alloca <3 x i8>, align 4 // CHECK-NEXT: store i32 [[A_COERCE]], ptr [[A]], align 4 -// CHECK-NEXT: [[LOADVEC4:%.*]] = load <4 x i8>, ptr [[A]], align 4 -// CHECK-NEXT: [[A1:%.*]] = shufflevector <4 x i8> [[LOADVEC4]], <4 x i8> poison, <3 x i32> +// CHECK-NEXT: [[LOADVECN:%.*]] = load <4 x i8>, ptr [[A]], align 4 +// CHECK-NEXT: [[A1:%.*]] = shufflevector <4 x i8> [[LOADVECN]], <4 x i8> poison, <3 x i32> // CHECK-NEXT: [[EXTRACTVEC:%.*]] = shufflevector <3 x i8> [[A1]], <3 x i8> poison, <4 x i32> // CHECK-NEXT: store <4 x i8> [[EXTRACTVEC]], ptr [[A_ADDR]], align 4 -// CHECK-NEXT: [[LOADVEC42:%.*]] = load <4 x i8>, ptr [[A_ADDR]], align 4 -// CHECK-NEXT: [[EXTRACTVEC3:%.*]] = shufflevector <4 x i8> [[LOADVEC42]], <4 x i8> poison, <3 x i32> -// CHECK-NEXT: [[LOADVEC44:%.*]] = load <4 x i8>, ptr [[A_ADDR]], align 4 -// CHECK-NEXT: [[EXTRACTVEC5:%.*]] = shufflevector <4 x i8> [[LOADVEC44]], <4 x i8> poison, <3 x i32> +// CHECK-NEXT: [[LOADVECN2:%.*]] = load <4 x i8>, ptr [[A_ADDR]], align 4 +// CHECK-NEXT: [[EXTRACTVEC3:%.*]] = shufflevector <4 x i8> [[LOADVECN2]], <4 x i8> poison, <3 x i32> +// CHECK-NEXT: [[LOADVECN4:%.*]] = load <4 x i8>, ptr [[A_ADDR]], align 4 +// CHECK-NEXT: [[EXTRACTVEC5:%.*]] = shufflevector <4 x i8> [[LOADVECN4]], <4 x i8> poison, <3 x i32> // CHECK-NEXT: [[ADD:%.*]] = add <3 x i8> [[EXTRACTVEC3]], [[EXTRACTVEC5]] // CHECK-NEXT: store <3 x i8> [[ADD]], ptr [[RETVAL]], align 4 // CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[RETVAL]], align 4 @@ -38,10 +38,10 @@ i8x3 v1(i8x3 a) { // CHECK-NEXT: [[A_ADDR:%.*]] = alloca <3 x i32>, align 16 // CHECK-NEXT: [[EXTRACTVEC:%.*]] = shufflevector <3 x i32> [[A]], <3 x i32> poison, <4 x i32> // CHECK-NEXT: store <4 x i32> [[EXTRACTVEC]], ptr [[A_ADDR]], align 16 -// CHECK-NEXT: [[LOADVEC4:%.*]] = load <4 x i32>, ptr [[A_ADDR]], align 16 -// CHECK-NEXT: [[EXTRACTVEC1:%.*]] = shufflevector <4 x i32> [[LOADVEC4]], <4 x i32> poison, <3 x i32> -// CHECK-NEXT: [[LOADVEC42:%.*]] = load <4 x i32>, ptr [[A_ADDR]], align 16 -// CHECK-NEXT: [[EXTRACTVEC3:%.*]] = shufflevector <4 x i32> [[LOADVEC42]], <4 x i32> poison, <3 x i32> +// CHECK-NEXT: [[LOADVECN:%.*]] = load <4 x i32>, ptr [[A_ADDR]], align 16 +// CHECK-NEXT: [[EXTRACTVEC1:%.*]] = shufflevector <4 x i32> [[LOADVECN]], <4 x i32> poison, <3 x i32> +// CHECK-NEXT: [[LOADVECN2:%.*]] = load <4 x i32>, ptr [[A_ADDR]], align 16 +// CHECK-NEXT: [[EXTRACTVEC3:%.*]] = shufflevector <4 x i32> [[LOADVECN2]], <4 x i32> poison, <3 x i32> // CHECK-NEXT: [[ADD:%.*]] = add <3 x i32> [[EXTRACTVEC1]], [[EXTRACTVEC3]] // CHECK-NEXT: ret <3 x i32> [[ADD]] // @@ -53,14 +53,14 @@ i32x3 v2(i32x3 a) { // CHECK-SAME: ptr noundef byval(<3 x i512>) align 256 [[TMP0:%.*]]) #[[ATTR2:[0-9]+]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[A_ADDR:%.*]] = alloca <3 x i512>, align 256 -// CHECK-NEXT: [[LOADVEC4:%.*]] = load <4 x i512>, ptr [[TMP0]], align 256 -// CHECK-NEXT: [[A:%.*]] = shufflevector <4 x i512> [[LOADVEC4]], <4 x i512> poison, <3 x i32> +// CHECK-NEXT: [[LOADVECN:%.*]] = load <4 x i512>, ptr [[TMP0]], align 256 +// CHECK-NEXT: [[A:%.*]] = shufflevector <4 x i512> [[LOADVECN]], <4 x i512> poison, <3 x i32> // CHECK-NEXT: [[EXTRACTVEC:%.*]] = shufflevector <3 x i512> [[A]], <3 x i512> poison, <4 x i32> // CHECK-NEXT: store <4 x i512> [[EXTRACTVEC]], ptr [[A_ADDR]], align 256 -// CHECK-NEXT: [[LOADVEC41:%.*]] = load <4 x i512>, ptr [[A_ADDR]], align 256 -// CHECK-NEXT: [[EXTRACTVEC2:%.*]] = shufflevector <4 x i512> [[LOADVEC41]], <4 x i512> poison, <3 x i32> -// CHECK-NEXT: [[LOADVEC43:%.*]] = load <4 x i512>, ptr [[A_ADDR]], align 256 -// CHECK-NEXT: [[EXTRACTVEC4:%.*]] = shufflevector <4 x i512> [[LOADVEC43]], <4 x i512> poison, <3 x i32> +// CHECK-NEXT: [[LOADVECN1:%.*]] = load <4 x i512>, ptr [[A_ADDR]], align 256 +// CHECK-NEXT: [[EXTRACTVEC2:%.*]] = shufflevector <4 x i512> [[LOADVECN1]], <4 x i512> poison, <3 x i32> +// CHECK-NEXT: [[LOADVECN3:%.*]] = load <4 x i512>, ptr [[A_ADDR]], align 256 +// CHECK-NEXT: [[EXTRACTVEC4:%.*]] = shufflevector <4 x i512> [[LOADVECN3]], <4 x i512> poison, <3 x i32> // CHECK-NEXT: [[ADD:%.*]] = add <3 x i512> [[EXTRACTVEC2]], [[EXTRACTVEC4]] // CHECK-NEXT: ret <3 x i512> [[ADD]] // diff --git a/clang/test/CodeGenCXX/ptrauth-member-function-pointer.cpp b/clang/test/CodeGenCXX/ptrauth-member-function-pointer.cpp index 0a9ac3fa510f5..e9436f11b5106 100644 --- a/clang/test/CodeGenCXX/ptrauth-member-function-pointer.cpp +++ b/clang/test/CodeGenCXX/ptrauth-member-function-pointer.cpp @@ -1,10 +1,12 @@ // RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -fptrauth-intrinsics -emit-llvm -std=c++11 -O1 -disable-llvm-passes -o - %s | FileCheck -check-prefixes=CHECK,NODEBUG,DARWIN %s +// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -fptrauth-intrinsics -emit-llvm -std=c++17 -O1 -disable-llvm-passes -o - %s | FileCheck -check-prefixes=CHECK,NODEBUG,DARWIN,CXX17 %s // RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -fptrauth-intrinsics -emit-llvm -std=c++11 -O1 -disable-llvm-passes -debug-info-kind=limited -o - %s | FileCheck -check-prefixes=CHECK,DARWIN %s // RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -fptrauth-intrinsics -emit-llvm -std=c++11 -O1 -disable-llvm-passes -stack-protector 1 -o - %s | FileCheck %s -check-prefix=STACK-PROT // RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -fptrauth-intrinsics -emit-llvm -std=c++11 -O1 -disable-llvm-passes -stack-protector 2 -o - %s | FileCheck %s -check-prefix=STACK-PROT // RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -fptrauth-intrinsics -emit-llvm -std=c++11 -O1 -disable-llvm-passes -stack-protector 3 -o - %s | FileCheck %s -check-prefix=STACK-PROT // RUN: %clang_cc1 -triple aarch64-linux-gnu -fptrauth-calls -fptrauth-intrinsics -emit-llvm -std=c++11 -O1 -disable-llvm-passes -o - %s | FileCheck -check-prefixes=CHECK,NODEBUG,ELF %s +// RUN: %clang_cc1 -triple aarch64-linux-gnu -fptrauth-calls -fptrauth-intrinsics -emit-llvm -std=c++17 -O1 -disable-llvm-passes -o - %s | FileCheck -check-prefixes=CHECK,NODEBUG,ELF,CXX17 %s // RUN: %clang_cc1 -triple aarch64-linux-gnu -fptrauth-calls -fptrauth-intrinsics -emit-llvm -std=c++11 -O1 -disable-llvm-passes -debug-info-kind=limited -o - %s | FileCheck -check-prefixes=CHECK,ELF %s // RUN: %clang_cc1 -triple aarch64-linux-gnu -fptrauth-calls -fptrauth-intrinsics -emit-llvm -std=c++11 -O1 -disable-llvm-passes -stack-protector 1 -o - %s | FileCheck %s -check-prefix=STACK-PROT // RUN: %clang_cc1 -triple aarch64-linux-gnu -fptrauth-calls -fptrauth-intrinsics -emit-llvm -std=c++11 -O1 -disable-llvm-passes -stack-protector 2 -o - %s | FileCheck %s -check-prefix=STACK-PROT @@ -20,6 +22,10 @@ // CHECK: @__const._Z13testArrayInitv.c0 = private unnamed_addr constant %struct.Class0 { { i64, i64 } { i64 ptrtoint (ptr ptrauth (ptr @_ZN5Base011nonvirtual0Ev, i32 0, i64 35591) to i64), i64 0 } }, align 8 // CHECK: @__const._Z13testArrayInitv.c1 = private unnamed_addr constant %struct.Class0 { { i64, i64 } { i64 ptrtoint (ptr ptrauth (ptr @_ZN5Base08virtual1Ev_vfpthunk_, i32 0, i64 35591) to i64), i64 0 } }, align 8 +// CHECK: @_ZN22testNoexceptConversion6mfptr1E = global { i64, i64 } { i64 ptrtoint (ptr ptrauth (ptr @_ZN22testNoexceptConversion1S19nonvirtual_noexceptEv, i32 0, i64 [[TYPEDISC3:.*]]) to i64), i64 0 }, +// CHECK: @_ZN22testNoexceptConversion6mfptr2E = global { i64, i64 } { i64 ptrtoint (ptr ptrauth (ptr @_ZN22testNoexceptConversion1S16virtual_noexceptEv_vfpthunk_, i32 0, i64 [[TYPEDISC3]]) to i64), i64 0 }, +// CHECK: @_ZN22testNoexceptConversion15mfptr3_noexceptE = global { i64, i64 } { i64 ptrtoint (ptr ptrauth (ptr @_ZN22testNoexceptConversion1S19nonvirtual_noexceptEv, i32 0, i64 [[TYPEDISC3]]) to i64), i64 0 }, + // CHECK: @_ZTV5Base0 = unnamed_addr constant { [5 x ptr] } { [5 x ptr] [ptr null, ptr @_ZTI5Base0, // CHECK-SAME: ptr ptrauth (ptr @_ZN5Base08virtual1Ev, i32 0, i64 55600, ptr getelementptr inbounds ({ [5 x ptr] }, ptr @_ZTV5Base0, i32 0, i32 0, i32 2)), // CHECK-SAME: ptr ptrauth (ptr @_ZN5Base08virtual3Ev, i32 0, i64 53007, ptr getelementptr inbounds ({ [5 x ptr] }, ptr @_ZTV5Base0, i32 0, i32 0, i32 3)), @@ -77,6 +83,9 @@ struct Derived1 : Base0, Base1 { }; typedef void (Base0::*MethodTy0)(); +#if __cplusplus >= 201703L +typedef void (Base0::*NoExceptMethodTy0)() noexcept; +#endif typedef void (Base0::*VariadicMethodTy0)(int, ...); typedef void (Derived0::*MethodTy1)(); @@ -293,6 +302,16 @@ void test1(Base0 *a0, MethodTy0 a1) { (a0->*a1)(); } +// CXX17: define{{.*}} void @_Z14test1_noexceptP5Base0MS_DoFvvE( +// CXX17: %[[V14:.*]] = phi ptr [ %{{.*}}, {{.*}} ], [ %{{.*}}, {{.*}} ] +// CXX17: %[[V15:.*]] = phi i64 [ 0, {{.*}} ], [ [[TYPEDISC0]], {{.*}} ] +// CXX17: call void %[[V14]](ptr noundef nonnull align {{[0-9]+}} dereferenceable(8) %{{.*}}) {{.*}}[ "ptrauth"(i32 0, i64 %[[V15]]) ] +#if __cplusplus >= 201703L +void test1_noexcept(Base0 *a0, NoExceptMethodTy0 a1) { + (a0->*a1)(); +} +#endif + // CHECK: define{{.*}} void @_Z15testConversion0M5Base0FvvEM8Derived0FvvE([2 x i64] %[[METHOD0_COERCE:.*]], [2 x i64] %[[METHOD1_COERCE:.*]]) // CHECK: %[[METHOD0:.*]] = alloca { i64, i64 }, align 8 // CHECK: %[[METHOD1:.*]] = alloca { i64, i64 }, align 8 @@ -438,3 +457,47 @@ void testArrayInit() { void testConvertNull() { VariadicMethodTy0 t = (VariadicMethodTy0)(MethodTy0{}); } + +namespace testNoexceptConversion { + +// CHECK-LABEL: define internal void @__cxx_global_var_init() +// CHECK: %[[V0:.*]] = load { i64, i64 }, ptr @_ZN22testNoexceptConversion15mfptr0_noexceptE, align 8 +// CHECK: store { i64, i64 } %[[V0]], ptr @_ZN22testNoexceptConversion6mfptr4E, align 8 + +// CHECK: define {{.*}}void @_ZN22testNoexceptConversion5test0Ev() +// CHECK: %[[P0:.*]] = alloca { i64, i64 }, align 8 +// CHECK: store { i64, i64 } { i64 ptrtoint (ptr ptrauth (ptr @_ZN22testNoexceptConversion1S19nonvirtual_noexceptEv, i32 0, i64 [[TYPEDISC3]]) to i64), i64 0 }, ptr %[[P0]], align 8, + +// CHECK: define {{.*}}void @_ZN22testNoexceptConversion5test1Ev() +// CHECK: %[[P0:.*]] = alloca { i64, i64 }, align 8 +// CHECK: store { i64, i64 } { i64 ptrtoint (ptr ptrauth (ptr @_ZN22testNoexceptConversion1S16virtual_noexceptEv_vfpthunk_, i32 0, i64 [[TYPEDISC3]]) to i64), i64 0 }, ptr %[[P0]], align 8, + +// CHECK: define {{.*}}void @_ZN22testNoexceptConversion5test2Ev() +// CHECK: %[[P0:.*]] = alloca { i64, i64 }, align 8 +// CHECK: %[[V0:.*]] = load { i64, i64 }, ptr @_ZN22testNoexceptConversion15mfptr0_noexceptE, align 8 +// CHECK: store { i64, i64 } %[[V0]], ptr %[[P0]], align 8, + +struct S { + void nonvirtual_noexcept() noexcept; + virtual void virtual_noexcept() noexcept; +}; + +void (S::*mfptr0_noexcept)() noexcept; +void (S::*mfptr1)() = &S::nonvirtual_noexcept; +void (S::*mfptr2)() = &S::virtual_noexcept; +void (S::*mfptr3_noexcept)() noexcept = &S::nonvirtual_noexcept; +void (S::*mfptr4)() = mfptr0_noexcept; + +void test0() { + void (S::*p0)() = &S::nonvirtual_noexcept; +} + +void test1() { + void (S::*p0)() = &S::virtual_noexcept; +} + +void test2() { + void (S::*p0)() = mfptr0_noexcept; +} + +} diff --git a/clang/test/CodeGenOpenCL/amdgpu-alignment.cl b/clang/test/CodeGenOpenCL/amdgpu-alignment.cl index 8f57713fe1f04..3c2653bf34124 100644 --- a/clang/test/CodeGenOpenCL/amdgpu-alignment.cl +++ b/clang/test/CodeGenOpenCL/amdgpu-alignment.cl @@ -106,7 +106,7 @@ typedef double __attribute__((ext_vector_type(16))) double16; // CHECK: store volatile <16 x i16> zeroinitializer, ptr addrspace(3) @local_memory_alignment_global.lds_v16i16, align 32 // CHECK: store volatile i32 0, ptr addrspace(3) @local_memory_alignment_global.lds_i32, align 4 // CHECK: store volatile <2 x i32> zeroinitializer, ptr addrspace(3) @local_memory_alignment_global.lds_v2i32, align 8 -// CHECK: store volatile <4 x i32> , ptr addrspace(3) @local_memory_alignment_global.lds_v3i32, align 16 +// CHECK: store volatile <3 x i32> zeroinitializer, ptr addrspace(3) @local_memory_alignment_global.lds_v3i32, align 16 // CHECK: store volatile <4 x i32> zeroinitializer, ptr addrspace(3) @local_memory_alignment_global.lds_v4i32, align 16 // CHECK: store volatile <8 x i32> zeroinitializer, ptr addrspace(3) @local_memory_alignment_global.lds_v8i32, align 32 // CHECK: store volatile <16 x i32> zeroinitializer, ptr addrspace(3) @local_memory_alignment_global.lds_v16i32, align 64 @@ -124,7 +124,7 @@ typedef double __attribute__((ext_vector_type(16))) double16; // CHECK: store volatile <16 x half> zeroinitializer, ptr addrspace(3) @local_memory_alignment_global.lds_v16f16, align 32 // CHECK: store volatile float 0.000000e+00, ptr addrspace(3) @local_memory_alignment_global.lds_f32, align 4 // CHECK: store volatile <2 x float> zeroinitializer, ptr addrspace(3) @local_memory_alignment_global.lds_v2f32, align 8 -// CHECK: store volatile <4 x float> , ptr addrspace(3) @local_memory_alignment_global.lds_v3f32, align 16 +// CHECK: store volatile <3 x float> zeroinitializer, ptr addrspace(3) @local_memory_alignment_global.lds_v3f32, align 16 // CHECK: store volatile <4 x float> zeroinitializer, ptr addrspace(3) @local_memory_alignment_global.lds_v4f32, align 16 // CHECK: store volatile <8 x float> zeroinitializer, ptr addrspace(3) @local_memory_alignment_global.lds_v8f32, align 32 // CHECK: store volatile <16 x float> zeroinitializer, ptr addrspace(3) @local_memory_alignment_global.lds_v16f32, align 64 @@ -393,7 +393,7 @@ kernel void local_memory_alignment_arg( // CHECK: store volatile <16 x i16> zeroinitializer, ptr addrspace(5) %arraydecay{{[0-9]+}}, align 32 // CHECK: store volatile i32 0, ptr addrspace(5) %arraydecay{{[0-9]+}}, align 4 // CHECK: store volatile <2 x i32> zeroinitializer, ptr addrspace(5) %arraydecay{{[0-9]+}}, align 8 -// CHECK: store volatile <4 x i32> , ptr addrspace(5) %arraydecay{{[0-9]+}}, align 16 +// CHECK: store volatile <3 x i32> zeroinitializer, ptr addrspace(5) %arraydecay{{[0-9]+}}, align 16 // CHECK: store volatile <4 x i32> zeroinitializer, ptr addrspace(5) %arraydecay{{[0-9]+}}, align 16 // CHECK: store volatile <8 x i32> zeroinitializer, ptr addrspace(5) %arraydecay{{[0-9]+}}, align 32 // CHECK: store volatile <16 x i32> zeroinitializer, ptr addrspace(5) %arraydecay{{[0-9]+}}, align 64 @@ -411,7 +411,7 @@ kernel void local_memory_alignment_arg( // CHECK: store volatile <16 x half> zeroinitializer, ptr addrspace(5) %arraydecay{{[0-9]+}}, align 32 // CHECK: store volatile float 0.000000e+00, ptr addrspace(5) %arraydecay{{[0-9]+}}, align 4 // CHECK: store volatile <2 x float> zeroinitializer, ptr addrspace(5) %arraydecay{{[0-9]+}}, align 8 -// CHECK: store volatile <4 x float> , ptr addrspace(5) %arraydecay{{[0-9]+}}, align 16 +// CHECK: store volatile <3 x float> zeroinitializer, ptr addrspace(5) %arraydecay{{[0-9]+}}, align 16 // CHECK: store volatile <4 x float> zeroinitializer, ptr addrspace(5) %arraydecay{{[0-9]+}}, align 16 // CHECK: store volatile <8 x float> zeroinitializer, ptr addrspace(5) %arraydecay{{[0-9]+}}, align 32 // CHECK: store volatile <16 x float> zeroinitializer, ptr addrspace(5) %arraydecay{{[0-9]+}}, align 64 diff --git a/clang/test/CodeGenOpenCL/preserve_vec3.cl b/clang/test/CodeGenOpenCL/preserve_vec3.cl index c84effe0c4b6e..747cc301feff6 100644 --- a/clang/test/CodeGenOpenCL/preserve_vec3.cl +++ b/clang/test/CodeGenOpenCL/preserve_vec3.cl @@ -1,5 +1,5 @@ // NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5 -// RUN: %clang_cc1 %s -emit-llvm -o - -triple spir-unknown-unknown -fpreserve-vec3-type | FileCheck %s +// RUN: %clang_cc1 %s -emit-llvm -o - -triple spir-unknown-unknown | FileCheck %s typedef char char3 __attribute__((ext_vector_type(3))); typedef char char8 __attribute__((ext_vector_type(8))); @@ -9,10 +9,11 @@ typedef float float3 __attribute__((ext_vector_type(3))); typedef float float4 __attribute__((ext_vector_type(4))); // CHECK-LABEL: define dso_local spir_kernel void @foo( -// CHECK-SAME: ptr addrspace(1) nocapture noundef readonly align 16 [[A:%.*]], ptr addrspace(1) nocapture noundef writeonly align 16 initializes((0, 12)) [[B:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] !kernel_arg_addr_space [[META3:![0-9]+]] !kernel_arg_access_qual [[META4:![0-9]+]] !kernel_arg_type [[META5:![0-9]+]] !kernel_arg_base_type [[META6:![0-9]+]] !kernel_arg_type_qual [[META7:![0-9]+]] { +// CHECK-SAME: ptr addrspace(1) nocapture noundef readonly align 16 [[A:%.*]], ptr addrspace(1) nocapture noundef writeonly align 16 initializes((0, 16)) [[B:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] !kernel_arg_addr_space [[META3:![0-9]+]] !kernel_arg_access_qual [[META4:![0-9]+]] !kernel_arg_type [[META5:![0-9]+]] !kernel_arg_base_type [[META6:![0-9]+]] !kernel_arg_type_qual [[META7:![0-9]+]] { // CHECK-NEXT: [[ENTRY:.*:]] -// CHECK-NEXT: [[TMP0:%.*]] = load <3 x float>, ptr addrspace(1) [[A]], align 16, !tbaa [[TBAA8:![0-9]+]] -// CHECK-NEXT: store <3 x float> [[TMP0]], ptr addrspace(1) [[B]], align 16, !tbaa [[TBAA8]] +// CHECK-NEXT: [[LOADVECN:%.*]] = load <4 x float>, ptr addrspace(1) [[A]], align 16 +// CHECK-NEXT: [[EXTRACTVEC1:%.*]] = shufflevector <4 x float> [[LOADVECN]], <4 x float> poison, <4 x i32> +// CHECK-NEXT: store <4 x float> [[EXTRACTVEC1]], ptr addrspace(1) [[B]], align 16, !tbaa [[TBAA8:![0-9]+]] // CHECK-NEXT: ret void // void kernel foo(global float3 *a, global float3 *b) { @@ -20,11 +21,11 @@ void kernel foo(global float3 *a, global float3 *b) { } // CHECK-LABEL: define dso_local spir_kernel void @float4_to_float3( -// CHECK-SAME: ptr addrspace(1) nocapture noundef writeonly align 16 initializes((0, 12)) [[A:%.*]], ptr addrspace(1) nocapture noundef readonly align 16 [[B:%.*]]) local_unnamed_addr #[[ATTR0]] !kernel_arg_addr_space [[META3]] !kernel_arg_access_qual [[META4]] !kernel_arg_type [[META11:![0-9]+]] !kernel_arg_base_type [[META12:![0-9]+]] !kernel_arg_type_qual [[META7]] { +// CHECK-SAME: ptr addrspace(1) nocapture noundef writeonly align 16 initializes((0, 16)) [[A:%.*]], ptr addrspace(1) nocapture noundef readonly align 16 [[B:%.*]]) local_unnamed_addr #[[ATTR0]] !kernel_arg_addr_space [[META3]] !kernel_arg_access_qual [[META4]] !kernel_arg_type [[META11:![0-9]+]] !kernel_arg_base_type [[META12:![0-9]+]] !kernel_arg_type_qual [[META7]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[TMP0:%.*]] = load <4 x float>, ptr addrspace(1) [[B]], align 16, !tbaa [[TBAA8]] -// CHECK-NEXT: [[ASTYPE:%.*]] = shufflevector <4 x float> [[TMP0]], <4 x float> poison, <3 x i32> -// CHECK-NEXT: store <3 x float> [[ASTYPE]], ptr addrspace(1) [[A]], align 16, !tbaa [[TBAA8]] +// CHECK-NEXT: [[EXTRACTVEC:%.*]] = shufflevector <4 x float> [[TMP0]], <4 x float> poison, <4 x i32> +// CHECK-NEXT: store <4 x float> [[EXTRACTVEC]], ptr addrspace(1) [[A]], align 16, !tbaa [[TBAA8]] // CHECK-NEXT: ret void // void kernel float4_to_float3(global float3 *a, global float4 *b) { @@ -34,8 +35,8 @@ void kernel float4_to_float3(global float3 *a, global float4 *b) { // CHECK-LABEL: define dso_local spir_kernel void @float3_to_float4( // CHECK-SAME: ptr addrspace(1) nocapture noundef readonly align 16 [[A:%.*]], ptr addrspace(1) nocapture noundef writeonly align 16 initializes((0, 16)) [[B:%.*]]) local_unnamed_addr #[[ATTR0]] !kernel_arg_addr_space [[META3]] !kernel_arg_access_qual [[META4]] !kernel_arg_type [[META11]] !kernel_arg_base_type [[META12]] !kernel_arg_type_qual [[META7]] { // CHECK-NEXT: [[ENTRY:.*:]] -// CHECK-NEXT: [[TMP0:%.*]] = load <3 x float>, ptr addrspace(1) [[A]], align 16, !tbaa [[TBAA8]] -// CHECK-NEXT: [[ASTYPE:%.*]] = shufflevector <3 x float> [[TMP0]], <3 x float> poison, <4 x i32> +// CHECK-NEXT: [[LOADVECN:%.*]] = load <4 x float>, ptr addrspace(1) [[A]], align 16 +// CHECK-NEXT: [[ASTYPE:%.*]] = shufflevector <4 x float> [[LOADVECN]], <4 x float> poison, <4 x i32> // CHECK-NEXT: store <4 x float> [[ASTYPE]], ptr addrspace(1) [[B]], align 16, !tbaa [[TBAA8]] // CHECK-NEXT: ret void // @@ -46,9 +47,9 @@ void kernel float3_to_float4(global float3 *a, global float4 *b) { // CHECK-LABEL: define dso_local spir_kernel void @float3_to_double2( // CHECK-SAME: ptr addrspace(1) nocapture noundef readonly align 16 [[A:%.*]], ptr addrspace(1) nocapture noundef writeonly align 16 initializes((0, 16)) [[B:%.*]]) local_unnamed_addr #[[ATTR0]] !kernel_arg_addr_space [[META3]] !kernel_arg_access_qual [[META4]] !kernel_arg_type [[META13:![0-9]+]] !kernel_arg_base_type [[META14:![0-9]+]] !kernel_arg_type_qual [[META7]] { // CHECK-NEXT: [[ENTRY:.*:]] -// CHECK-NEXT: [[TMP0:%.*]] = load <3 x float>, ptr addrspace(1) [[A]], align 16, !tbaa [[TBAA8]] -// CHECK-NEXT: [[TMP1:%.*]] = shufflevector <3 x float> [[TMP0]], <3 x float> poison, <4 x i32> -// CHECK-NEXT: store <4 x float> [[TMP1]], ptr addrspace(1) [[B]], align 16, !tbaa [[TBAA8]] +// CHECK-NEXT: [[LOADVECN:%.*]] = load <4 x float>, ptr addrspace(1) [[A]], align 16 +// CHECK-NEXT: [[TMP0:%.*]] = shufflevector <4 x float> [[LOADVECN]], <4 x float> poison, <4 x i32> +// CHECK-NEXT: store <4 x float> [[TMP0]], ptr addrspace(1) [[B]], align 16, !tbaa [[TBAA8]] // CHECK-NEXT: ret void // void kernel float3_to_double2(global float3 *a, global double2 *b) { @@ -56,11 +57,11 @@ void kernel float3_to_double2(global float3 *a, global double2 *b) { } // CHECK-LABEL: define dso_local spir_kernel void @char8_to_short3( -// CHECK-SAME: ptr addrspace(1) nocapture noundef writeonly align 8 initializes((0, 6)) [[A:%.*]], ptr addrspace(1) nocapture noundef readonly align 8 [[B:%.*]]) local_unnamed_addr #[[ATTR0]] !kernel_arg_addr_space [[META3]] !kernel_arg_access_qual [[META4]] !kernel_arg_type [[META15:![0-9]+]] !kernel_arg_base_type [[META16:![0-9]+]] !kernel_arg_type_qual [[META7]] { +// CHECK-SAME: ptr addrspace(1) nocapture noundef writeonly align 8 initializes((0, 8)) [[A:%.*]], ptr addrspace(1) nocapture noundef readonly align 8 [[B:%.*]]) local_unnamed_addr #[[ATTR0]] !kernel_arg_addr_space [[META3]] !kernel_arg_access_qual [[META4]] !kernel_arg_type [[META15:![0-9]+]] !kernel_arg_base_type [[META16:![0-9]+]] !kernel_arg_type_qual [[META7]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[TMP0:%.*]] = load <4 x i16>, ptr addrspace(1) [[B]], align 8, !tbaa [[TBAA8]] -// CHECK-NEXT: [[ASTYPE:%.*]] = shufflevector <4 x i16> [[TMP0]], <4 x i16> poison, <3 x i32> -// CHECK-NEXT: store <3 x i16> [[ASTYPE]], ptr addrspace(1) [[A]], align 8, !tbaa [[TBAA8]] +// CHECK-NEXT: [[EXTRACTVEC:%.*]] = shufflevector <4 x i16> [[TMP0]], <4 x i16> poison, <4 x i32> +// CHECK-NEXT: store <4 x i16> [[EXTRACTVEC]], ptr addrspace(1) [[A]], align 8, !tbaa [[TBAA8]] // CHECK-NEXT: ret void // void kernel char8_to_short3(global short3 *a, global char8 *b) { @@ -70,8 +71,8 @@ void kernel char8_to_short3(global short3 *a, global char8 *b) { // CHECK-LABEL: define dso_local spir_func void @from_char3( // CHECK-SAME: <3 x i8> noundef [[A:%.*]], ptr addrspace(1) nocapture noundef writeonly initializes((0, 4)) [[OUT:%.*]]) local_unnamed_addr #[[ATTR1:[0-9]+]] { // CHECK-NEXT: [[ENTRY:.*:]] -// CHECK-NEXT: [[TMP0:%.*]] = shufflevector <3 x i8> [[A]], <3 x i8> poison, <4 x i32> -// CHECK-NEXT: store <4 x i8> [[TMP0]], ptr addrspace(1) [[OUT]], align 4, !tbaa [[TBAA17:![0-9]+]] +// CHECK-NEXT: [[EXTRACTVEC:%.*]] = shufflevector <3 x i8> [[A]], <3 x i8> poison, <4 x i32> +// CHECK-NEXT: store <4 x i8> [[EXTRACTVEC]], ptr addrspace(1) [[OUT]], align 4, !tbaa [[TBAA17:![0-9]+]] // CHECK-NEXT: ret void // void from_char3(char3 a, global int *out) { @@ -81,8 +82,8 @@ void from_char3(char3 a, global int *out) { // CHECK-LABEL: define dso_local spir_func void @from_short3( // CHECK-SAME: <3 x i16> noundef [[A:%.*]], ptr addrspace(1) nocapture noundef writeonly initializes((0, 8)) [[OUT:%.*]]) local_unnamed_addr #[[ATTR1]] { // CHECK-NEXT: [[ENTRY:.*:]] -// CHECK-NEXT: [[TMP0:%.*]] = shufflevector <3 x i16> [[A]], <3 x i16> poison, <4 x i32> -// CHECK-NEXT: store <4 x i16> [[TMP0]], ptr addrspace(1) [[OUT]], align 8, !tbaa [[TBAA19:![0-9]+]] +// CHECK-NEXT: [[EXTRACTVEC:%.*]] = shufflevector <3 x i16> [[A]], <3 x i16> poison, <4 x i32> +// CHECK-NEXT: store <4 x i16> [[EXTRACTVEC]], ptr addrspace(1) [[OUT]], align 8, !tbaa [[TBAA19:![0-9]+]] // CHECK-NEXT: ret void // void from_short3(short3 a, global long *out) { @@ -90,11 +91,11 @@ void from_short3(short3 a, global long *out) { } // CHECK-LABEL: define dso_local spir_func void @scalar_to_char3( -// CHECK-SAME: i32 noundef [[A:%.*]], ptr addrspace(1) nocapture noundef writeonly initializes((0, 3)) [[OUT:%.*]]) local_unnamed_addr #[[ATTR1]] { +// CHECK-SAME: i32 noundef [[A:%.*]], ptr addrspace(1) nocapture noundef writeonly initializes((0, 4)) [[OUT:%.*]]) local_unnamed_addr #[[ATTR1]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[TMP0:%.*]] = bitcast i32 [[A]] to <4 x i8> -// CHECK-NEXT: [[ASTYPE:%.*]] = shufflevector <4 x i8> [[TMP0]], <4 x i8> poison, <3 x i32> -// CHECK-NEXT: store <3 x i8> [[ASTYPE]], ptr addrspace(1) [[OUT]], align 4, !tbaa [[TBAA8]] +// CHECK-NEXT: [[EXTRACTVEC:%.*]] = shufflevector <4 x i8> [[TMP0]], <4 x i8> poison, <4 x i32> +// CHECK-NEXT: store <4 x i8> [[EXTRACTVEC]], ptr addrspace(1) [[OUT]], align 4, !tbaa [[TBAA8]] // CHECK-NEXT: ret void // void scalar_to_char3(int a, global char3 *out) { @@ -102,11 +103,11 @@ void scalar_to_char3(int a, global char3 *out) { } // CHECK-LABEL: define dso_local spir_func void @scalar_to_short3( -// CHECK-SAME: i64 noundef [[A:%.*]], ptr addrspace(1) nocapture noundef writeonly initializes((0, 6)) [[OUT:%.*]]) local_unnamed_addr #[[ATTR1]] { +// CHECK-SAME: i64 noundef [[A:%.*]], ptr addrspace(1) nocapture noundef writeonly initializes((0, 8)) [[OUT:%.*]]) local_unnamed_addr #[[ATTR1]] { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[TMP0:%.*]] = bitcast i64 [[A]] to <4 x i16> -// CHECK-NEXT: [[ASTYPE:%.*]] = shufflevector <4 x i16> [[TMP0]], <4 x i16> poison, <3 x i32> -// CHECK-NEXT: store <3 x i16> [[ASTYPE]], ptr addrspace(1) [[OUT]], align 8, !tbaa [[TBAA8]] +// CHECK-NEXT: [[EXTRACTVEC:%.*]] = shufflevector <4 x i16> [[TMP0]], <4 x i16> poison, <4 x i32> +// CHECK-NEXT: store <4 x i16> [[EXTRACTVEC]], ptr addrspace(1) [[OUT]], align 8, !tbaa [[TBAA8]] // CHECK-NEXT: ret void // void scalar_to_short3(long a, global short3 *out) { diff --git a/clang/test/Driver/darwin-version.c b/clang/test/Driver/darwin-version.c index ff05d4c10c487..a00bd832dc802 100644 --- a/clang/test/Driver/darwin-version.c +++ b/clang/test/Driver/darwin-version.c @@ -1,6 +1,6 @@ // RUN: %clang -target armv6-apple-darwin9 -c %s -### 2>&1 | \ -// RUN: FileCheck --check-prefix=CHECK-VERSION-OSX %s -// CHECK-VERSION-OSX: "armv6k-apple-macosx10.5.0" +// RUN: FileCheck --check-prefix=CHECK-VERSION-IOS %s +// CHECK-VERSION-IOS: "armv6k-apple-ios5.0.0" // RUN: %clang -target armv6-apple-darwin9 -miphoneos-version-min=2.0 -c %s -### 2>&1 | \ // RUN: FileCheck --check-prefix=CHECK-VERSION-IOS2 %s // CHECK-VERSION-IOS2: "armv6k-apple-ios2.0.0" diff --git a/clang/test/Driver/print-enabled-extensions/aarch64-ampere1b.c b/clang/test/Driver/print-enabled-extensions/aarch64-ampere1b.c index d9bee7093bee2..444ac4526200f 100644 --- a/clang/test/Driver/print-enabled-extensions/aarch64-ampere1b.c +++ b/clang/test/Driver/print-enabled-extensions/aarch64-ampere1b.c @@ -51,7 +51,6 @@ // CHECK-NEXT: FEAT_SHA3, FEAT_SHA512 Enable SHA512 and SHA3 support // CHECK-NEXT: FEAT_SM4, FEAT_SM3 Enable SM3 and SM4 support // CHECK-NEXT: FEAT_SPECRES Enable Armv8.5-A execution and data prediction invalidation instructions -// CHECK-NEXT: FEAT_SPEv1p2 Enable extra register in the Statistical Profiling Extension // CHECK-NEXT: FEAT_SSBS, FEAT_SSBS2 Enable Speculative Store Bypass Safe bit // CHECK-NEXT: FEAT_TLBIOS, FEAT_TLBIRANGE Enable Armv8.4-A TLB Range and Maintenance instructions // CHECK-NEXT: FEAT_TRF Enable Armv8.4-A Trace extension diff --git a/clang/test/Driver/print-enabled-extensions/aarch64-cortex-a520.c b/clang/test/Driver/print-enabled-extensions/aarch64-cortex-a520.c index b906074ce7659..6ddd52a4a7089 100644 --- a/clang/test/Driver/print-enabled-extensions/aarch64-cortex-a520.c +++ b/clang/test/Driver/print-enabled-extensions/aarch64-cortex-a520.c @@ -46,7 +46,6 @@ // CHECK-NEXT: FEAT_SB Enable Armv8.5-A Speculation Barrier // CHECK-NEXT: FEAT_SEL2 Enable Armv8.4-A Secure Exception Level 2 extension // CHECK-NEXT: FEAT_SPECRES Enable Armv8.5-A execution and data prediction invalidation instructions -// CHECK-NEXT: FEAT_SPEv1p2 Enable extra register in the Statistical Profiling Extension // CHECK-NEXT: FEAT_SSBS, FEAT_SSBS2 Enable Speculative Store Bypass Safe bit // CHECK-NEXT: FEAT_SVE Enable Scalable Vector Extension (SVE) instructions // CHECK-NEXT: FEAT_SVE2 Enable Scalable Vector Extension 2 (SVE2) instructions diff --git a/clang/test/Driver/print-enabled-extensions/aarch64-cortex-a520ae.c b/clang/test/Driver/print-enabled-extensions/aarch64-cortex-a520ae.c index 2e147732d5c68..35399a3c85c62 100644 --- a/clang/test/Driver/print-enabled-extensions/aarch64-cortex-a520ae.c +++ b/clang/test/Driver/print-enabled-extensions/aarch64-cortex-a520ae.c @@ -46,7 +46,6 @@ // CHECK-NEXT: FEAT_SB Enable Armv8.5-A Speculation Barrier // CHECK-NEXT: FEAT_SEL2 Enable Armv8.4-A Secure Exception Level 2 extension // CHECK-NEXT: FEAT_SPECRES Enable Armv8.5-A execution and data prediction invalidation instructions -// CHECK-NEXT: FEAT_SPEv1p2 Enable extra register in the Statistical Profiling Extension // CHECK-NEXT: FEAT_SSBS, FEAT_SSBS2 Enable Speculative Store Bypass Safe bit // CHECK-NEXT: FEAT_SVE Enable Scalable Vector Extension (SVE) instructions // CHECK-NEXT: FEAT_SVE2 Enable Scalable Vector Extension 2 (SVE2) instructions diff --git a/clang/test/Driver/print-enabled-extensions/aarch64-fujitsu-monaka.c b/clang/test/Driver/print-enabled-extensions/aarch64-fujitsu-monaka.c index 01a97a00de542..a80d0f5c79ec1 100644 --- a/clang/test/Driver/print-enabled-extensions/aarch64-fujitsu-monaka.c +++ b/clang/test/Driver/print-enabled-extensions/aarch64-fujitsu-monaka.c @@ -63,7 +63,6 @@ // CHECK-NEXT: FEAT_SM4, FEAT_SM3 Enable SM3 and SM4 support // CHECK-NEXT: FEAT_SPECRES Enable Armv8.5-A execution and data prediction invalidation instructions // CHECK-NEXT: FEAT_SPECRES2 Enable Speculation Restriction Instruction -// CHECK-NEXT: FEAT_SPEv1p2 Enable extra register in the Statistical Profiling Extension // CHECK-NEXT: FEAT_SSBS, FEAT_SSBS2 Enable Speculative Store Bypass Safe bit // CHECK-NEXT: FEAT_SVE Enable Scalable Vector Extension (SVE) instructions // CHECK-NEXT: FEAT_SVE2 Enable Scalable Vector Extension 2 (SVE2) instructions @@ -77,4 +76,4 @@ // CHECK-NEXT: FEAT_UAO Enable Armv8.2-A UAO PState // CHECK-NEXT: FEAT_VHE Enable Armv8.1-A Virtual Host extension // CHECK-NEXT: FEAT_WFxT Enable Armv8.7-A WFET and WFIT instruction -// CHECK-NEXT: FEAT_XS Enable Armv8.7-A limited-TLB-maintenance instruction \ No newline at end of file +// CHECK-NEXT: FEAT_XS Enable Armv8.7-A limited-TLB-maintenance instruction diff --git a/clang/test/Driver/ps4-sdk-root.c b/clang/test/Driver/ps4-sdk-root.c index 78eb1ce2ba630..6e5f1e28958ad 100644 --- a/clang/test/Driver/ps4-sdk-root.c +++ b/clang/test/Driver/ps4-sdk-root.c @@ -1,10 +1,10 @@ /// PS4 clang emits warnings when SDK headers (/target/include/) or -/// libraries (/target/lib/) are missing, unless the user takes control -/// of search paths, when corresponding existence checks are skipped. +/// libraries (/target/lib/) are missing. If the the user takes control +/// of header search paths, the existence check for /target/include is +/// skipped. /// /// User control of header search is assumed if `--sysroot`, `-isysroot`, -/// `-nostdinc` or `-nostdlibinc` is supplied. User control of library search -/// is assumed if `--sysroot` is supplied. +/// `-nostdinc` or `-nostdlibinc` is supplied. /// /// Warnings are emitted if a specified `-isysroot` or `--sysroot` does not /// exist. @@ -46,22 +46,23 @@ // RUN: env SCE_ORBIS_SDK_DIR=.. %clang @%t.rsp %s -c -isysroot . 2>&1 | FileCheck -check-prefixes=NO-WARN %s // RUN: env SCE_ORBIS_SDK_DIR=.. %clang @%t.rsp %s -c --sysroot=. 2>&1 | FileCheck -check-prefixes=NO-WARN %s -/// --sysroot disables the existence check for libraries and headers. -// RUN: env SCE_ORBIS_SDK_DIR=.. %clang @%t.rsp %s --sysroot=. 2>&1 | FileCheck -check-prefix=NO-WARN %s +/// --sysroot disables the existence check for headers. The check for libraries +/// remains. +// RUN: env SCE_ORBIS_SDK_DIR=.. %clang @%t.rsp %s --sysroot=. 2>&1 | FileCheck -check-prefixes=WARN-SYS-LIBS,NO-WARN %s /// -isysroot overrides --sysroot for header search, but not library search. -// RUN: env SCE_ORBIS_SDK_DIR=.. %clang @%t.rsp %s -isysroot . --sysroot=.. 2>&1 | FileCheck -check-prefixes=ISYSTEM,NO-WARN %s -// RUN: env SCE_ORBIS_SDK_DIR=.. %clang @%t.rsp %s --sysroot=.. -isysroot . 2>&1 | FileCheck -check-prefixes=ISYSTEM,NO-WARN %s +// RUN: env SCE_ORBIS_SDK_DIR=.. %clang @%t.rsp %s -isysroot . --sysroot=%t.inconly 2>&1 | FileCheck -check-prefixes=ISYSTEM,WARN-SYS-LIBS,NO-WARN %s +// RUN: env SCE_ORBIS_SDK_DIR=.. %clang @%t.rsp %s --sysroot=%t.inconly -isysroot . 2>&1 | FileCheck -check-prefixes=ISYSTEM,WARN-SYS-LIBS,NO-WARN %s /// Warnings are emitted if non-existent --sysroot/-isysroot are supplied. -// RUN: env SCE_ORBIS_SDK_DIR=.. %clang @%t.rsp %s --sysroot=foo -isysroot . 2>&1 | FileCheck -check-prefixes=WARN-SYSROOT,NO-WARN %s -// RUN: env SCE_ORBIS_SDK_DIR=.. %clang @%t.rsp %s -isysroot foo --sysroot=. 2>&1 | FileCheck -check-prefixes=WARN-SYSROOT,NO-WARN %s -// RUN: env SCE_ORBIS_SDK_DIR=.. %clang @%t.rsp %s --sysroot=foo -isysroot bar 2>&1 | FileCheck -check-prefixes=WARN-SYSROOT,WARN-SYSROOT2,NO-WARN %s +// RUN: env SCE_ORBIS_SDK_DIR=.. %clang @%t.rsp %s --sysroot=foo -isysroot %t.both 2>&1 | FileCheck -check-prefixes=WARN-SYSROOT,WARN-SYS-LIBS,NO-WARN %s +// RUN: env SCE_ORBIS_SDK_DIR=.. %clang @%t.rsp %s -isysroot foo --sysroot=%t.both 2>&1 | FileCheck -check-prefixes=WARN-SYSROOT,NO-WARN %s +// RUN: env SCE_ORBIS_SDK_DIR=.. %clang @%t.rsp %s --sysroot=foo -isysroot bar 2>&1 | FileCheck -check-prefixes=WARN-SYSROOT,WARN-SYSROOT2,WARN-SYS-LIBS,NO-WARN %s // NO-WARN-NOT: {{warning:|error:}} -// WARN-SYS-LIBS: warning: unable to find PS4 system libraries directory -// WARN-SYS-HEADERS: warning: unable to find PS4 system headers directory // WARN-SYSROOT: warning: no such sysroot directory: 'foo' // WARN-SYSROOT2: warning: no such sysroot directory: 'bar' +// WARN-SYS-LIBS: warning: unable to find PS4 system libraries directory +// WARN-SYS-HEADERS: warning: unable to find PS4 system headers directory // NO-WARN-NOT: {{warning:|error:}} // ISYSTEM: "-cc1"{{.*}}"-internal-externc-isystem" "./target/include" diff --git a/clang/test/Driver/ps5-linker.c b/clang/test/Driver/ps5-linker.c index 53f89a914f4fa..9dd35c40619b6 100644 --- a/clang/test/Driver/ps5-linker.c +++ b/clang/test/Driver/ps5-linker.c @@ -174,25 +174,26 @@ // Test implicit library search paths are supplied to the linker, after any // search paths specified by the user. /target/lib is implicitly -// added if it exists and no --sysroot is specified. CRT objects are found -// there. "." is always implicitly added to library search paths. This is -// long-standing behavior, unique to PlayStation toolchains. +// added if it exists. CRT objects are found there. "." is always implicitly +// added to library search paths. This is long-standing behavior, unique to +// PlayStation toolchains. // RUN: rm -rf %t.dir && mkdir %t.dir // RUN: env SCE_PROSPERO_SDK_DIR=%t.dir %clang --target=x64_64-sie-ps5 %s -### -Luser 2>&1 | FileCheck --check-prefixes=CHECK-NO-TARGETLIB %s -// RUN: env SCE_PROSPERO_SDK_DIR=%t.dir %clang --target=x64_64-sie-ps5 %s -### -Luser --sysroot=%t.dir 2>&1 | FileCheck --check-prefixes=CHECK-NO-TARGETLIB %s +// RUN: %clang --target=x64_64-sie-ps5 %s -### -Luser --sysroot=%t.dir 2>&1 | FileCheck --check-prefixes=CHECK-NO-TARGETLIB %s // CHECK-NO-TARGETLIB: {{ld(\.exe)?}}" // CHECK-NO-TARGETLIB-SAME: "-Luser" // CHECK-NO-TARGETLIB-NOT: "-L{{.*[/\\]}}target/lib" // CHECK-NO-TARGETLIB-SAME: "-L." -// RUN: mkdir -p %t.dir/target/lib -// RUN: touch %t.dir/target/lib/crti.o -// RUN: env SCE_PROSPERO_SDK_DIR=%t.dir %clang --target=x64_64-sie-ps5 %s -### -Luser 2>&1 | FileCheck --check-prefixes=CHECK-TARGETLIB %s +// RUN: mkdir -p %t.dir/myroot/target/lib +// RUN: touch %t.dir/myroot/target/lib/crti.o +// RUN: env SCE_PROSPERO_SDK_DIR=%t.dir/myroot %clang --target=x64_64-sie-ps5 %s -### -Luser 2>&1 | FileCheck --check-prefixes=CHECK-TARGETLIB %s +// RUN: %clang --target=x64_64-sie-ps5 %s -### -Luser --sysroot=%t.dir/myroot 2>&1 | FileCheck --check-prefixes=CHECK-TARGETLIB %s // CHECK-TARGETLIB: {{ld(\.exe)?}}" // CHECK-TARGETLIB-SAME: "-Luser" -// CHECK-TARGETLIB-SAME: "-L{{.*[/\\]}}target/lib" +// CHECK-TARGETLIB-SAME: "-L{{.*}}myroot{{/|\\\\}}target{{/|\\\\}}lib" // CHECK-TARGETLIB-SAME: "-L." -// CHECK-TARGETLIB-SAME: "{{.*[/\\]}}target{{/|\\\\}}lib{{/|\\\\}}crti.o" +// CHECK-TARGETLIB-SAME: "{{.*}}myroot{{/|\\\\}}target{{/|\\\\}}lib{{/|\\\\}}crti.o" diff --git a/clang/test/Driver/ps5-sdk-root.c b/clang/test/Driver/ps5-sdk-root.c index a12e0dfffeb58..16ef2cc01f5e7 100644 --- a/clang/test/Driver/ps5-sdk-root.c +++ b/clang/test/Driver/ps5-sdk-root.c @@ -1,12 +1,12 @@ /// (Essentially identical to ps4-sdk-root.c except for the target.) /// PS5 clang emits warnings when SDK headers (/target/include/) or -/// libraries (/target/lib/) are missing, unless the user takes control -/// of search paths, when corresponding existence checks are skipped. +/// libraries (/target/lib/) are missing. If the the user takes control +/// of header search paths, the existence check for /target/include is +/// skipped. /// /// User control of header search is assumed if `--sysroot`, `-isysroot`, -/// `-nostdinc` or `-nostdlibinc` is supplied. User control of library search -/// is assumed if `--sysroot` is supplied. +/// `-nostdinc` or `-nostdlibinc` is supplied. /// /// Warnings are emitted if a specified `-isysroot` or `--sysroot` does not /// exist. @@ -48,22 +48,23 @@ // RUN: env SCE_PROSPERO_SDK_DIR=.. %clang @%t.rsp %s -c -isysroot . 2>&1 | FileCheck -check-prefixes=NO-WARN %s // RUN: env SCE_PROSPERO_SDK_DIR=.. %clang @%t.rsp %s -c --sysroot=. 2>&1 | FileCheck -check-prefixes=NO-WARN %s -/// --sysroot disables the existence check for libraries and headers. -// RUN: env SCE_PROSPERO_SDK_DIR=.. %clang @%t.rsp %s --sysroot=. 2>&1 | FileCheck -check-prefix=NO-WARN %s +/// --sysroot disables the existence check for headers. The check for libraries +/// remains. +// RUN: env SCE_PROSPERO_SDK_DIR=.. %clang @%t.rsp %s --sysroot=. 2>&1 | FileCheck -check-prefixes=WARN-SYS-LIBS,NO-WARN %s /// -isysroot overrides --sysroot for header search, but not library search. -// RUN: env SCE_PROSPERO_SDK_DIR=.. %clang @%t.rsp %s -isysroot . --sysroot=.. 2>&1 | FileCheck -check-prefixes=ISYSTEM,NO-WARN %s -// RUN: env SCE_PROSPERO_SDK_DIR=.. %clang @%t.rsp %s --sysroot=.. -isysroot . 2>&1 | FileCheck -check-prefixes=ISYSTEM,NO-WARN %s +// RUN: env SCE_PROSPERO_SDK_DIR=.. %clang @%t.rsp %s -isysroot . --sysroot=%t.inconly 2>&1 | FileCheck -check-prefixes=ISYSTEM,WARN-SYS-LIBS,NO-WARN %s +// RUN: env SCE_PROSPERO_SDK_DIR=.. %clang @%t.rsp %s --sysroot=%t.inconly -isysroot . 2>&1 | FileCheck -check-prefixes=ISYSTEM,WARN-SYS-LIBS,NO-WARN %s /// Warnings are emitted if non-existent --sysroot/-isysroot are supplied. -// RUN: env SCE_PROSPERO_SDK_DIR=.. %clang @%t.rsp %s --sysroot=foo -isysroot . 2>&1 | FileCheck -check-prefixes=WARN-SYSROOT,NO-WARN %s -// RUN: env SCE_PROSPERO_SDK_DIR=.. %clang @%t.rsp %s -isysroot foo --sysroot=. 2>&1 | FileCheck -check-prefixes=WARN-SYSROOT,NO-WARN %s -// RUN: env SCE_PROSPERO_SDK_DIR=.. %clang @%t.rsp %s --sysroot=foo -isysroot bar 2>&1 | FileCheck -check-prefixes=WARN-SYSROOT,WARN-SYSROOT2,NO-WARN %s +// RUN: env SCE_PROSPERO_SDK_DIR=.. %clang @%t.rsp %s --sysroot=foo -isysroot %t.both 2>&1 | FileCheck -check-prefixes=WARN-SYSROOT,WARN-SYS-LIBS,NO-WARN %s +// RUN: env SCE_PROSPERO_SDK_DIR=.. %clang @%t.rsp %s -isysroot foo --sysroot=%t.both 2>&1 | FileCheck -check-prefixes=WARN-SYSROOT,NO-WARN %s +// RUN: env SCE_PROSPERO_SDK_DIR=.. %clang @%t.rsp %s --sysroot=foo -isysroot bar 2>&1 | FileCheck -check-prefixes=WARN-SYSROOT,WARN-SYSROOT2,WARN-SYS-LIBS,NO-WARN %s // NO-WARN-NOT: {{warning:|error:}} -// WARN-SYS-LIBS: warning: unable to find PS5 system libraries directory -// WARN-SYS-HEADERS: warning: unable to find PS5 system headers directory // WARN-SYSROOT: warning: no such sysroot directory: 'foo' // WARN-SYSROOT2: warning: no such sysroot directory: 'bar' +// WARN-SYS-LIBS: warning: unable to find PS5 system libraries directory +// WARN-SYS-HEADERS: warning: unable to find PS5 system headers directory // NO-WARN-NOT: {{warning:|error:}} // ISYSTEM: "-cc1"{{.*}}"-internal-externc-isystem" "./target/include" diff --git a/clang/test/Misc/target-invalid-cpu-note/nvptx.c b/clang/test/Misc/target-invalid-cpu-note/nvptx.c index 3ea6c02d6b384..3afcdf8c9fe5c 100644 --- a/clang/test/Misc/target-invalid-cpu-note/nvptx.c +++ b/clang/test/Misc/target-invalid-cpu-note/nvptx.c @@ -27,6 +27,7 @@ // CHECK-SAME: {{^}}, sm_90 // CHECK-SAME: {{^}}, sm_90a // CHECK-SAME: {{^}}, sm_100 +// CHECK-SAME: {{^}}, sm_100a // CHECK-SAME: {{^}}, gfx600 // CHECK-SAME: {{^}}, gfx601 // CHECK-SAME: {{^}}, gfx602 diff --git a/clang/test/Modules/module-local-hidden-friend.cppm b/clang/test/Modules/module-local-hidden-friend.cppm new file mode 100644 index 0000000000000..6ad0f5be51db1 --- /dev/null +++ b/clang/test/Modules/module-local-hidden-friend.cppm @@ -0,0 +1,88 @@ +// RUN: rm -rf %t +// RUN: split-file %s %t +// RUN: cd %t +// +// RUN: %clang_cc1 -std=c++20 %t/a.cppm -emit-module-interface -o %t/a.pcm +// RUN: %clang_cc1 -std=c++20 %t/b.cppm -emit-module-interface -o %t/b.pcm \ +// RUN: -fmodule-file=a=%t/a.pcm +// RUN: %clang_cc1 -std=c++20 %t/use.cc -fmodule-file=a=%t/a.pcm -fmodule-file=b=%t/b.pcm \ +// RUN: -fsyntax-only -verify +// +// RUN: %clang_cc1 -std=c++20 %t/a.cppm -emit-reduced-module-interface -o %t/a.pcm +// RUN: %clang_cc1 -std=c++20 %t/b.cppm -emit-reduced-module-interface -o %t/b.pcm \ +// RUN: -fmodule-file=a=%t/a.pcm +// RUN: %clang_cc1 -std=c++20 %t/use.cc -fmodule-file=a=%t/a.pcm -fmodule-file=b=%t/b.pcm \ +// RUN: -fsyntax-only -verify + +//--- a.cppm +export module a; + +namespace n { +} + +//--- ordering.mock.h +namespace std { + class strong_ordering { + public: + int n; + static const strong_ordering less, equal, greater; + constexpr bool operator==(int n) const noexcept { return this->n == n;} + constexpr bool operator!=(int n) const noexcept { return this->n != n;} + }; + constexpr strong_ordering strong_ordering::less = {-1}; + constexpr strong_ordering strong_ordering::equal = {0}; + constexpr strong_ordering strong_ordering::greater = {1}; + + class partial_ordering { + public: + long n; + static const partial_ordering less, equal, greater, equivalent, unordered; + constexpr bool operator==(long n) const noexcept { return this->n == n;} + constexpr bool operator!=(long n) const noexcept { return this->n != n;} + }; + constexpr partial_ordering partial_ordering::less = {-1}; + constexpr partial_ordering partial_ordering::equal = {0}; + constexpr partial_ordering partial_ordering::greater = {1}; + constexpr partial_ordering partial_ordering::equivalent = {0}; + constexpr partial_ordering partial_ordering::unordered = {-127}; +} // namespace std + +//--- b.cppm +module; +#include "ordering.mock.h" +export module b; + +import a; + +namespace n { + +struct monostate { + friend constexpr bool operator==(monostate, monostate) = default; +}; + +export struct wrapper { + friend constexpr bool operator==(wrapper const &LHS, wrapper const &RHS) { + return LHS.m_value == RHS.m_value; + } + + monostate m_value; +}; + +struct monostate2 { + auto operator<=>(monostate2 const &) const & = default; +}; + +export struct wrapper2 { + friend bool operator==(wrapper2 const &LHS, wrapper2 const &RHS) = default; + + monostate2 m_value; +}; + +} // namespace n + +//--- use.cc +// expected-no-diagnostics +import b; + +static_assert(n::wrapper() == n::wrapper()); +static_assert(n::wrapper2() == n::wrapper2()); diff --git a/clang/test/Modules/visibility-for-implicit-global-module.cppm b/clang/test/Modules/visibility-for-implicit-global-module.cppm new file mode 100644 index 0000000000000..c55f2c3beee20 --- /dev/null +++ b/clang/test/Modules/visibility-for-implicit-global-module.cppm @@ -0,0 +1,18 @@ +// RUN: rm -rf %t +// RUN: mkdir %t +// RUN: split-file %s %t +// +// RUN: %clang_cc1 -std=c++20 %t/a.interface.cppm -emit-module-interface -o %t/a.pcm +// RUN: %clang_cc1 -std=c++20 %t/a.impl.cc -fmodule-file=a:interface=%t/a.pcm \ +// RUN: -verify -fsyntax-only + +//--- a.interface.cppm +export module a:interface; +extern "C++" constexpr int a = 43; + +//--- a.impl.cc +// expected-no-diagnostics +module a:impl; +import :interface; +static_assert(a == 43); + diff --git a/clang/test/Modules/vtable-in-explicit-instantiation.cppm b/clang/test/Modules/vtable-in-explicit-instantiation.cppm new file mode 100644 index 0000000000000..b090607751744 --- /dev/null +++ b/clang/test/Modules/vtable-in-explicit-instantiation.cppm @@ -0,0 +1,34 @@ +// RUN: rm -rf %t +// RUN: mkdir %t +// RUN: split-file %s %t + +// RUN: %clang_cc1 -std=c++20 %t/a.cppm -triple %itanium_abi_triple -emit-module-interface -o %t/a.pcm +// RUN: %clang_cc1 -std=c++20 %t/a.cc -triple %itanium_abi_triple -fmodule-file=a=%t/a.pcm -emit-llvm -o - | FileCheck %t/a.cc +// +// RUN: %clang_cc1 -std=c++20 %t/a.cppm -triple %itanium_abi_triple -emit-reduced-module-interface -o %t/a.pcm +// RUN: %clang_cc1 -std=c++20 %t/a.cc -triple %itanium_abi_triple -fmodule-file=a=%t/a.pcm -emit-llvm -o - | FileCheck %t/a.cc + +//--- a.cppm +export module a; +class base { +public: + ~base() = default; + virtual void foo(); +}; + +template +class a : public base { +public: + virtual void foo() override; +}; + +extern template class a; + +//--- a.cc +module a; + +template +void a::foo() {} + +template class a; +// CHECK: _ZTVW1a1aIiE diff --git a/clang/test/Sema/Inputs/lifetime-analysis.h b/clang/test/Sema/Inputs/lifetime-analysis.h index f888e6ab94bb6..d318033ff0cc4 100644 --- a/clang/test/Sema/Inputs/lifetime-analysis.h +++ b/clang/test/Sema/Inputs/lifetime-analysis.h @@ -52,7 +52,7 @@ struct vector { void push_back(const T&); void push_back(T&&); - + const T& back() const; void insert(iterator, T&&); }; diff --git a/clang/test/Sema/atomic-ops.c b/clang/test/Sema/atomic-ops.c index 2405f804d0da5..725a12060d4e0 100644 --- a/clang/test/Sema/atomic-ops.c +++ b/clang/test/Sema/atomic-ops.c @@ -284,11 +284,29 @@ void f(_Atomic(int) *i, const _Atomic(int) *ci, const volatile int flag_k = 0; volatile int flag = 0; - (void)(int)__atomic_test_and_set(&flag_k, memory_order_seq_cst); // expected-warning {{passing 'const volatile int *' to parameter of type 'volatile void *'}} + (void)(int)__atomic_test_and_set(&flag_k, memory_order_seq_cst); // expected-error {{address argument to atomic operation must be a pointer to non-const type ('const volatile int *' invalid)}} (void)(int)__atomic_test_and_set(&flag, memory_order_seq_cst); - __atomic_clear(&flag_k, memory_order_seq_cst); // expected-warning {{passing 'const volatile int *' to parameter of type 'volatile void *'}} + __atomic_clear(&flag_k, memory_order_seq_cst); // expected-error {{address argument to atomic operation must be a pointer to non-const type ('const volatile int *' invalid)}} __atomic_clear(&flag, memory_order_seq_cst); (int)__atomic_clear(&flag, memory_order_seq_cst); // expected-error {{operand of type 'void'}} + __atomic_clear(0x8000, memory_order_seq_cst); // expected-error {{address argument to atomic builtin must be a pointer ('int' invalid)}} + __atomic_clear(&flag, memory_order_consume); // expected-warning {{memory order argument to atomic operation is invalid}} + __atomic_clear(&flag, memory_order_acquire); // expected-warning {{memory order argument to atomic operation is invalid}} + __atomic_clear(&flag, memory_order_acq_rel); // expected-warning {{memory order argument to atomic operation is invalid}} + _Bool lock; + __atomic_test_and_set(lock, memory_order_acquire); // expected-error {{address argument to atomic builtin must be a pointer}} + __atomic_clear(lock, memory_order_release); // expected-error {{address argument to atomic builtin must be a pointer}} + + // These intrinsics accept any non-const pointer type (including + // pointer-to-incomplete), and access the first byte. + __atomic_test_and_set((void*)0x8000, memory_order_seq_cst); + __atomic_test_and_set((char*)0x8000, memory_order_seq_cst); + __atomic_test_and_set((int*)0x8000, memory_order_seq_cst); + __atomic_test_and_set((struct incomplete*)0x8000, memory_order_seq_cst); + __atomic_clear((void*)0x8000, memory_order_seq_cst); + __atomic_clear((char*)0x8000, memory_order_seq_cst); + __atomic_clear((int*)0x8000, memory_order_seq_cst); + __atomic_clear((struct incomplete*)0x8000, memory_order_seq_cst); __c11_atomic_init(ci, 0); // expected-error {{address argument to atomic operation must be a pointer to non-const _Atomic type ('const _Atomic(int) *' invalid)}} __c11_atomic_store(ci, 0, memory_order_release); // expected-error {{address argument to atomic operation must be a pointer to non-const _Atomic type ('const _Atomic(int) *' invalid)}} diff --git a/clang/test/Sema/pragma-clang-section.c b/clang/test/Sema/pragma-clang-section.c index 458c91c2cf31c..e33e1dfe8cbef 100644 --- a/clang/test/Sema/pragma-clang-section.c +++ b/clang/test/Sema/pragma-clang-section.c @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s -triple arm-none-eabi +// RUN: %clang_cc1 -fsyntax-only -verify %s -triple arm64-windows-msvc #pragma clang section bss = "mybss.1" data = "mydata.1" rodata = "myrodata.1" text = "mytext.1" // expected-note 2 {{#pragma entered here}} #pragma clang section bss="" data="" rodata="" text="" #pragma clang section diff --git a/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp b/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp index 4c19367bb7f3d..04bb1330ded4c 100644 --- a/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp +++ b/clang/test/Sema/warn-lifetime-analysis-nocfg.cpp @@ -806,3 +806,49 @@ std::string_view test2(int c, std::string_view sv) { } } // namespace GH120206 + +namespace GH120543 { +struct S { + std::string_view sv; + std::string s; +}; +struct Q { + const S* get() const [[clang::lifetimebound]]; +}; + +std::string_view foo(std::string_view sv [[clang::lifetimebound]]); + +void test1() { + std::string_view k1 = S().sv; // OK + std::string_view k2 = S().s; // expected-warning {{object backing the pointer will}} + + std::string_view k3 = Q().get()->sv; // OK + std::string_view k4 = Q().get()->s; // expected-warning {{object backing the pointer will}} + + std::string_view lb1 = foo(S().s); // expected-warning {{object backing the pointer will}} + std::string_view lb2 = foo(Q().get()->s); // expected-warning {{object backing the pointer will}} +} + +struct Bar {}; +struct Foo { + std::vector v; +}; +Foo getFoo(); +void test2() { + const Foo& foo = getFoo(); + const Bar& bar = foo.v.back(); // OK +} + +struct Foo2 { + std::unique_ptr bar; +}; + +struct Test { + Test(Foo2 foo) : bar(foo.bar.get()), // OK + storage(std::move(foo.bar)) {}; + + Bar* bar; + std::unique_ptr storage; +}; + +} // namespace GH120543 diff --git a/clang/test/SemaCXX/constant-expression-cxx11.cpp b/clang/test/SemaCXX/constant-expression-cxx11.cpp index c990dc78deb9b..a1234b67acd6d 100644 --- a/clang/test/SemaCXX/constant-expression-cxx11.cpp +++ b/clang/test/SemaCXX/constant-expression-cxx11.cpp @@ -1471,9 +1471,9 @@ namespace ConvertedConstantExpr { // useless note and instead just point to the non-constant subexpression. enum class E { em = m, - en = n, // expected-error {{not a constant expression}} expected-note {{initializer of 'n' is unknown}} + en = n, // cxx23-note {{initializer of 'n' is not a constant expression}} expected-error {{enumerator value is not a constant expression}} cxx11_20-note {{initializer of 'n' is unknown}} eo = (m + // expected-error {{not a constant expression}} - n // expected-note {{initializer of 'n' is unknown}} + n // cxx23-note {{initializer of 'n' is not a constant expression}} cxx11_20-note {{initializer of 'n' is unknown}} ), eq = reinterpret_cast((int*)0) // expected-error {{not a constant expression}} expected-note {{reinterpret_cast}} }; @@ -2007,7 +2007,8 @@ namespace ConstexprConstructorRecovery { namespace Lifetime { void f() { - constexpr int &n = n; // expected-error {{constant expression}} expected-note {{use of reference outside its lifetime}} expected-warning {{not yet bound to a value}} + constexpr int &n = n; // expected-error {{constant expression}} cxx23-note {{reference to 'n' is not a constant expression}} cxx23-note {{address of non-static constexpr variable 'n' may differ}} expected-warning {{not yet bound to a value}} + // cxx11_20-note@-1 {{use of reference outside its lifetime is not allowed in a constant expression}} constexpr int m = m; // expected-error {{constant expression}} expected-note {{read of object outside its lifetime}} } @@ -2427,15 +2428,15 @@ namespace array_size { template void f1(T t) { constexpr int k = t.size(); } - template void f2(const T &t) { // expected-note 2{{declared here}} - constexpr int k = t.size(); // expected-error 2{{constant}} expected-note 2{{function parameter 't' with unknown value cannot be used in a constant expression}} + template void f2(const T &t) { // cxx11_20-note 2{{declared here}} + constexpr int k = t.size(); // cxx11_20-error 2{{constexpr variable 'k' must be initialized by a constant expression}} cxx11_20-note 2{{function parameter 't' with unknown value cannot be used in a constant expression}} } template void f3(const T &t) { constexpr int k = T::size(); } void g(array<3> a) { f1(a); - f2(a); // expected-note {{instantiation of}} + f2(a); // cxx11_20-note {{in instantiation of function template}} f3(a); } @@ -2444,8 +2445,9 @@ namespace array_size { }; void h(array_nonstatic<3> a) { f1(a); - f2(a); // expected-note {{instantiation of}} + f2(a); // cxx11_20-note {{instantiation of}} } + //static_assert(f2(array_size::array<3>{})); } namespace flexible_array { diff --git a/clang/test/SemaCXX/constant-expression-cxx2a.cpp b/clang/test/SemaCXX/constant-expression-cxx2a.cpp index 36d4d25c48471..85720606fe9de 100644 --- a/clang/test/SemaCXX/constant-expression-cxx2a.cpp +++ b/clang/test/SemaCXX/constant-expression-cxx2a.cpp @@ -308,8 +308,7 @@ namespace TypeId { static_assert(&B2().ti1 == &typeid(B)); static_assert(&B2().ti2 == &typeid(B2)); extern B2 extern_b2; - // expected-note@+1 {{typeid applied to object 'extern_b2' whose dynamic type is not constant}} - static_assert(&typeid(extern_b2) == &typeid(B2)); // expected-error {{constant expression}} + static_assert(&typeid(extern_b2) == &typeid(B2)); constexpr B2 b2; constexpr const B &b1 = b2; diff --git a/clang/test/SemaCXX/constant-expression-p2280r4.cpp b/clang/test/SemaCXX/constant-expression-p2280r4.cpp new file mode 100644 index 0000000000000..0f85c60629eed --- /dev/null +++ b/clang/test/SemaCXX/constant-expression-p2280r4.cpp @@ -0,0 +1,156 @@ +// RUN: %clang_cc1 -std=c++23 -verify %s + +using size_t = decltype(sizeof(0)); + +namespace std { +struct type_info { + const char* name() const noexcept(true); +}; +} + +template +constexpr size_t array_size(T (&)[N]) { + return N; +} + +void use_array(int const (&gold_medal_mel)[2]) { + constexpr auto gold = array_size(gold_medal_mel); // ok +} + +constexpr auto olympic_mile() { + const int ledecky = 1500; + return []{ return ledecky; }; +} +static_assert(olympic_mile()() == 1500); // ok + +struct Swim { + constexpr int phelps() { return 28; } + virtual constexpr int lochte() { return 12; } + int coughlin = 12; +}; + +constexpr int how_many(Swim& swam) { + Swim* p = &swam; + return (p + 1 - 1)->phelps(); +} + +void splash(Swim& swam) { + static_assert(swam.phelps() == 28); // ok + static_assert((&swam)->phelps() == 28); // ok + Swim* pswam = &swam; // expected-note {{declared here}} + static_assert(pswam->phelps() == 28); // expected-error {{static assertion expression is not an integral constant expression}} + // expected-note@-1 {{read of non-constexpr variable 'pswam' is not allowed in a constant expression}} + static_assert(how_many(swam) == 28); // ok + static_assert(Swim().lochte() == 12); // ok + static_assert(swam.lochte() == 12); // expected-error {{static assertion expression is not an integral constant expression}} + static_assert(swam.coughlin == 12); // expected-error {{static assertion expression is not an integral constant expression}} +} + +extern Swim dc; +extern Swim& trident; // expected-note {{declared here}} + +constexpr auto& sandeno = typeid(dc); // ok: can only be typeid(Swim) +constexpr auto& gallagher = typeid(trident); // expected-error {{constexpr variable 'gallagher' must be initialized by a constant expression}} + // expected-note@-1 {{initializer of 'trident' is not a constant expression}} + +namespace explicitThis { +struct C { + constexpr int b() { return 0; }; + + constexpr int f(this C &c) { + return c.b(); // ok + } + + constexpr int g() { + return f(); // ok + } +}; + +void g() { + C c; + constexpr int x = c.f(); + constexpr int y = c.g(); +} +} + +namespace GH64376 { +template +struct Test { + static constexpr int value = V; +}; + +int main() { + Test<124> test; + auto& test2 = test; + + if constexpr(test2.value > 3) { + return 1; + } + + return 0; +} +} + +namespace GH30060 { +template +struct A { + static constexpr int value = V; +}; + +template +static void test1(T &f) { + A bar; +} + +void g() { + A<42> f; + + test1(f); +} +} + +namespace GH26067 { +struct A { + constexpr operator int() const { return 42; } +}; + +template +void f() {} + +void test(const A& value) { + f(); +} + +int main() { + A a{}; + test(a); +} +} + +namespace GH34365 { +void g() { + auto f = []() { return 42; }; + constexpr int x = f(); + [](auto f) { constexpr int x = f(); }(f); + [](auto &f) { constexpr int x = f(); }(f); + (void)[&]() { constexpr int x = f(); }; +} +} + +namespace GH118063 { +template +struct array { + constexpr auto size() const -> unsigned int { + return N; + } +}; + +constexpr auto f(array<5> const& arr) { + return array{}.size(); +} + +int g() { + array<5> arr {}; + static_assert(f(arr) == 5); +} +} diff --git a/clang/test/SemaCXX/warn-base-type-qualifiers.cpp b/clang/test/SemaCXX/warn-base-type-qualifiers.cpp new file mode 100644 index 0000000000000..b9fd577c574b9 --- /dev/null +++ b/clang/test/SemaCXX/warn-base-type-qualifiers.cpp @@ -0,0 +1,35 @@ +// RUN: %clang_cc1 %s -std=c++11 -Wignored-qualifiers -verify + +template struct add_const { + using type = const T; +}; +template using add_const_t = typename add_const::type; + +class A { }; + +typedef const A A_Const; +class B : public A_Const { }; // expected-warning {{'const' qualifier on base class type 'A_Const' (aka 'const A') have no effect}} \ + // expected-note {{base class 'A_Const' (aka 'const A') specified here}} + +typedef const volatile A A_Const_Volatile; +class C : public A_Const_Volatile { }; // expected-warning {{'const volatile' qualifiers on base class type 'A_Const_Volatile' (aka 'const volatile A') have no effect}} \ + // expected-note {{base class 'A_Const_Volatile' (aka 'const volatile A') specified here}} + +struct D { + D(int); +}; + +template struct E : T { // expected-warning {{'const' qualifier on base class type 'const D' have no effect}} \ + // expected-note {{base class 'const D' specified here}} + using T::T; + E(int &) : E(0) {} +}; +E e(1); // expected-note {{in instantiation of template class 'E' requested here}} + +template +struct G : add_const::type { // expected-warning {{'const' qualifier on base class type 'add_const::type' (aka 'const D') have no effect}} \ + // expected-note {{base class 'add_const::type' (aka 'const D') specified here}} + using T::T; + G(int &) : G(0) {} +}; +G g(1); // expected-note {{in instantiation of template class 'G' requested here}} diff --git a/clang/test/SemaOpenCL/invalid-block.cl b/clang/test/SemaOpenCL/invalid-block.cl index 6c918d302f801..1605369000429 100644 --- a/clang/test/SemaOpenCL/invalid-block.cl +++ b/clang/test/SemaOpenCL/invalid-block.cl @@ -65,6 +65,8 @@ void f5(int i) { bl2_t arr[] = {bl1, bl2}; // expected-error {{array of 'bl2_t' (aka 'int (__generic ^const)(__private int)') type is invalid in OpenCL}} int tmp = i ? bl1(i) // expected-error {{block type cannot be used as expression in ternary expression in OpenCL}} : bl2(i); // expected-error {{block type cannot be used as expression in ternary expression in OpenCL}} + bl2_t bref = i ? bl1 // expected-error {{block type cannot be used as expression in ternary expression in OpenCL}} + : bl2; // expected-error {{block type cannot be used as expression in ternary expression in OpenCL}} } // A block pointer type and all pointer operations are disallowed void f6(bl2_t *bl_ptr) { // expected-error{{pointer to type 'bl2_t' (aka 'int (__generic ^const)(__private int)') is invalid in OpenCL}} diff --git a/clang/test/SemaTemplate/concepts-out-of-line-def.cpp b/clang/test/SemaTemplate/concepts-out-of-line-def.cpp index 7cb5cfc10b9a7..6c1a229a9fdda 100644 --- a/clang/test/SemaTemplate/concepts-out-of-line-def.cpp +++ b/clang/test/SemaTemplate/concepts-out-of-line-def.cpp @@ -737,3 +737,17 @@ ptr make_item(auto &&args) ptr p; } // namespace GH114685 + +namespace GH123472 { + +consteval bool fn() { return true; } + +struct S { + template + static consteval void mfn() requires (bool(&fn)); +}; + +template +consteval void S::mfn() requires (bool(&fn)) {} + +} diff --git a/clang/tools/diagtool/DiagnosticNames.cpp b/clang/tools/diagtool/DiagnosticNames.cpp index c3a3002889c73..4ac9825848ef3 100644 --- a/clang/tools/diagtool/DiagnosticNames.cpp +++ b/clang/tools/diagtool/DiagnosticNames.cpp @@ -9,6 +9,7 @@ #include "DiagnosticNames.h" #include "clang/Basic/AllDiagnostics.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringTable.h" using namespace clang; using namespace diagtool; @@ -68,7 +69,7 @@ static const GroupRecord OptionTable[] = { }; llvm::StringRef GroupRecord::getName() const { - return StringRef(DiagGroupNames + NameOffset + 1, DiagGroupNames[NameOffset]); + return DiagGroupNames[NameOffset]; } GroupRecord::subgroup_iterator GroupRecord::subgroup_begin() const { diff --git a/clang/unittests/Analysis/CFGBuildResult.h b/clang/unittests/Analysis/CFGBuildResult.h index 72ad1cc7ce401..0d5539005840d 100644 --- a/clang/unittests/Analysis/CFGBuildResult.h +++ b/clang/unittests/Analysis/CFGBuildResult.h @@ -65,8 +65,8 @@ class CFGCallback : public ast_matchers::MatchFinder::MatchCallback { template BuildResult BuildCFG(const char *Code, CFG::BuildOptions Options = {}, FuncMatcherT FuncMatcher = ast_matchers::anything()) { - std::vector Args = {"-std=c++11", - "-fno-delayed-template-parsing"}; + const std::vector Args = { + "-std=c++11", "-fno-delayed-template-parsing", "-Wno-everything"}; std::unique_ptr AST = tooling::buildASTFromCodeWithArgs(Code, Args); if (!AST) return BuildResult::ToolFailed; diff --git a/clang/unittests/Analysis/CFGTest.cpp b/clang/unittests/Analysis/CFGTest.cpp index 2b27da0081425..46a6751391cf5 100644 --- a/clang/unittests/Analysis/CFGTest.cpp +++ b/clang/unittests/Analysis/CFGTest.cpp @@ -195,7 +195,6 @@ TEST(CFG, ElementRefIterator) { // Reverse, non-const version Index = MainBlockSize; for (CFGBlock::CFGElementRef ElementRef : MainBlock->rrefs()) { - llvm::errs() << Index << '\n'; EXPECT_EQ(ElementRef.getParent(), MainBlock); EXPECT_EQ(ElementRef.getIndexInBlock(), Index); EXPECT_TRUE(ElementRef->getAs()); diff --git a/clang/unittests/Analysis/ExprMutationAnalyzerTest.cpp b/clang/unittests/Analysis/ExprMutationAnalyzerTest.cpp index 137baab53301a..cc277d56b37a2 100644 --- a/clang/unittests/Analysis/ExprMutationAnalyzerTest.cpp +++ b/clang/unittests/Analysis/ExprMutationAnalyzerTest.cpp @@ -14,6 +14,7 @@ #include "clang/Tooling/Tooling.h" #include "gmock/gmock.h" #include "gtest/gtest.h" +#include #include namespace clang { @@ -1609,4 +1610,398 @@ TEST(ExprMutationAnalyzerTest, ReproduceFailureMinimal) { match(withEnclosingCompound(declRefTo("x")), AST11->getASTContext()); EXPECT_FALSE(isMutated(Results11, AST11.get())); } + +static bool isPointeeMutated(const SmallVectorImpl &Results, + ASTUnit *AST) { + const auto *const S = selectFirst("stmt", Results); + const auto *const E = selectFirst("expr", Results); + assert(S && E); + TraversalKindScope RAII(AST->getASTContext(), TK_AsIs); + return ExprMutationAnalyzer(*S, AST->getASTContext()).isPointeeMutated(E); +} + +static bool isDeclPointeeMutated(const SmallVectorImpl &Results, + ASTUnit *AST) { + const auto *const S = selectFirst("stmt", Results); + const auto *const D = selectFirst("decl", Results); + assert(S && D); + TraversalKindScope RAII(AST->getASTContext(), TK_AsIs); + return ExprMutationAnalyzer(*S, AST->getASTContext()).isPointeeMutated(D); +} + +TEST(ExprMutationAnalyzerTest, PointeeMutatedByAssign) { + { + const std::string Code = "void f() { int* x = nullptr; int b = *x; }"; + auto AST = buildASTFromCodeWithArgs(Code, {}); + auto Results = + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + EXPECT_FALSE(isPointeeMutated(Results, AST.get())); + } + { + const std::string Code = "void f() { int* x = nullptr; *x = 100; }"; + auto AST = buildASTFromCodeWithArgs(Code, {}); + auto Results = + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + EXPECT_TRUE(isPointeeMutated(Results, AST.get())); + } + { + const std::string Code = "void f() { int* x = nullptr; (*x)++; }"; + auto AST = buildASTFromCodeWithArgs(Code, {"-Wno-unused-value"}); + auto Results = + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + EXPECT_TRUE(isPointeeMutated(Results, AST.get())); + } +} + +TEST(ExprMutationAnalyzerTest, PointeeMutatedByMember) { + { + const std::string Code = + "struct A { int v; }; void f() { A* x = nullptr; int b = x->v; }"; + auto AST = buildASTFromCodeWithArgs(Code, {}); + auto Results = + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + EXPECT_FALSE(isPointeeMutated(Results, AST.get())); + } + { + const std::string Code = + "struct A { int v; }; void f() { A* x = nullptr; x->v = 1; }"; + auto AST = buildASTFromCodeWithArgs(Code, {}); + auto Results = + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + EXPECT_TRUE(isPointeeMutated(Results, AST.get())); + } + { + const std::string Code = + "struct A { int v; }; void f() { A* x = nullptr; x->v++; }"; + auto AST = buildASTFromCodeWithArgs(Code, {"-Wno-unused-value"}); + auto Results = + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + EXPECT_TRUE(isPointeeMutated(Results, AST.get())); + } +} +TEST(ExprMutationAnalyzerTest, PointeeMutatedByMethod) { + { + const std::string Code = "struct A { int v; void foo(); };" + "void f() { A* x = nullptr; x->foo(); }"; + auto AST = buildASTFromCodeWithArgs(Code, {}); + auto Results = + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + EXPECT_TRUE(isPointeeMutated(Results, AST.get())); + } + { + const std::string Code = "struct A { int v; void foo() const; };" + "void f() { A* x = nullptr; x->foo(); }"; + auto AST = buildASTFromCodeWithArgs(Code, {}); + auto Results = + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + EXPECT_FALSE(isPointeeMutated(Results, AST.get())); + } +} +TEST(ExprMutationAnalyzerTest, PointeeMutatedByOperatorOverload) { + { + const std::string Code = "struct A { int v; int operator++(); };" + "void f() { A* x = nullptr; x->operator++(); }"; + auto AST = buildASTFromCodeWithArgs(Code, {}); + auto Results = + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + EXPECT_TRUE(isPointeeMutated(Results, AST.get())); + } + { + const std::string Code = "struct A { int v; int operator++() const; };" + "void f() { A* x = nullptr; x->operator++(); }"; + auto AST = buildASTFromCodeWithArgs(Code, {}); + auto Results = + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + EXPECT_FALSE(isPointeeMutated(Results, AST.get())); + } +} + +TEST(ExprMutationAnalyzerTest, PointeeMutatedByInitToNonConst) { + { + const std::string Code = "void f() { int* x = nullptr; int const* b = x; }"; + auto AST = buildASTFromCodeWithArgs(Code, {}); + auto Results = + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + EXPECT_FALSE(isPointeeMutated(Results, AST.get())); + } + { + const std::string Code = "void f() { int* x = nullptr; int* b = x; }"; + auto AST = buildASTFromCodeWithArgs(Code, {}); + auto Results = + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + EXPECT_TRUE(isPointeeMutated(Results, AST.get())); + } + { + const std::string Code = "void f() { int* x = nullptr; int* const b = x; }"; + auto AST = buildASTFromCodeWithArgs(Code, {}); + auto Results = + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + EXPECT_TRUE(isPointeeMutated(Results, AST.get())); + } +} + +TEST(ExprMutationAnalyzerTest, PointeeMutatedByAssignToNonConst) { + { + const std::string Code = + "void f() { int* x = nullptr; int const* b; b = x; }"; + auto AST = buildASTFromCodeWithArgs(Code, {}); + auto Results = + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + EXPECT_FALSE(isPointeeMutated(Results, AST.get())); + } + { + const std::string Code = "void f() { int* x = nullptr; int* b; b = x; }"; + auto AST = buildASTFromCodeWithArgs(Code, {}); + auto Results = + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + EXPECT_TRUE(isPointeeMutated(Results, AST.get())); + } +} + +TEST(ExprMutationAnalyzerTest, PointeeMutatedByPassAsArgument) { + { + const std::string Code = + "void b(int const*); void f() { int* x = nullptr; b(x); }"; + auto AST = buildASTFromCodeWithArgs(Code, {}); + auto Results = + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + EXPECT_FALSE(isPointeeMutated(Results, AST.get())); + } + { + const std::string Code = + "void b(int *); void f() { int* x = nullptr; b(x); }"; + auto AST = buildASTFromCodeWithArgs(Code, {}); + auto Results = + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + EXPECT_TRUE(isPointeeMutated(Results, AST.get())); + } +} + +TEST(ExprMutationAnalyzerTest, PointeeMutatedByPassAsArgumentInConstruct) { + { + const std::string Code = "struct A { A(int const*); };" + "void f() { int *x; A a{x}; }"; + auto AST = buildASTFromCodeWithArgs(Code, {}); + auto Results = + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + EXPECT_FALSE(isPointeeMutated(Results, AST.get())); + } + { + const std::string Code = "struct A { A(int const*); };" + "void f() { int *x; A a(x); }"; + auto AST = buildASTFromCodeWithArgs(Code, {}); + auto Results = + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + EXPECT_FALSE(isPointeeMutated(Results, AST.get())); + } + { + const std::string Code = "struct A { A(int const*); };" + "void f() { int *x; A a = x; }"; + auto AST = buildASTFromCodeWithArgs(Code, {}); + auto Results = + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + EXPECT_FALSE(isPointeeMutated(Results, AST.get())); + } + { + const std::string Code = "struct A { A(int *); };" + "void f() { int *x; A a{x}; }"; + auto AST = buildASTFromCodeWithArgs(Code, {}); + auto Results = + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + EXPECT_TRUE(isPointeeMutated(Results, AST.get())); + } +} + +TEST(ExprMutationAnalyzerTest, + PointeeMutatedByPassAsArgumentInTemplateConstruct) { + const std::string Code = "template void f() { int *x; new T(x); }"; + auto AST = buildASTFromCodeWithArgs(Code, {"-fno-delayed-template-parsing"}); + auto Results = + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + EXPECT_TRUE(isPointeeMutated(Results, AST.get())); +} + +TEST(ExprMutationAnalyzerTest, PointeeMutatedByPassAsArgumentInInitList) { + { + const std::string Code = + "namespace std {" + "template" + "struct initializer_list{ T const* begin; T const* end; };" + "}" + "void f() { int *x; std::initializer_list a{x, x, x}; }"; + auto AST = + buildASTFromCodeWithArgs(Code, {"-fno-delayed-template-parsing"}); + auto Results = + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + EXPECT_TRUE(isPointeeMutated(Results, AST.get())); + } +} + +TEST(ExprMutationAnalyzerTest, PointeeMutatedByThis) { + { + const std::string Code = + "struct A { void m() const; }; void f() { A* x = nullptr; x->m(); }"; + auto AST = buildASTFromCodeWithArgs(Code, {}); + auto Results = + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + EXPECT_FALSE(isPointeeMutated(Results, AST.get())); + } + { + const std::string Code = + "struct A { void m(); }; void f() { A* x = nullptr; x->m(); }"; + auto AST = buildASTFromCodeWithArgs(Code, {}); + auto Results = + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + EXPECT_TRUE(isPointeeMutated(Results, AST.get())); + } +} + +TEST(ExprMutationAnalyzerTest, PointeeMutatedByExplicitCastToNonConst) { + { + const std::string Code = + "void f() { int* x = nullptr; static_cast(x); }"; + auto AST = buildASTFromCodeWithArgs(Code, {"-Wno-everything"}); + auto Results = + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + EXPECT_FALSE(isPointeeMutated(Results, AST.get())); + } + { + const std::string Code = + "void f() { int* x = nullptr; static_cast(x); }"; + auto AST = buildASTFromCodeWithArgs(Code, {"-Wno-everything"}); + auto Results = + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + EXPECT_TRUE(isPointeeMutated(Results, AST.get())); + } +} + +TEST(ExprMutationAnalyzerTest, PointeeMutatedByConstCastToNonConst) { + // const_cast to non-const even treat as mutated. + { + const std::string Code = + "void f() { int* x = nullptr; const_cast(x); }"; + auto AST = buildASTFromCodeWithArgs(Code, {"-Wno-everything"}); + auto Results = + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + EXPECT_FALSE(isPointeeMutated(Results, AST.get())); + } + { + const std::string Code = + "void f() { int* x = nullptr; const_cast(x); }"; + auto AST = buildASTFromCodeWithArgs(Code, {"-Wno-everything"}); + auto Results = + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + EXPECT_TRUE(isPointeeMutated(Results, AST.get())); + } +} + +TEST(ExprMutationAnalyzerTest, PointeeMutatedByUnresolvedCall) { + const std::string Code = + "template struct S;" + "template void f() { S s; int* x = nullptr; s.m(x); }"; + auto AST = buildASTFromCodeWithArgs( + Code, {"-fno-delayed-template-parsing", "-Wno-everything"}); + auto Results = + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + EXPECT_TRUE(isPointeeMutated(Results, AST.get())); +} + +TEST(ExprMutationAnalyzerTest, PointeeMutatedByAssignToUnknownType) { + { + const std::string Code = "template void f() {" + " int* x = nullptr;" + " T t = x;" + "}"; + auto AST = buildASTFromCodeWithArgs( + Code, {"-fno-delayed-template-parsing", "-Wno-everything"}); + auto Results = + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + EXPECT_TRUE(isPointeeMutated(Results, AST.get())); + } + { + const std::string Code = "template void f() {" + " int* x = nullptr;" + " typename T::t t = x;" + "}"; + auto AST = buildASTFromCodeWithArgs( + Code, {"-fno-delayed-template-parsing", "-Wno-everything"}); + auto Results = + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + EXPECT_TRUE(isPointeeMutated(Results, AST.get())); + } +} + +TEST(ExprMutationAnalyzerTest, PointeeMutatedByLambdaCapture) { + const std::string Code = R"( + void f() { + int* x; + [x] () { *x = 1; }; + })"; + auto AST = buildASTFromCodeWithArgs(Code, {"-Wno-everything"}); + auto Results = + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + EXPECT_TRUE(isDeclPointeeMutated(Results, AST.get())); +} + +TEST(ExprMutationAnalyzerTest, PointeeMutatedByLambdaCaptureInit) { + const std::string Code = R"( + void f() { + int* x; + [t = x] () { *t = 1; }; + })"; + auto AST = buildASTFromCodeWithArgs(Code, {"-Wno-everything"}); + auto Results = + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + EXPECT_TRUE(isDeclPointeeMutated(Results, AST.get())); +} + +TEST(ExprMutationAnalyzerTest, PointeeMutatedByPointerArithmeticAdd) { + { + const std::string Code = R"( + void f() { + int* x; + int* y = x + 1; + })"; + auto AST = buildASTFromCodeWithArgs(Code, {"-Wno-everything"}); + auto Results = + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + EXPECT_TRUE(isPointeeMutated(Results, AST.get())); + } + { + const std::string Code = R"( + void f() { + int* x; + x + 1; + })"; + auto AST = buildASTFromCodeWithArgs(Code, {"-Wno-everything"}); + auto Results = + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + EXPECT_FALSE(isPointeeMutated(Results, AST.get())); + } +} + +TEST(ExprMutationAnalyzerTest, PointeeMutatedByPointerArithmeticSubElement) { + const std::string Code = R"( + void f() { + int* x; + int* y = &x[1]; + })"; + auto AST = buildASTFromCodeWithArgs(Code, {"-Wno-everything"}); + auto Results = + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + EXPECT_TRUE(isPointeeMutated(Results, AST.get())); +} + +TEST(ExprMutationAnalyzerTest, PointeeMutatedByConditionOperator) { + const std::string Code = R"( + void f() { + int* x; + int* y = 1 ? nullptr : x; + })"; + auto AST = buildASTFromCodeWithArgs(Code, {"-Wno-everything"}); + auto Results = + match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + EXPECT_TRUE(isPointeeMutated(Results, AST.get())); +} + } // namespace clang diff --git a/clang/unittests/Format/ConfigParseTest.cpp b/clang/unittests/Format/ConfigParseTest.cpp index 1f0beafaad7f7..9746aa3547846 100644 --- a/clang/unittests/Format/ConfigParseTest.cpp +++ b/clang/unittests/Format/ConfigParseTest.cpp @@ -176,6 +176,7 @@ TEST(ConfigParseTest, ParsesConfigurationBools) { CHECK_PARSE_BOOL(IndentAccessModifiers); CHECK_PARSE_BOOL(IndentCaseBlocks); CHECK_PARSE_BOOL(IndentCaseLabels); + CHECK_PARSE_BOOL(IndentExportBlock); CHECK_PARSE_BOOL(IndentGotoLabels); CHECK_PARSE_BOOL(IndentRequiresClause); CHECK_PARSE_BOOL_FIELD(IndentRequiresClause, "IndentRequires"); diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp index 9623187073a0b..61aa140dfdc9c 100644 --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -9059,9 +9059,9 @@ TEST_F(FormatTest, AdaptiveOnePerLineFormatting) { Style); } -TEST_F(FormatTest, ExportBlockIndentation) { +TEST_F(FormatTest, IndentExportBlock) { FormatStyle Style = getLLVMStyleWithColumns(80); - Style.ExportBlockIndentation = true; + Style.IndentExportBlock = true; verifyFormat("export {\n" " int x;\n" " int y;\n" @@ -9072,7 +9072,7 @@ TEST_F(FormatTest, ExportBlockIndentation) { "}", Style); - Style.ExportBlockIndentation = false; + Style.IndentExportBlock = false; verifyFormat("export {\n" "int x;\n" "int y;\n" @@ -9086,7 +9086,7 @@ TEST_F(FormatTest, ExportBlockIndentation) { TEST_F(FormatTest, ShortExportBlocks) { FormatStyle Style = getLLVMStyleWithColumns(80); - Style.ExportBlockIndentation = false; + Style.IndentExportBlock = false; Style.AllowShortBlocksOnASingleLine = FormatStyle::SBS_Never; verifyFormat("export {\n" diff --git a/clang/unittests/Format/QualifierFixerTest.cpp b/clang/unittests/Format/QualifierFixerTest.cpp index 9ed567445eb07..129828b0d187a 100644 --- a/clang/unittests/Format/QualifierFixerTest.cpp +++ b/clang/unittests/Format/QualifierFixerTest.cpp @@ -1279,6 +1279,18 @@ TEST_F(QualifierFixerTest, WithConstraints) { Style); } +TEST_F(QualifierFixerTest, WithCpp11Attribute) { + FormatStyle Style = getLLVMStyle(); + Style.QualifierAlignment = FormatStyle::QAS_Custom; + Style.QualifierOrder = {"static", "constexpr", "inline", "type"}; + + verifyFormat("[[nodiscard]] static constexpr inline int func() noexcept {}", + "[[nodiscard]] inline constexpr static int func() noexcept {}", + Style); + verifyFormat("[[maybe_unused]] static constexpr int A", + "[[maybe_unused]] constexpr static int A", Style); +} + TEST_F(QualifierFixerTest, DisableRegions) { FormatStyle Style = getLLVMStyle(); Style.QualifierAlignment = FormatStyle::QAS_Custom; diff --git a/clang/unittests/Lex/LexerTest.cpp b/clang/unittests/Lex/LexerTest.cpp index c897998cabe66..29c61fee6f531 100644 --- a/clang/unittests/Lex/LexerTest.cpp +++ b/clang/unittests/Lex/LexerTest.cpp @@ -640,6 +640,41 @@ TEST_F(LexerTest, FindNextTokenIncludingComments) { "=", "abcd", ";")); } +TEST_F(LexerTest, FindPreviousToken) { + Lex("int abcd = 0;\n" + "// A comment.\n" + "int xyz = abcd;\n"); + std::vector GeneratedByPrevToken; + SourceLocation Loc = SourceMgr.getLocForEndOfFile(SourceMgr.getMainFileID()); + while (true) { + auto T = Lexer::findPreviousToken(Loc, SourceMgr, LangOpts, false); + if (!T.has_value()) + break; + GeneratedByPrevToken.push_back(getSourceText(*T, *T)); + Loc = Lexer::GetBeginningOfToken(T->getLocation(), SourceMgr, LangOpts); + } + EXPECT_THAT(GeneratedByPrevToken, ElementsAre(";", "abcd", "=", "xyz", "int", + ";", "0", "=", "abcd", "int")); +} + +TEST_F(LexerTest, FindPreviousTokenIncludingComments) { + Lex("int abcd = 0;\n" + "// A comment.\n" + "int xyz = abcd;\n"); + std::vector GeneratedByPrevToken; + SourceLocation Loc = SourceMgr.getLocForEndOfFile(SourceMgr.getMainFileID()); + while (true) { + auto T = Lexer::findPreviousToken(Loc, SourceMgr, LangOpts, true); + if (!T.has_value()) + break; + GeneratedByPrevToken.push_back(getSourceText(*T, *T)); + Loc = Lexer::GetBeginningOfToken(T->getLocation(), SourceMgr, LangOpts); + } + EXPECT_THAT(GeneratedByPrevToken, + ElementsAre(";", "abcd", "=", "xyz", "int", "// A comment.", ";", + "0", "=", "abcd", "int")); +} + TEST_F(LexerTest, CreatedFIDCountForPredefinedBuffer) { TrivialModuleLoader ModLoader; auto PP = CreatePP("", ModLoader); diff --git a/clang/utils/TableGen/ClangDiagnosticsEmitter.cpp b/clang/utils/TableGen/ClangDiagnosticsEmitter.cpp index fb00c640d6b14..5f03efdb80434 100644 --- a/clang/utils/TableGen/ClangDiagnosticsEmitter.cpp +++ b/clang/utils/TableGen/ClangDiagnosticsEmitter.cpp @@ -1782,19 +1782,12 @@ static void emitDiagArrays(DiagsInGroupTy &DiagsInGroup, /// Emit a list of group names. /// -/// This creates a long string which by itself contains a list of pascal style -/// strings, which consist of a length byte directly followed by the string. -/// -/// \code -/// static const char DiagGroupNames[] = { -/// \000\020#pragma-messages\t#warnings\020CFString-literal" -/// }; -/// \endcode +/// This creates an `llvm::StringTable` of all the diagnostic group names. static void emitDiagGroupNames(const StringToOffsetTable &GroupNames, raw_ostream &OS) { - OS << "static const char DiagGroupNames[] = {\n"; - GroupNames.EmitString(OS); - OS << "};\n\n"; + GroupNames.EmitStringLiteralDef( + OS, "static constexpr llvm::StringTable DiagGroupNames"); + OS << "\n"; } /// Emit diagnostic arrays and related data structures. @@ -1806,7 +1799,7 @@ static void emitDiagGroupNames(const StringToOffsetTable &GroupNames, /// #ifdef GET_DIAG_ARRAYS /// static const int16_t DiagArrays[]; /// static const int16_t DiagSubGroups[]; -/// static const char DiagGroupNames[]; +/// static constexpr llvm::StringTable DiagGroupNames; /// #endif /// \endcode static void emitAllDiagArrays(DiagsInGroupTy &DiagsInGroup, @@ -1858,9 +1851,7 @@ static void emitDiagTable(DiagsInGroupTy &DiagsInGroup, "0123456789!@#$%^*-+=:?") != std::string::npos) PrintFatalError("Invalid character in diagnostic group '" + Name + "'"); OS << Name << " */, "; - // Store a pascal-style length byte at the beginning of the string. - std::string PascalName = char(Name.size()) + Name.str(); - OS << *GroupNames.GetStringOffset(PascalName) << ", "; + OS << *GroupNames.GetStringOffset(Name) << ", "; // Special handling for 'pedantic'. const bool IsPedantic = Name == "pedantic"; @@ -1948,10 +1939,11 @@ void clang::EmitClangDiagGroups(const RecordKeeper &Records, raw_ostream &OS) { inferPedantic.compute(&DiagsInPedantic, &GroupsInPedantic); StringToOffsetTable GroupNames; + // Add an empty string to the table first so we can use `llvm::StringTable`. + // TODO: Factor this into `StringToOffsetTable`. + GroupNames.GetOrAddStringOffset(""); for (const auto &[Name, Group] : DiagsInGroup) { - // Store a pascal-style length byte at the beginning of the string. - std::string PascalName = char(Name.size()) + Name.str(); - GroupNames.GetOrAddStringOffset(PascalName, false); + GroupNames.GetOrAddStringOffset(Name); } emitAllDiagArrays(DiagsInGroup, DiagsInPedantic, GroupsInPedantic, GroupNames, diff --git a/clang/utils/TableGen/SveEmitter.cpp b/clang/utils/TableGen/SveEmitter.cpp index 35477cfc3cf45..0ecbf7cede1da 100644 --- a/clang/utils/TableGen/SveEmitter.cpp +++ b/clang/utils/TableGen/SveEmitter.cpp @@ -1050,7 +1050,7 @@ std::string Intrinsic::replaceTemplatedArgs(std::string Name, TypeSpec TS, else if (T.isBFloat()) TypeCode = "bf"; else if (T.isMFloat()) - TypeCode = "mfp"; + TypeCode = "mf"; else TypeCode = 'f'; Ret.replace(Pos, NumChars, TypeCode + utostr(T.getElementSizeInBits())); diff --git a/clang/www/cxx_status.html b/clang/www/cxx_status.html index a8e79cd3475ab..575055117b35f 100755 --- a/clang/www/cxx_status.html +++ b/clang/www/cxx_status.html @@ -439,8 +439,8 @@

C++23 implementation status

Using unknown pointers and references in constant expressions - P2280R4 (DR) - No + P2280R4 + Clang 20 static operator() diff --git a/compiler-rt/lib/builtins/arm/adddf3vfp.S b/compiler-rt/lib/builtins/arm/adddf3vfp.S index 1a271db0847c2..280f5ab075638 100644 --- a/compiler-rt/lib/builtins/arm/adddf3vfp.S +++ b/compiler-rt/lib/builtins/arm/adddf3vfp.S @@ -19,10 +19,10 @@ DEFINE_COMPILERRT_FUNCTION(__adddf3vfp) #if defined(COMPILER_RT_ARMHF_TARGET) vadd.f64 d0, d0, d1 #else - vmov d6, r0, r1 // move first param from r0/r1 pair into d6 - vmov d7, r2, r3 // move second param from r2/r3 pair into d7 + VMOV_TO_DOUBLE(d6, r0, r1) // move first param from r0/r1 pair into d6 + VMOV_TO_DOUBLE(d7, r2, r3) // move second param from r2/r3 pair into d7 vadd.f64 d6, d6, d7 - vmov r0, r1, d6 // move result back to r0/r1 pair + VMOV_FROM_DOUBLE(r0, r1, d6) // move result back to r0/r1 pair #endif bx lr END_COMPILERRT_FUNCTION(__adddf3vfp) diff --git a/compiler-rt/lib/builtins/arm/aeabi_dcmp.S b/compiler-rt/lib/builtins/arm/aeabi_dcmp.S index 5f720670ddd7c..bee14b3ff8afe 100644 --- a/compiler-rt/lib/builtins/arm/aeabi_dcmp.S +++ b/compiler-rt/lib/builtins/arm/aeabi_dcmp.S @@ -18,9 +18,9 @@ // } #if defined(COMPILER_RT_ARMHF_TARGET) -# define CONVERT_DCMP_ARGS_TO_DF2_ARGS \ - vmov d0, r0, r1 SEPARATOR \ - vmov d1, r2, r3 +# define CONVERT_DCMP_ARGS_TO_DF2_ARGS \ + VMOV_TO_DOUBLE(d0, r0, r1) \ + VMOV_TO_DOUBLE(d1, r2, r3) #else # define CONVERT_DCMP_ARGS_TO_DF2_ARGS #endif diff --git a/compiler-rt/lib/builtins/arm/divdf3vfp.S b/compiler-rt/lib/builtins/arm/divdf3vfp.S index ad50b57a651db..c8c0aa84c192f 100644 --- a/compiler-rt/lib/builtins/arm/divdf3vfp.S +++ b/compiler-rt/lib/builtins/arm/divdf3vfp.S @@ -20,10 +20,10 @@ DEFINE_COMPILERRT_FUNCTION(__divdf3vfp) #if defined(COMPILER_RT_ARMHF_TARGET) vdiv.f64 d0, d0, d1 #else - vmov d6, r0, r1 // move first param from r0/r1 pair into d6 - vmov d7, r2, r3 // move second param from r2/r3 pair into d7 + VMOV_TO_DOUBLE(d6, r0, r1) // move first param from r0/r1 pair into d6 + VMOV_TO_DOUBLE(d7, r2, r3) // move second param from r2/r3 pair into d7 vdiv.f64 d5, d6, d7 - vmov r0, r1, d5 // move result back to r0/r1 pair + VMOV_FROM_DOUBLE(r0, r1, d5) // move result back to r0/r1 pair #endif bx lr END_COMPILERRT_FUNCTION(__divdf3vfp) diff --git a/compiler-rt/lib/builtins/arm/eqdf2vfp.S b/compiler-rt/lib/builtins/arm/eqdf2vfp.S index 2a0a64b97e7d4..a6f341dc1f46d 100644 --- a/compiler-rt/lib/builtins/arm/eqdf2vfp.S +++ b/compiler-rt/lib/builtins/arm/eqdf2vfp.S @@ -20,8 +20,8 @@ DEFINE_COMPILERRT_FUNCTION(__eqdf2vfp) #if defined(COMPILER_RT_ARMHF_TARGET) vcmp.f64 d0, d1 #else - vmov d6, r0, r1 // load r0/r1 pair in double register - vmov d7, r2, r3 // load r2/r3 pair in double register + VMOV_TO_DOUBLE(d6, r0, r1) // load r0/r1 pair in double register + VMOV_TO_DOUBLE(d7, r2, r3) // load r2/r3 pair in double register vcmp.f64 d6, d7 #endif vmrs apsr_nzcv, fpscr diff --git a/compiler-rt/lib/builtins/arm/extendsfdf2vfp.S b/compiler-rt/lib/builtins/arm/extendsfdf2vfp.S index 37c8be8dcd9c7..815be830003a2 100644 --- a/compiler-rt/lib/builtins/arm/extendsfdf2vfp.S +++ b/compiler-rt/lib/builtins/arm/extendsfdf2vfp.S @@ -23,7 +23,7 @@ DEFINE_COMPILERRT_FUNCTION(__extendsfdf2vfp) #else vmov s15, r0 // load float register from R0 vcvt.f64.f32 d7, s15 // convert single to double - vmov r0, r1, d7 // return result in r0/r1 pair + VMOV_FROM_DOUBLE(r0, r1, d7) // return result in r0/r1 pair #endif bx lr END_COMPILERRT_FUNCTION(__extendsfdf2vfp) diff --git a/compiler-rt/lib/builtins/arm/fixdfsivfp.S b/compiler-rt/lib/builtins/arm/fixdfsivfp.S index af1d4f4fa5f5e..d708f3f4d8051 100644 --- a/compiler-rt/lib/builtins/arm/fixdfsivfp.S +++ b/compiler-rt/lib/builtins/arm/fixdfsivfp.S @@ -22,7 +22,7 @@ DEFINE_COMPILERRT_FUNCTION(__fixdfsivfp) vcvt.s32.f64 s0, d0 vmov r0, s0 #else - vmov d7, r0, r1 // load double register from R0/R1 + VMOV_TO_DOUBLE(d7, r0, r1) // load double register from R0/R1 vcvt.s32.f64 s15, d7 // convert double to 32-bit int into s15 vmov r0, s15 // move s15 to result register #endif diff --git a/compiler-rt/lib/builtins/arm/fixunsdfsivfp.S b/compiler-rt/lib/builtins/arm/fixunsdfsivfp.S index 44e6dbd4989e1..a3dda15e8c045 100644 --- a/compiler-rt/lib/builtins/arm/fixunsdfsivfp.S +++ b/compiler-rt/lib/builtins/arm/fixunsdfsivfp.S @@ -23,7 +23,7 @@ DEFINE_COMPILERRT_FUNCTION(__fixunsdfsivfp) vcvt.u32.f64 s0, d0 vmov r0, s0 #else - vmov d7, r0, r1 // load double register from R0/R1 + VMOV_TO_DOUBLE(d7, r0, r1) // load double register from R0/R1 vcvt.u32.f64 s15, d7 // convert double to 32-bit int into s15 vmov r0, s15 // move s15 to result register #endif diff --git a/compiler-rt/lib/builtins/arm/floatsidfvfp.S b/compiler-rt/lib/builtins/arm/floatsidfvfp.S index ae8d2465889c6..d0fc5e8a4480b 100644 --- a/compiler-rt/lib/builtins/arm/floatsidfvfp.S +++ b/compiler-rt/lib/builtins/arm/floatsidfvfp.S @@ -24,7 +24,7 @@ DEFINE_COMPILERRT_FUNCTION(__floatsidfvfp) #else vmov s15, r0 // move int to float register s15 vcvt.f64.s32 d7, s15 // convert 32-bit int in s15 to double in d7 - vmov r0, r1, d7 // move d7 to result register pair r0/r1 + VMOV_FROM_DOUBLE(r0, r1, d7) // move d7 to result register pair r0/r1 #endif bx lr END_COMPILERRT_FUNCTION(__floatsidfvfp) diff --git a/compiler-rt/lib/builtins/arm/floatunssidfvfp.S b/compiler-rt/lib/builtins/arm/floatunssidfvfp.S index 0932dab2bdb9d..5acc2d5c0b25d 100644 --- a/compiler-rt/lib/builtins/arm/floatunssidfvfp.S +++ b/compiler-rt/lib/builtins/arm/floatunssidfvfp.S @@ -24,7 +24,7 @@ DEFINE_COMPILERRT_FUNCTION(__floatunssidfvfp) #else vmov s15, r0 // move int to float register s15 vcvt.f64.u32 d7, s15 // convert 32-bit int in s15 to double in d7 - vmov r0, r1, d7 // move d7 to result register pair r0/r1 + VMOV_FROM_DOUBLE(r0, r1, d7) // move d7 to result register pair r0/r1 #endif bx lr END_COMPILERRT_FUNCTION(__floatunssidfvfp) diff --git a/compiler-rt/lib/builtins/arm/gedf2vfp.S b/compiler-rt/lib/builtins/arm/gedf2vfp.S index 2af9d909967b0..00746b891c997 100644 --- a/compiler-rt/lib/builtins/arm/gedf2vfp.S +++ b/compiler-rt/lib/builtins/arm/gedf2vfp.S @@ -21,8 +21,8 @@ DEFINE_COMPILERRT_FUNCTION(__gedf2vfp) #if defined(COMPILER_RT_ARMHF_TARGET) vcmp.f64 d0, d1 #else - vmov d6, r0, r1 // load r0/r1 pair in double register - vmov d7, r2, r3 // load r2/r3 pair in double register + VMOV_TO_DOUBLE(d6, r0, r1) // load r0/r1 pair in double register + VMOV_TO_DOUBLE(d7, r2, r3) // load r2/r3 pair in double register vcmp.f64 d6, d7 #endif vmrs apsr_nzcv, fpscr diff --git a/compiler-rt/lib/builtins/arm/gtdf2vfp.S b/compiler-rt/lib/builtins/arm/gtdf2vfp.S index 782ad8cac013d..980a09eb24b01 100644 --- a/compiler-rt/lib/builtins/arm/gtdf2vfp.S +++ b/compiler-rt/lib/builtins/arm/gtdf2vfp.S @@ -21,8 +21,8 @@ DEFINE_COMPILERRT_FUNCTION(__gtdf2vfp) #if defined(COMPILER_RT_ARMHF_TARGET) vcmp.f64 d0, d1 #else - vmov d6, r0, r1 // load r0/r1 pair in double register - vmov d7, r2, r3 // load r2/r3 pair in double register + VMOV_TO_DOUBLE(d6, r0, r1) // load r0/r1 pair in double register + VMOV_TO_DOUBLE(d7, r2, r3) // load r2/r3 pair in double register vcmp.f64 d6, d7 #endif vmrs apsr_nzcv, fpscr diff --git a/compiler-rt/lib/builtins/arm/ledf2vfp.S b/compiler-rt/lib/builtins/arm/ledf2vfp.S index 0097e4b6c129a..c7fe6d84535a4 100644 --- a/compiler-rt/lib/builtins/arm/ledf2vfp.S +++ b/compiler-rt/lib/builtins/arm/ledf2vfp.S @@ -21,8 +21,8 @@ DEFINE_COMPILERRT_FUNCTION(__ledf2vfp) #if defined(COMPILER_RT_ARMHF_TARGET) vcmp.f64 d0, d1 #else - vmov d6, r0, r1 // load r0/r1 pair in double register - vmov d7, r2, r3 // load r2/r3 pair in double register + VMOV_TO_DOUBLE(d6, r0, r1) // load r0/r1 pair in double register + VMOV_TO_DOUBLE(d7, r2, r3) // load r2/r3 pair in double register vcmp.f64 d6, d7 #endif vmrs apsr_nzcv, fpscr diff --git a/compiler-rt/lib/builtins/arm/ltdf2vfp.S b/compiler-rt/lib/builtins/arm/ltdf2vfp.S index a126aa9e0536a..be5827075f993 100644 --- a/compiler-rt/lib/builtins/arm/ltdf2vfp.S +++ b/compiler-rt/lib/builtins/arm/ltdf2vfp.S @@ -21,8 +21,8 @@ DEFINE_COMPILERRT_FUNCTION(__ltdf2vfp) #if defined(COMPILER_RT_ARMHF_TARGET) vcmp.f64 d0, d1 #else - vmov d6, r0, r1 // load r0/r1 pair in double register - vmov d7, r2, r3 // load r2/r3 pair in double register + VMOV_TO_DOUBLE(d6, r0, r1) // load r0/r1 pair in double register + VMOV_TO_DOUBLE(d7, r2, r3) // load r2/r3 pair in double register vcmp.f64 d6, d7 #endif vmrs apsr_nzcv, fpscr diff --git a/compiler-rt/lib/builtins/arm/muldf3vfp.S b/compiler-rt/lib/builtins/arm/muldf3vfp.S index 9adc937bcb3f0..97daf7363787b 100644 --- a/compiler-rt/lib/builtins/arm/muldf3vfp.S +++ b/compiler-rt/lib/builtins/arm/muldf3vfp.S @@ -20,10 +20,10 @@ DEFINE_COMPILERRT_FUNCTION(__muldf3vfp) #if defined(COMPILER_RT_ARMHF_TARGET) vmul.f64 d0, d0, d1 #else - vmov d6, r0, r1 // move first param from r0/r1 pair into d6 - vmov d7, r2, r3 // move second param from r2/r3 pair into d7 + VMOV_TO_DOUBLE(d6, r0, r1) // move first param from r0/r1 pair into d6 + VMOV_TO_DOUBLE(d7, r2, r3) // move second param from r2/r3 pair into d7 vmul.f64 d6, d6, d7 - vmov r0, r1, d6 // move result back to r0/r1 pair + VMOV_FROM_DOUBLE(r0, r1, d6) // move result back to r0/r1 pair #endif bx lr END_COMPILERRT_FUNCTION(__muldf3vfp) diff --git a/compiler-rt/lib/builtins/arm/nedf2vfp.S b/compiler-rt/lib/builtins/arm/nedf2vfp.S index 32d35c41d4664..5edafc25988db 100644 --- a/compiler-rt/lib/builtins/arm/nedf2vfp.S +++ b/compiler-rt/lib/builtins/arm/nedf2vfp.S @@ -20,8 +20,8 @@ DEFINE_COMPILERRT_FUNCTION(__nedf2vfp) #if defined(COMPILER_RT_ARMHF_TARGET) vcmp.f64 d0, d1 #else - vmov d6, r0, r1 // load r0/r1 pair in double register - vmov d7, r2, r3 // load r2/r3 pair in double register + VMOV_TO_DOUBLE(d6, r0, r1) // load r0/r1 pair in double register + VMOV_TO_DOUBLE(d7, r2, r3) // load r2/r3 pair in double register vcmp.f64 d6, d7 #endif vmrs apsr_nzcv, fpscr diff --git a/compiler-rt/lib/builtins/arm/subdf3vfp.S b/compiler-rt/lib/builtins/arm/subdf3vfp.S index f4eaf9af1afee..2a7b1d38b577f 100644 --- a/compiler-rt/lib/builtins/arm/subdf3vfp.S +++ b/compiler-rt/lib/builtins/arm/subdf3vfp.S @@ -20,10 +20,10 @@ DEFINE_COMPILERRT_FUNCTION(__subdf3vfp) #if defined(COMPILER_RT_ARMHF_TARGET) vsub.f64 d0, d0, d1 #else - vmov d6, r0, r1 // move first param from r0/r1 pair into d6 - vmov d7, r2, r3 // move second param from r2/r3 pair into d7 + VMOV_TO_DOUBLE(d6, r0, r1) // move first param from r0/r1 pair into d6 + VMOV_TO_DOUBLE(d7, r2, r3) // move second param from r2/r3 pair into d7 vsub.f64 d6, d6, d7 - vmov r0, r1, d6 // move result back to r0/r1 pair + VMOV_FROM_DOUBLE(r0, r1, d6) // move result back to r0/r1 pair #endif bx lr END_COMPILERRT_FUNCTION(__subdf3vfp) diff --git a/compiler-rt/lib/builtins/arm/truncdfsf2vfp.S b/compiler-rt/lib/builtins/arm/truncdfsf2vfp.S index e1c171262a78b..541d025b4f922 100644 --- a/compiler-rt/lib/builtins/arm/truncdfsf2vfp.S +++ b/compiler-rt/lib/builtins/arm/truncdfsf2vfp.S @@ -21,7 +21,7 @@ DEFINE_COMPILERRT_FUNCTION(__truncdfsf2vfp) #if defined(COMPILER_RT_ARMHF_TARGET) vcvt.f32.f64 s0, d0 #else - vmov d7, r0, r1 // load double from r0/r1 pair + VMOV_TO_DOUBLE(d7, r0, r1) // load double from r0/r1 pair vcvt.f32.f64 s15, d7 // convert double to single (trucate precision) vmov r0, s15 // return result in r0 #endif diff --git a/compiler-rt/lib/builtins/arm/unorddf2vfp.S b/compiler-rt/lib/builtins/arm/unorddf2vfp.S index ea36a1cb55949..3abb622c81ecb 100644 --- a/compiler-rt/lib/builtins/arm/unorddf2vfp.S +++ b/compiler-rt/lib/builtins/arm/unorddf2vfp.S @@ -21,8 +21,8 @@ DEFINE_COMPILERRT_FUNCTION(__unorddf2vfp) #if defined(COMPILER_RT_ARMHF_TARGET) vcmp.f64 d0, d1 #else - vmov d6, r0, r1 // load r0/r1 pair in double register - vmov d7, r2, r3 // load r2/r3 pair in double register + VMOV_TO_DOUBLE(d6, r0, r1) // load r0/r1 pair in double register + VMOV_TO_DOUBLE(d7, r2, r3) // load r2/r3 pair in double register vcmp.f64 d6, d7 #endif vmrs apsr_nzcv, fpscr diff --git a/compiler-rt/lib/builtins/assembly.h b/compiler-rt/lib/builtins/assembly.h index 8c42fc773483b..34c71241524dc 100644 --- a/compiler-rt/lib/builtins/assembly.h +++ b/compiler-rt/lib/builtins/assembly.h @@ -290,4 +290,16 @@ CFI_END #endif +#ifdef __arm__ +#include "int_endianness.h" + +#if _YUGA_BIG_ENDIAN +#define VMOV_TO_DOUBLE(dst, src0, src1) vmov dst, src1, src0 SEPARATOR +#define VMOV_FROM_DOUBLE(dst0, dst1, src) vmov dst1, dst0, src SEPARATOR +#else +#define VMOV_TO_DOUBLE(dst, src0, src1) vmov dst, src0, src1 SEPARATOR +#define VMOV_FROM_DOUBLE(dst0, dst1, src) vmov dst0, dst1, src SEPARATOR +#endif +#endif + #endif // COMPILERRT_ASSEMBLY_H diff --git a/compiler-rt/lib/interception/interception_win.cpp b/compiler-rt/lib/interception/interception_win.cpp index 0841161ee5c42..64004c171d534 100644 --- a/compiler-rt/lib/interception/interception_win.cpp +++ b/compiler-rt/lib/interception/interception_win.cpp @@ -606,6 +606,7 @@ static size_t GetInstructionSize(uptr address, size_t* rel_offset = nullptr) { case 0xb8: // b8 XX XX XX XX : mov eax, XX XX XX XX case 0xB9: // b9 XX XX XX XX : mov ecx, XX XX XX XX + case 0xBA: // ba XX XX XX XX : mov edx, XX XX XX XX return 5; // Cannot overwrite control-instruction. Return 0 to indicate failure. @@ -666,6 +667,9 @@ static size_t GetInstructionSize(uptr address, size_t* rel_offset = nullptr) { } switch (0x00FFFFFF & *(u32 *)address) { + case 0x244C8D: // 8D 4C 24 XX : lea ecx, [esp + XX] + case 0x2474FF: // FF 74 24 XX : push qword ptr [rsp + XX] + return 4; case 0x24A48D: // 8D A4 24 XX XX XX XX : lea esp, [esp + XX XX XX XX] return 7; } @@ -829,8 +833,13 @@ static size_t GetInstructionSize(uptr address, size_t* rel_offset = nullptr) { case 0x588948: // 48 89 58 XX : mov QWORD PTR[rax + XX], rbx case 0xec8348: // 48 83 ec XX : sub rsp, XX case 0xf88349: // 49 83 f8 XX : cmp r8, XX + case 0x488d49: // 49 8d 48 XX : lea rcx, [...] + case 0x048d4c: // 4c 8d 04 XX : lea r8, [...] + case 0x148d4e: // 4e 8d 14 XX : lea r10, [...] + case 0x398366: // 66 83 39 XX : cmp WORD PTR [rcx], XX return 4; + case 0x441F0F: // 0F 1F 44 XX XX : nop DWORD PTR [...] case 0x246483: // 83 64 24 XX YY : and DWORD PTR [rsp+XX], YY return 5; @@ -883,6 +892,10 @@ static size_t GetInstructionSize(uptr address, size_t* rel_offset = nullptr) { } switch (*(u32*)(address)) { + case 0x01b60f44: // 44 0f b6 01 : movzx r8d, BYTE PTR [rcx] + case 0x09b60f44: // 44 0f b6 09 : movzx r9d, BYTE PTR [rcx] + case 0x0ab60f44: // 44 0f b6 0a : movzx r8d, BYTE PTR [rdx] + case 0x11b60f44: // 44 0f b6 11 : movzx r10d, BYTE PTR [rcx] case 0x1ab60f44: // 44 0f b6 1a : movzx r11d, BYTE PTR [rdx] return 4; case 0x24448b48: // 48 8b 44 24 XX : mov rax, QWORD ptr [rsp + XX] @@ -902,6 +915,11 @@ static size_t GetInstructionSize(uptr address, size_t* rel_offset = nullptr) { return 6; } + switch (0xFFFFFFFFFFULL & *(u64 *)(address)) { + case 0xC07E0F4866: // 66 48 0F 7E C0 : movq rax, xmm0 + return 5; + } + #else switch (*(u8*)address) { diff --git a/compiler-rt/lib/interception/tests/interception_win_test.cpp b/compiler-rt/lib/interception/tests/interception_win_test.cpp index 9d8dbfcb4285f..c5dcf26070f0d 100644 --- a/compiler-rt/lib/interception/tests/interception_win_test.cpp +++ b/compiler-rt/lib/interception/tests/interception_win_test.cpp @@ -864,9 +864,12 @@ const struct InstructionSizeData { { 3, {0x8B, 0x55, 0x72}, 0, "8B 55 XX : mov XX(%ebp), edx"}, { 3, {0x8B, 0x75, 0x72}, 0, "8B 75 XX : mov XX(%ebp), esp"}, { 3, {0xc2, 0x71, 0x72}, 0, "C2 XX XX : ret XX (needed for registering weak functions)"}, + { 4, {0x8D, 0x4C, 0x24, 0x73}, 0, "8D 4C 24 XX : lea ecx, [esp + XX]"}, + { 4, {0xFF, 0x74, 0x24, 0x73}, 0, "FF 74 24 XX : push qword ptr [rsp + XX]"}, { 5, {0x68, 0x71, 0x72, 0x73, 0x74}, 0, "68 XX XX XX XX : push imm32"}, { 5, {0xb8, 0x71, 0x72, 0x73, 0x74}, 0, "b8 XX XX XX XX : mov eax, XX XX XX XX"}, { 5, {0xB9, 0x71, 0x72, 0x73, 0x74}, 0, "b9 XX XX XX XX : mov ecx, XX XX XX XX"}, + { 5, {0xBA, 0x71, 0x72, 0x73, 0x74}, 0, "ba XX XX XX XX : mov edx, XX XX XX XX"}, { 7, {0x8D, 0xA4, 0x24, 0x73, 0x74, 0x75, 0x76}, 0, "8D A4 24 XX XX XX XX : lea esp, [esp + XX XX XX XX]"}, #if SANITIZER_WINDOWS_x64 // sorted list @@ -961,11 +964,19 @@ const struct InstructionSizeData { { 3, {0x4d, 0x85, 0xf6}, 0, "4d 85 f6 : test r14, r14"}, { 3, {0x4d, 0x85, 0xff}, 0, "4d 85 ff : test r15, r15"}, { 3, {0xf6, 0xc1, 0x72}, 0, "f6 c1 XX : test cl, XX"}, + { 4, {0x44, 0x0f, 0xb6, 0x01}, 0, "44 0f b6 01 : movzx r8d, BYTE PTR [rcx]"}, + { 4, {0x44, 0x0f, 0xb6, 0x09}, 0, "44 0f b6 09 : movzx r9d, BYTE PTR [rcx]"}, + { 4, {0x44, 0x0f, 0xb6, 0x0a}, 0, "44 0f b6 0a : movzx r8d, BYTE PTR [rdx]"}, + { 4, {0x44, 0x0f, 0xb6, 0x11}, 0, "44 0f b6 11 : movzx r10d, BYTE PTR [rcx]"}, { 4, {0x44, 0x0f, 0xb6, 0x1a}, 0, "44 0f b6 1a : movzx r11d, BYTE PTR [rdx]"}, { 4, {0x44, 0x8d, 0x42, 0x73}, 0, "44 8d 42 XX : lea r8d , [rdx + XX]"}, { 4, {0x48, 0x83, 0xec, 0x73}, 0, "48 83 ec XX : sub rsp, XX"}, { 4, {0x48, 0x89, 0x58, 0x73}, 0, "48 89 58 XX : mov QWORD PTR[rax + XX], rbx"}, { 4, {0x49, 0x83, 0xf8, 0x73}, 0, "49 83 f8 XX : cmp r8, XX"}, + { 4, {0x49, 0x8d, 0x48, 0x73}, 0, "49 8d 48 XX : lea rcx, [...]"}, + { 4, {0x4c, 0x8d, 0x04, 0x73}, 0, "4c 8d 04 XX : lea r8, [...]"}, + { 4, {0x4e, 0x8d, 0x14, 0x73}, 0, "4e 8d 14 XX : lea r10, [...]"}, + { 4, {0x66, 0x83, 0x39, 0x73}, 0, "66 83 39 XX : cmp WORD PTR [rcx], XX"}, { 4, {0x80, 0x78, 0x72, 0x73}, 0, "80 78 YY XX : cmp BYTE PTR [rax+YY], XX"}, { 4, {0x80, 0x79, 0x72, 0x73}, 0, "80 79 YY XX : cmp BYTE ptr [rcx+YY], XX"}, { 4, {0x80, 0x7A, 0x72, 0x73}, 0, "80 7A YY XX : cmp BYTE PTR [rdx+YY], XX"}, @@ -973,6 +984,7 @@ const struct InstructionSizeData { { 4, {0x80, 0x7D, 0x72, 0x73}, 0, "80 7D YY XX : cmp BYTE PTR [rbp+YY], XX"}, { 4, {0x80, 0x7E, 0x72, 0x73}, 0, "80 7E YY XX : cmp BYTE PTR [rsi+YY], XX"}, { 4, {0x89, 0x54, 0x24, 0x73}, 0, "89 54 24 XX : mov DWORD PTR[rsp + XX], edx"}, + { 5, {0x0F, 0x1F, 0x44, 0x73, 0x74}, 0, "0F 1F 44 XX XX : nop DWORD PTR [...]"}, { 5, {0x44, 0x89, 0x44, 0x24, 0x74}, 0, "44 89 44 24 XX : mov DWORD PTR [rsp + XX], r8d"}, { 5, {0x44, 0x89, 0x4c, 0x24, 0x74}, 0, "44 89 4c 24 XX : mov DWORD PTR [rsp + XX], r9d"}, { 5, {0x48, 0x89, 0x4C, 0x24, 0x74}, 0, "48 89 4C 24 XX : mov QWORD PTR [rsp + XX], rcx"}, @@ -985,6 +997,7 @@ const struct InstructionSizeData { { 5, {0x48, 0x8d, 0x6c, 0x24, 0x74}, 0, "48 8d 6c 24 XX : lea rbp, [rsp + XX]"}, { 5, {0x4c, 0x89, 0x44, 0x24, 0x74}, 0, "4c 89 44 24 XX : mov QWORD PTR [rsp + XX], r8"}, { 5, {0x4c, 0x89, 0x4c, 0x24, 0x74}, 0, "4c 89 4c 24 XX : mov QWORD PTR [rsp + XX], r9"}, + { 5, {0x66, 0x48, 0x0F, 0x7E, 0xC0}, 0, "66 48 0F 7E C0 : movq rax, xmm0"}, { 5, {0x83, 0x44, 0x72, 0x73, 0x74}, 0, "83 44 72 XX YY : add DWORD PTR [rdx+rsi*2+XX],YY"}, { 5, {0x83, 0x64, 0x24, 0x73, 0x74}, 0, "83 64 24 XX YY : and DWORD PTR [rsp+XX], YY"}, { 6, {0x48, 0x83, 0x64, 0x24, 0x74, 0x75}, 0, "48 83 64 24 XX YY : and QWORD PTR [rsp + XX], YY"}, diff --git a/compiler-rt/lib/rtsan/rtsan_interceptors_posix.cpp b/compiler-rt/lib/rtsan/rtsan_interceptors_posix.cpp index 34c2d4cb37fd0..71938d3edba38 100644 --- a/compiler-rt/lib/rtsan/rtsan_interceptors_posix.cpp +++ b/compiler-rt/lib/rtsan/rtsan_interceptors_posix.cpp @@ -808,6 +808,35 @@ INTERCEPTOR(int, munmap, void *addr, size_t length) { return REAL(munmap)(addr, length); } +INTERCEPTOR(int, madvise, void *addr, size_t length, int flag) { + __rtsan_notify_intercepted_call("madvise"); + return REAL(madvise)(addr, length, flag); +} + +INTERCEPTOR(int, posix_madvise, void *addr, size_t length, int flag) { + __rtsan_notify_intercepted_call("posix_madvise"); + return REAL(posix_madvise)(addr, length, flag); +} + +INTERCEPTOR(int, mprotect, void *addr, size_t length, int prot) { + __rtsan_notify_intercepted_call("mprotect"); + return REAL(mprotect)(addr, length, prot); +} + +INTERCEPTOR(int, msync, void *addr, size_t length, int flag) { + __rtsan_notify_intercepted_call("msync"); + return REAL(msync)(addr, length, flag); +} + +#if SANITIZER_APPLE +INTERCEPTOR(int, mincore, const void *addr, size_t length, char *vec) { +#else +INTERCEPTOR(int, mincore, void *addr, size_t length, unsigned char *vec) { +#endif + __rtsan_notify_intercepted_call("mincore"); + return REAL(mincore)(addr, length, vec); +} + INTERCEPTOR(int, shm_open, const char *name, int oflag, mode_t mode) { __rtsan_notify_intercepted_call("shm_open"); return REAL(shm_open)(name, oflag, mode); @@ -894,8 +923,13 @@ INTERCEPTOR(ssize_t, sendmsg, int socket, const struct msghdr *message, } #if SANITIZER_INTERCEPT_SENDMMSG +#if SANITIZER_MUSL +INTERCEPTOR(int, sendmmsg, int socket, struct mmsghdr *message, + unsigned int len, unsigned int flags) { +#else INTERCEPTOR(int, sendmmsg, int socket, struct mmsghdr *message, unsigned int len, int flags) { +#endif __rtsan_notify_intercepted_call("sendmmsg"); return REAL(sendmmsg)(socket, message, len, flags); } @@ -927,8 +961,16 @@ INTERCEPTOR(ssize_t, recvmsg, int socket, struct msghdr *message, int flags) { } #if SANITIZER_INTERCEPT_RECVMMSG +#if SANITIZER_MUSL +INTERCEPTOR(int, recvmmsg, int socket, struct mmsghdr *message, + unsigned int len, unsigned int flags, struct timespec *timeout) { +#elif defined(__GLIBC_MINOR__) && __GLIBC_MINOR__ < 21 +INTERCEPTOR(int, recvmmsg, int socket, struct mmsghdr *message, + unsigned int len, int flags, const struct timespec *timeout) { +#else INTERCEPTOR(int, recvmmsg, int socket, struct mmsghdr *message, unsigned int len, int flags, struct timespec *timeout) { +#endif // defined(__GLIBC_MINOR) && __GLIBC_MINOR__ < 21 __rtsan_notify_intercepted_call("recvmmsg"); return REAL(recvmmsg)(socket, message, len, flags, timeout); } @@ -1093,6 +1135,32 @@ INTERCEPTOR(int, execve, const char *filename, char *const argv[], return REAL(execve)(filename, argv, envp); } +#if SANITIZER_INTERCEPT_PROCESS_VM_READV +INTERCEPTOR(ssize_t, process_vm_readv, pid_t pid, const struct iovec *local_iov, + unsigned long liovcnt, const struct iovec *remote_iov, + unsigned long riovcnt, unsigned long flags) { + __rtsan_notify_intercepted_call("process_vm_readv"); + return REAL(process_vm_readv)(pid, local_iov, liovcnt, remote_iov, riovcnt, + flags); +} + +INTERCEPTOR(ssize_t, process_vm_writev, pid_t pid, + const struct iovec *local_iov, unsigned long liovcnt, + const struct iovec *remote_iov, unsigned long riovcnt, + unsigned long flags) { + __rtsan_notify_intercepted_call("process_vm_writev"); + return REAL(process_vm_writev)(pid, local_iov, liovcnt, remote_iov, riovcnt, + flags); +} +#define RTSAN_MAYBE_INTERCEPT_PROCESS_VM_READV \ + INTERCEPT_FUNCTION(process_vm_readv) +#define RTSAN_MAYBE_INTERCEPT_PROCESS_VM_WRITEV \ + INTERCEPT_FUNCTION(process_vm_writev) +#else +#define RTSAN_MAYBE_INTERCEPT_PROCESS_VM_READV +#define RTSAN_MAYBE_INTERCEPT_PROCESS_VM_WRITEV +#endif + // TODO: the `wait` family of functions is an oddity. In testing, if you // intercept them, Darwin seemingly ignores them, and linux never returns from // the test. Revisit this in the future, but hopefully intercepting fork/exec is @@ -1148,6 +1216,11 @@ void __rtsan::InitializeInterceptors() { INTERCEPT_FUNCTION(mmap); RTSAN_MAYBE_INTERCEPT_MMAP64; INTERCEPT_FUNCTION(munmap); + INTERCEPT_FUNCTION(madvise); + INTERCEPT_FUNCTION(posix_madvise); + INTERCEPT_FUNCTION(mprotect); + INTERCEPT_FUNCTION(msync); + INTERCEPT_FUNCTION(mincore); INTERCEPT_FUNCTION(shm_open); INTERCEPT_FUNCTION(shm_unlink); RTSAN_MAYBE_INTERCEPT_MEMALIGN; @@ -1272,6 +1345,9 @@ void __rtsan::InitializeInterceptors() { INTERCEPT_FUNCTION(fork); INTERCEPT_FUNCTION(execve); + RTSAN_MAYBE_INTERCEPT_PROCESS_VM_READV; + RTSAN_MAYBE_INTERCEPT_PROCESS_VM_WRITEV; + INTERCEPT_FUNCTION(syscall); } diff --git a/compiler-rt/lib/rtsan/tests/rtsan_test_interceptors_posix.cpp b/compiler-rt/lib/rtsan/tests/rtsan_test_interceptors_posix.cpp index c858a5a771fe4..0a59ae0ea9254 100644 --- a/compiler-rt/lib/rtsan/tests/rtsan_test_interceptors_posix.cpp +++ b/compiler-rt/lib/rtsan/tests/rtsan_test_interceptors_posix.cpp @@ -204,6 +204,75 @@ TEST(TestRtsanInterceptors, MunmapDiesWhenRealtime) { ExpectNonRealtimeSurvival(Func); } +class RtsanOpenedMmapTest : public RtsanFileTest { +protected: + void SetUp() override { + RtsanFileTest::SetUp(); + file = fopen(GetTemporaryFilePath(), "w+"); + ASSERT_THAT(file, Ne(nullptr)); + fd = fileno(file); + ASSERT_THAT(fd, Ne(-1)); + int ret = ftruncate(GetOpenFd(), size); + ASSERT_THAT(ret, Ne(-1)); + addr = + mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, GetOpenFd(), 0); + ASSERT_THAT(addr, Ne(MAP_FAILED)); + ASSERT_THAT(addr, Ne(nullptr)); + } + + void TearDown() override { + if (addr != nullptr && addr != MAP_FAILED) + munmap(addr, size); + RtsanFileTest::TearDown(); + } + + void *GetAddr() { return addr; } + static constexpr size_t GetSize() { return size; } + + int GetOpenFd() { return fd; } + +private: + void *addr = nullptr; + static constexpr size_t size = 4096; + FILE *file = nullptr; + int fd = -1; +}; + +TEST_F(RtsanOpenedMmapTest, MadviseDiesWhenRealtime) { + auto Func = [this]() { madvise(GetAddr(), GetSize(), MADV_NORMAL); }; + ExpectRealtimeDeath(Func, "madvise"); + ExpectNonRealtimeSurvival(Func); +} + +TEST_F(RtsanOpenedMmapTest, PosixMadviseDiesWhenRealtime) { + auto Func = [this]() { posix_madvise(GetAddr(), GetSize(), MADV_NORMAL); }; + ExpectRealtimeDeath(Func, "posix_madvise"); + ExpectNonRealtimeSurvival(Func); +} + +TEST_F(RtsanOpenedMmapTest, MprotectDiesWhenRealtime) { + auto Func = [this]() { mprotect(GetAddr(), GetSize(), PROT_READ); }; + ExpectRealtimeDeath(Func, "mprotect"); + ExpectNonRealtimeSurvival(Func); +} + +TEST_F(RtsanOpenedMmapTest, MsyncDiesWhenRealtime) { + auto Func = [this]() { msync(GetAddr(), GetSize(), MS_INVALIDATE); }; + ExpectRealtimeDeath(Func, "msync"); + ExpectNonRealtimeSurvival(Func); +} + +TEST_F(RtsanOpenedMmapTest, MincoreDiesWhenRealtime) { +#if SANITIZER_APPLE + std::vector vec(GetSize() / 1024); +#else + std::vector vec(GetSize() / 1024); +#endif + auto Func = [this, &vec]() { mincore(GetAddr(), GetSize(), vec.data()); }; + ExpectRealtimeDeath(Func, "mincore"); + ExpectNonRealtimeSurvival(Func); +} + TEST(TestRtsanInterceptors, ShmOpenDiesWhenRealtime) { auto Func = []() { shm_open("/rtsan_test_shm", O_CREAT | O_RDWR, 0); }; ExpectRealtimeDeath(Func, "shm_open"); @@ -657,6 +726,28 @@ TEST(TestRtsanInterceptors, UmaskDiesWhenRealtime) { ExpectNonRealtimeSurvival(Func); } +#if SANITIZER_INTERCEPT_PROCESS_VM_READV +TEST(TestRtsanInterceptors, ProcessVmReadvDiesWhenRealtime) { + char stack[1024]; + int p; + iovec lcl{&stack, sizeof(stack)}; + iovec rmt{&p, sizeof(p)}; + auto Func = [&lcl, &rmt]() { process_vm_readv(0, &lcl, 1, &rmt, 1, 0); }; + ExpectRealtimeDeath(Func, "process_vm_readv"); + ExpectNonRealtimeSurvival(Func); +} + +TEST(TestRtsanInterceptors, ProcessVmWritevDiesWhenRealtime) { + char stack[1024]; + int p; + iovec lcl{&p, sizeof(p)}; + iovec rmt{&stack, sizeof(stack)}; + auto Func = [&lcl, &rmt]() { process_vm_writev(0, &lcl, 1, &rmt, 1, 0); }; + ExpectRealtimeDeath(Func, "process_vm_writev"); + ExpectNonRealtimeSurvival(Func); +} +#endif + class RtsanDirectoryTest : public ::testing::Test { protected: void SetUp() override { diff --git a/compiler-rt/test/asan/TestCases/Posix/fake_stack_gc.cpp b/compiler-rt/test/asan/TestCases/Posix/fake_stack_gc.cpp index 8c368b9b1b947..36fdf81120b59 100644 --- a/compiler-rt/test/asan/TestCases/Posix/fake_stack_gc.cpp +++ b/compiler-rt/test/asan/TestCases/Posix/fake_stack_gc.cpp @@ -89,6 +89,7 @@ int main(void) { pthread_t tid; assert(pthread_create(&tid, &attr, Thread, alt_stack) == 0); + assert(pthread_attr_destroy(&attr) == 0); pthread_join(tid, nullptr); diff --git a/compiler-rt/test/asan/TestCases/Posix/unpoison-alternate-stack.cpp b/compiler-rt/test/asan/TestCases/Posix/unpoison-alternate-stack.cpp index 593114bdf2e8d..8e7d5082d0b5d 100644 --- a/compiler-rt/test/asan/TestCases/Posix/unpoison-alternate-stack.cpp +++ b/compiler-rt/test/asan/TestCases/Posix/unpoison-alternate-stack.cpp @@ -159,6 +159,7 @@ int main() { pthread_attr_init(&ThreadAttr); pthread_attr_setstack(&ThreadAttr, Mapping, DefaultStackSize); pthread_create(&Thread, &ThreadAttr, &threadFun, (void *)&AltStack); + pthread_attr_destroy(&ThreadAttr); pthread_join(Thread, nullptr); diff --git a/compiler-rt/test/lsan/TestCases/leak_check_before_thread_started.cpp b/compiler-rt/test/lsan/TestCases/leak_check_before_thread_started.cpp index 68eea93a81e57..d0363a0bf85ae 100644 --- a/compiler-rt/test/lsan/TestCases/leak_check_before_thread_started.cpp +++ b/compiler-rt/test/lsan/TestCases/leak_check_before_thread_started.cpp @@ -37,6 +37,7 @@ void create_detached_thread() { pthread_mutex_lock(&mutex); int res = pthread_create(&thread_id, &attr, func, arg); assert(res == 0); + pthread_attr_destroy(&attr); } int main() { diff --git a/flang/include/flang/Lower/DirectivesCommon.h b/flang/include/flang/Lower/DirectivesCommon.h index 6e2c6ee4b1bcd..c7cac1357b227 100644 --- a/flang/include/flang/Lower/DirectivesCommon.h +++ b/flang/include/flang/Lower/DirectivesCommon.h @@ -29,12 +29,9 @@ #include "flang/Lower/PFTBuilder.h" #include "flang/Lower/StatementContext.h" #include "flang/Lower/Support/Utils.h" -#include "flang/Optimizer/Builder/BoxValue.h" -#include "flang/Optimizer/Builder/FIRBuilder.h" +#include "flang/Optimizer/Builder/DirectivesCommon.h" #include "flang/Optimizer/Builder/HLFIRTools.h" -#include "flang/Optimizer/Builder/Todo.h" #include "flang/Optimizer/Dialect/FIRType.h" -#include "flang/Optimizer/HLFIR/HLFIROps.h" #include "flang/Parser/parse-tree.h" #include "flang/Semantics/openmp-directive-sets.h" #include "flang/Semantics/tools.h" @@ -49,31 +46,6 @@ namespace Fortran { namespace lower { -/// Information gathered to generate bounds operation and data entry/exit -/// operations. -struct AddrAndBoundsInfo { - explicit AddrAndBoundsInfo() {} - explicit AddrAndBoundsInfo(mlir::Value addr, mlir::Value rawInput) - : addr(addr), rawInput(rawInput) {} - explicit AddrAndBoundsInfo(mlir::Value addr, mlir::Value rawInput, - mlir::Value isPresent) - : addr(addr), rawInput(rawInput), isPresent(isPresent) {} - explicit AddrAndBoundsInfo(mlir::Value addr, mlir::Value rawInput, - mlir::Value isPresent, mlir::Type boxType) - : addr(addr), rawInput(rawInput), isPresent(isPresent), boxType(boxType) { - } - mlir::Value addr = nullptr; - mlir::Value rawInput = nullptr; - mlir::Value isPresent = nullptr; - mlir::Type boxType = nullptr; - void dump(llvm::raw_ostream &os) { - os << "AddrAndBoundsInfo addr: " << addr << "\n"; - os << "AddrAndBoundsInfo rawInput: " << rawInput << "\n"; - os << "AddrAndBoundsInfo isPresent: " << isPresent << "\n"; - os << "AddrAndBoundsInfo boxType: " << boxType << "\n"; - } -}; - /// Populates \p hint and \p memoryOrder with appropriate clause information /// if present on atomic construct. static inline void genOmpAtomicHintAndMemoryOrderClauses( @@ -609,195 +581,13 @@ void createEmptyRegionBlocks( } } -inline AddrAndBoundsInfo getDataOperandBaseAddr(fir::FirOpBuilder &builder, - mlir::Value symAddr, - bool isOptional, - mlir::Location loc) { - mlir::Value rawInput = symAddr; - if (auto declareOp = - mlir::dyn_cast_or_null(symAddr.getDefiningOp())) { - symAddr = declareOp.getResults()[0]; - rawInput = declareOp.getResults()[1]; - } - - if (!symAddr) - llvm::report_fatal_error("could not retrieve symbol address"); - - mlir::Value isPresent; - if (isOptional) - isPresent = - builder.create(loc, builder.getI1Type(), rawInput); - - if (auto boxTy = mlir::dyn_cast( - fir::unwrapRefType(symAddr.getType()))) { - if (mlir::isa(boxTy.getEleTy())) - TODO(loc, "derived type"); - - // In case of a box reference, load it here to get the box value. - // This is preferrable because then the same box value can then be used for - // all address/dimension retrievals. For Fortran optional though, leave - // the load generation for later so it can be done in the appropriate - // if branches. - if (mlir::isa(symAddr.getType()) && !isOptional) { - mlir::Value addr = builder.create(loc, symAddr); - return AddrAndBoundsInfo(addr, rawInput, isPresent, boxTy); - } - - return AddrAndBoundsInfo(symAddr, rawInput, isPresent, boxTy); - } - return AddrAndBoundsInfo(symAddr, rawInput, isPresent); -} - -inline AddrAndBoundsInfo +inline fir::factory::AddrAndBoundsInfo getDataOperandBaseAddr(Fortran::lower::AbstractConverter &converter, fir::FirOpBuilder &builder, Fortran::lower::SymbolRef sym, mlir::Location loc) { - return getDataOperandBaseAddr(builder, converter.getSymbolAddress(sym), - Fortran::semantics::IsOptional(sym), loc); -} - -template -llvm::SmallVector -gatherBoundsOrBoundValues(fir::FirOpBuilder &builder, mlir::Location loc, - fir::ExtendedValue dataExv, mlir::Value box, - bool collectValuesOnly = false) { - assert(box && "box must exist"); - llvm::SmallVector values; - mlir::Value byteStride; - mlir::Type idxTy = builder.getIndexType(); - mlir::Type boundTy = builder.getType(); - mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1); - for (unsigned dim = 0; dim < dataExv.rank(); ++dim) { - mlir::Value d = builder.createIntegerConstant(loc, idxTy, dim); - mlir::Value baseLb = - fir::factory::readLowerBound(builder, loc, dataExv, dim, one); - auto dimInfo = - builder.create(loc, idxTy, idxTy, idxTy, box, d); - mlir::Value lb = builder.createIntegerConstant(loc, idxTy, 0); - mlir::Value ub = - builder.create(loc, dimInfo.getExtent(), one); - if (dim == 0) // First stride is the element size. - byteStride = dimInfo.getByteStride(); - if (collectValuesOnly) { - values.push_back(lb); - values.push_back(ub); - values.push_back(dimInfo.getExtent()); - values.push_back(byteStride); - values.push_back(baseLb); - } else { - mlir::Value bound = builder.create( - loc, boundTy, lb, ub, dimInfo.getExtent(), byteStride, true, baseLb); - values.push_back(bound); - } - // Compute the stride for the next dimension. - byteStride = builder.create(loc, byteStride, - dimInfo.getExtent()); - } - return values; -} - -/// Generate the bounds operation from the descriptor information. -template -llvm::SmallVector -genBoundsOpsFromBox(fir::FirOpBuilder &builder, mlir::Location loc, - fir::ExtendedValue dataExv, - Fortran::lower::AddrAndBoundsInfo &info) { - llvm::SmallVector bounds; - mlir::Type idxTy = builder.getIndexType(); - mlir::Type boundTy = builder.getType(); - - assert(mlir::isa(info.boxType) && - "expect fir.box or fir.class"); - assert(fir::unwrapRefType(info.addr.getType()) == info.boxType && - "expected box type consistency"); - - if (info.isPresent) { - llvm::SmallVector resTypes; - constexpr unsigned nbValuesPerBound = 5; - for (unsigned dim = 0; dim < dataExv.rank() * nbValuesPerBound; ++dim) - resTypes.push_back(idxTy); - - mlir::Operation::result_range ifRes = - builder.genIfOp(loc, resTypes, info.isPresent, /*withElseRegion=*/true) - .genThen([&]() { - mlir::Value box = - !fir::isBoxAddress(info.addr.getType()) - ? info.addr - : builder.create(loc, info.addr); - llvm::SmallVector boundValues = - gatherBoundsOrBoundValues( - builder, loc, dataExv, box, - /*collectValuesOnly=*/true); - builder.create(loc, boundValues); - }) - .genElse([&] { - // Box is not present. Populate bound values with default values. - llvm::SmallVector boundValues; - mlir::Value zero = builder.createIntegerConstant(loc, idxTy, 0); - mlir::Value mOne = builder.createMinusOneInteger(loc, idxTy); - for (unsigned dim = 0; dim < dataExv.rank(); ++dim) { - boundValues.push_back(zero); // lb - boundValues.push_back(mOne); // ub - boundValues.push_back(zero); // extent - boundValues.push_back(zero); // byteStride - boundValues.push_back(zero); // baseLb - } - builder.create(loc, boundValues); - }) - .getResults(); - // Create the bound operations outside the if-then-else with the if op - // results. - for (unsigned i = 0; i < ifRes.size(); i += nbValuesPerBound) { - mlir::Value bound = builder.create( - loc, boundTy, ifRes[i], ifRes[i + 1], ifRes[i + 2], ifRes[i + 3], - true, ifRes[i + 4]); - bounds.push_back(bound); - } - } else { - mlir::Value box = !fir::isBoxAddress(info.addr.getType()) - ? info.addr - : builder.create(loc, info.addr); - bounds = gatherBoundsOrBoundValues(builder, loc, - dataExv, box); - } - return bounds; -} - -/// Generate bounds operation for base array without any subscripts -/// provided. -template -llvm::SmallVector -genBaseBoundsOps(fir::FirOpBuilder &builder, mlir::Location loc, - fir::ExtendedValue dataExv, bool isAssumedSize) { - mlir::Type idxTy = builder.getIndexType(); - mlir::Type boundTy = builder.getType(); - llvm::SmallVector bounds; - - if (dataExv.rank() == 0) - return bounds; - - mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1); - const unsigned rank = dataExv.rank(); - for (unsigned dim = 0; dim < rank; ++dim) { - mlir::Value baseLb = - fir::factory::readLowerBound(builder, loc, dataExv, dim, one); - mlir::Value zero = builder.createIntegerConstant(loc, idxTy, 0); - mlir::Value ub; - mlir::Value lb = zero; - mlir::Value ext = fir::factory::readExtent(builder, loc, dataExv, dim); - if (isAssumedSize && dim + 1 == rank) { - ext = zero; - ub = lb; - } else { - // ub = extent - 1 - ub = builder.create(loc, ext, one); - } - - mlir::Value bound = - builder.create(loc, boundTy, lb, ub, ext, one, false, baseLb); - bounds.push_back(bound); - } - return bounds; + return fir::factory::getDataOperandBaseAddr( + builder, converter.getSymbolAddress(sym), + Fortran::semantics::IsOptional(sym), loc); } namespace detail { @@ -878,7 +668,7 @@ genBoundsOps(fir::FirOpBuilder &builder, mlir::Location loc, Fortran::lower::StatementContext &stmtCtx, const std::vector &subscripts, std::stringstream &asFortran, fir::ExtendedValue &dataExv, - bool dataExvIsAssumedSize, AddrAndBoundsInfo &info, + bool dataExvIsAssumedSize, fir::factory::AddrAndBoundsInfo &info, bool treatIndexAsSection = false) { int dimension = 0; mlir::Type idxTy = builder.getIndexType(); @@ -1083,7 +873,7 @@ std::optional getRef(Expr &&expr) { } // namespace detail template -AddrAndBoundsInfo gatherDataOperandAddrAndBounds( +fir::factory::AddrAndBoundsInfo gatherDataOperandAddrAndBounds( Fortran::lower::AbstractConverter &converter, fir::FirOpBuilder &builder, semantics::SemanticsContext &semaCtx, Fortran::lower::StatementContext &stmtCtx, @@ -1093,7 +883,7 @@ AddrAndBoundsInfo gatherDataOperandAddrAndBounds( llvm::SmallVector &bounds, bool treatIndexAsSection = false) { using namespace Fortran; - AddrAndBoundsInfo info; + fir::factory::AddrAndBoundsInfo info; if (!maybeDesignator) { info = getDataOperandBaseAddr(converter, builder, symbol, operandLocation); @@ -1158,9 +948,9 @@ AddrAndBoundsInfo gatherDataOperandAddrAndBounds( info.addr = fir::getBase(compExv); info.rawInput = info.addr; if (mlir::isa(fir::unwrapRefType(info.addr.getType()))) - bounds = genBaseBoundsOps(builder, operandLocation, - compExv, - /*isAssumedSize=*/false); + bounds = fir::factory::genBaseBoundsOps( + builder, operandLocation, compExv, + /*isAssumedSize=*/false); asFortran << designator.AsFortran(); if (semantics::IsOptional(compRef->GetLastSymbol())) { @@ -1187,7 +977,7 @@ AddrAndBoundsInfo gatherDataOperandAddrAndBounds( info.addr = boxAddrOp.getVal(); info.boxType = info.addr.getType(); info.rawInput = info.addr; - bounds = genBoundsOpsFromBox( + bounds = fir::factory::genBoundsOpsFromBox( builder, operandLocation, compExv, info); } } else { @@ -1205,13 +995,13 @@ AddrAndBoundsInfo gatherDataOperandAddrAndBounds( if (mlir::isa( fir::unwrapRefType(info.addr.getType()))) { info.boxType = fir::unwrapRefType(info.addr.getType()); - bounds = genBoundsOpsFromBox( + bounds = fir::factory::genBoundsOpsFromBox( builder, operandLocation, dataExv, info); } bool dataExvIsAssumedSize = Fortran::semantics::IsAssumedSizeArray(symRef->get().GetUltimate()); if (mlir::isa(fir::unwrapRefType(info.addr.getType()))) - bounds = genBaseBoundsOps( + bounds = fir::factory::genBaseBoundsOps( builder, operandLocation, dataExv, dataExvIsAssumedSize); asFortran << symRef->get().name().ToString(); } else { // Unsupported @@ -1222,24 +1012,6 @@ AddrAndBoundsInfo gatherDataOperandAddrAndBounds( return info; } -template -llvm::SmallVector -genImplicitBoundsOps(fir::FirOpBuilder &builder, lower::AddrAndBoundsInfo &info, - fir::ExtendedValue dataExv, bool dataExvIsAssumedSize, - mlir::Location loc) { - llvm::SmallVector bounds; - - mlir::Value baseOp = info.rawInput; - if (mlir::isa(fir::unwrapRefType(baseOp.getType()))) - bounds = lower::genBoundsOpsFromBox(builder, loc, - dataExv, info); - if (mlir::isa(fir::unwrapRefType(baseOp.getType()))) { - bounds = lower::genBaseBoundsOps( - builder, loc, dataExv, dataExvIsAssumedSize); - } - - return bounds; -} } // namespace lower } // namespace Fortran diff --git a/flang/include/flang/Optimizer/Builder/DirectivesCommon.h b/flang/include/flang/Optimizer/Builder/DirectivesCommon.h new file mode 100644 index 0000000000000..443b0ee59007f --- /dev/null +++ b/flang/include/flang/Optimizer/Builder/DirectivesCommon.h @@ -0,0 +1,256 @@ +//===-- DirectivesCommon.h --------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/ +// +//===----------------------------------------------------------------------===// +/// +/// A location to place directive utilities shared across multiple lowering +/// and optimizer files, e.g. utilities shared in OpenMP and OpenACC. +//===----------------------------------------------------------------------===// + +#ifndef FORTRAN_OPTIMIZER_BUILDER_DIRECTIVESCOMMON_H_ +#define FORTRAN_OPTIMIZER_BUILDER_DIRECTIVESCOMMON_H_ + +#include "flang/Optimizer/Builder/BoxValue.h" +#include "flang/Optimizer/Builder/FIRBuilder.h" +#include "flang/Optimizer/Builder/Todo.h" +#include "flang/Optimizer/HLFIR/HLFIROps.h" +#include "mlir/Dialect/OpenACC/OpenACC.h" +#include "mlir/Dialect/OpenMP/OpenMPDialect.h" + +namespace fir::factory { + +/// Information gathered to generate bounds operation and data entry/exit +/// operations. +struct AddrAndBoundsInfo { + explicit AddrAndBoundsInfo() {} + explicit AddrAndBoundsInfo(mlir::Value addr, mlir::Value rawInput) + : addr(addr), rawInput(rawInput) {} + explicit AddrAndBoundsInfo(mlir::Value addr, mlir::Value rawInput, + mlir::Value isPresent) + : addr(addr), rawInput(rawInput), isPresent(isPresent) {} + explicit AddrAndBoundsInfo(mlir::Value addr, mlir::Value rawInput, + mlir::Value isPresent, mlir::Type boxType) + : addr(addr), rawInput(rawInput), isPresent(isPresent), boxType(boxType) { + } + mlir::Value addr = nullptr; + mlir::Value rawInput = nullptr; + mlir::Value isPresent = nullptr; + mlir::Type boxType = nullptr; + void dump(llvm::raw_ostream &os) { + os << "AddrAndBoundsInfo addr: " << addr << "\n"; + os << "AddrAndBoundsInfo rawInput: " << rawInput << "\n"; + os << "AddrAndBoundsInfo isPresent: " << isPresent << "\n"; + os << "AddrAndBoundsInfo boxType: " << boxType << "\n"; + } +}; + +inline AddrAndBoundsInfo getDataOperandBaseAddr(fir::FirOpBuilder &builder, + mlir::Value symAddr, + bool isOptional, + mlir::Location loc) { + mlir::Value rawInput = symAddr; + if (auto declareOp = + mlir::dyn_cast_or_null(symAddr.getDefiningOp())) { + symAddr = declareOp.getResults()[0]; + rawInput = declareOp.getResults()[1]; + } + + if (!symAddr) + llvm::report_fatal_error("could not retrieve symbol address"); + + mlir::Value isPresent; + if (isOptional) + isPresent = + builder.create(loc, builder.getI1Type(), rawInput); + + if (auto boxTy = mlir::dyn_cast( + fir::unwrapRefType(symAddr.getType()))) { + if (mlir::isa(boxTy.getEleTy())) + TODO(loc, "derived type"); + + // In case of a box reference, load it here to get the box value. + // This is preferrable because then the same box value can then be used for + // all address/dimension retrievals. For Fortran optional though, leave + // the load generation for later so it can be done in the appropriate + // if branches. + if (mlir::isa(symAddr.getType()) && !isOptional) { + mlir::Value addr = builder.create(loc, symAddr); + return AddrAndBoundsInfo(addr, rawInput, isPresent, boxTy); + } + + return AddrAndBoundsInfo(symAddr, rawInput, isPresent, boxTy); + } + return AddrAndBoundsInfo(symAddr, rawInput, isPresent); +} + +template +llvm::SmallVector +gatherBoundsOrBoundValues(fir::FirOpBuilder &builder, mlir::Location loc, + fir::ExtendedValue dataExv, mlir::Value box, + bool collectValuesOnly = false) { + assert(box && "box must exist"); + llvm::SmallVector values; + mlir::Value byteStride; + mlir::Type idxTy = builder.getIndexType(); + mlir::Type boundTy = builder.getType(); + mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1); + for (unsigned dim = 0; dim < dataExv.rank(); ++dim) { + mlir::Value d = builder.createIntegerConstant(loc, idxTy, dim); + mlir::Value baseLb = + fir::factory::readLowerBound(builder, loc, dataExv, dim, one); + auto dimInfo = + builder.create(loc, idxTy, idxTy, idxTy, box, d); + mlir::Value lb = builder.createIntegerConstant(loc, idxTy, 0); + mlir::Value ub = + builder.create(loc, dimInfo.getExtent(), one); + if (dim == 0) // First stride is the element size. + byteStride = dimInfo.getByteStride(); + if (collectValuesOnly) { + values.push_back(lb); + values.push_back(ub); + values.push_back(dimInfo.getExtent()); + values.push_back(byteStride); + values.push_back(baseLb); + } else { + mlir::Value bound = builder.create( + loc, boundTy, lb, ub, dimInfo.getExtent(), byteStride, true, baseLb); + values.push_back(bound); + } + // Compute the stride for the next dimension. + byteStride = builder.create(loc, byteStride, + dimInfo.getExtent()); + } + return values; +} + +/// Generate the bounds operation from the descriptor information. +template +llvm::SmallVector +genBoundsOpsFromBox(fir::FirOpBuilder &builder, mlir::Location loc, + fir::ExtendedValue dataExv, AddrAndBoundsInfo &info) { + llvm::SmallVector bounds; + mlir::Type idxTy = builder.getIndexType(); + mlir::Type boundTy = builder.getType(); + + assert(mlir::isa(info.boxType) && + "expect fir.box or fir.class"); + assert(fir::unwrapRefType(info.addr.getType()) == info.boxType && + "expected box type consistency"); + + if (info.isPresent) { + llvm::SmallVector resTypes; + constexpr unsigned nbValuesPerBound = 5; + for (unsigned dim = 0; dim < dataExv.rank() * nbValuesPerBound; ++dim) + resTypes.push_back(idxTy); + + mlir::Operation::result_range ifRes = + builder.genIfOp(loc, resTypes, info.isPresent, /*withElseRegion=*/true) + .genThen([&]() { + mlir::Value box = + !fir::isBoxAddress(info.addr.getType()) + ? info.addr + : builder.create(loc, info.addr); + llvm::SmallVector boundValues = + gatherBoundsOrBoundValues( + builder, loc, dataExv, box, + /*collectValuesOnly=*/true); + builder.create(loc, boundValues); + }) + .genElse([&] { + // Box is not present. Populate bound values with default values. + llvm::SmallVector boundValues; + mlir::Value zero = builder.createIntegerConstant(loc, idxTy, 0); + mlir::Value mOne = builder.createMinusOneInteger(loc, idxTy); + for (unsigned dim = 0; dim < dataExv.rank(); ++dim) { + boundValues.push_back(zero); // lb + boundValues.push_back(mOne); // ub + boundValues.push_back(zero); // extent + boundValues.push_back(zero); // byteStride + boundValues.push_back(zero); // baseLb + } + builder.create(loc, boundValues); + }) + .getResults(); + // Create the bound operations outside the if-then-else with the if op + // results. + for (unsigned i = 0; i < ifRes.size(); i += nbValuesPerBound) { + mlir::Value bound = builder.create( + loc, boundTy, ifRes[i], ifRes[i + 1], ifRes[i + 2], ifRes[i + 3], + true, ifRes[i + 4]); + bounds.push_back(bound); + } + } else { + mlir::Value box = !fir::isBoxAddress(info.addr.getType()) + ? info.addr + : builder.create(loc, info.addr); + bounds = gatherBoundsOrBoundValues(builder, loc, + dataExv, box); + } + return bounds; +} + +/// Generate bounds operation for base array without any subscripts +/// provided. +template +llvm::SmallVector +genBaseBoundsOps(fir::FirOpBuilder &builder, mlir::Location loc, + fir::ExtendedValue dataExv, bool isAssumedSize) { + mlir::Type idxTy = builder.getIndexType(); + mlir::Type boundTy = builder.getType(); + llvm::SmallVector bounds; + + if (dataExv.rank() == 0) + return bounds; + + mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1); + const unsigned rank = dataExv.rank(); + for (unsigned dim = 0; dim < rank; ++dim) { + mlir::Value baseLb = + fir::factory::readLowerBound(builder, loc, dataExv, dim, one); + mlir::Value zero = builder.createIntegerConstant(loc, idxTy, 0); + mlir::Value ub; + mlir::Value lb = zero; + mlir::Value ext = fir::factory::readExtent(builder, loc, dataExv, dim); + if (isAssumedSize && dim + 1 == rank) { + ext = zero; + ub = lb; + } else { + // ub = extent - 1 + ub = builder.create(loc, ext, one); + } + + mlir::Value bound = + builder.create(loc, boundTy, lb, ub, ext, one, false, baseLb); + bounds.push_back(bound); + } + return bounds; +} + +template +llvm::SmallVector +genImplicitBoundsOps(fir::FirOpBuilder &builder, AddrAndBoundsInfo &info, + fir::ExtendedValue dataExv, bool dataExvIsAssumedSize, + mlir::Location loc) { + llvm::SmallVector bounds; + + mlir::Value baseOp = info.rawInput; + if (mlir::isa(fir::unwrapRefType(baseOp.getType()))) + bounds = + genBoundsOpsFromBox(builder, loc, dataExv, info); + if (mlir::isa(fir::unwrapRefType(baseOp.getType()))) { + bounds = genBaseBoundsOps(builder, loc, dataExv, + dataExvIsAssumedSize); + } + + return bounds; +} + +} // namespace fir::factory +#endif // FORTRAN_OPTIMIZER_BUILDER_DIRECTIVESCOMMON_H_ diff --git a/flang/lib/Lower/OpenACC.cpp b/flang/lib/Lower/OpenACC.cpp index 86d8a549331fb..456c30264d068 100644 --- a/flang/lib/Lower/OpenACC.cpp +++ b/flang/lib/Lower/OpenACC.cpp @@ -352,7 +352,7 @@ genDataOperandOperations(const Fortran::parser::AccObjectList &objectList, Fortran::semantics::Symbol &symbol = getSymbolFromAccObject(accObject); Fortran::semantics::MaybeExpr designator = Fortran::common::visit( [&](auto &&s) { return ea.Analyze(s); }, accObject.u); - Fortran::lower::AddrAndBoundsInfo info = + fir::factory::AddrAndBoundsInfo info = Fortran::lower::gatherDataOperandAddrAndBounds< mlir::acc::DataBoundsOp, mlir::acc::DataBoundsType>( converter, builder, semanticsContext, stmtCtx, symbol, designator, @@ -392,7 +392,7 @@ static void genDeclareDataOperandOperations( Fortran::semantics::Symbol &symbol = getSymbolFromAccObject(accObject); Fortran::semantics::MaybeExpr designator = Fortran::common::visit( [&](auto &&s) { return ea.Analyze(s); }, accObject.u); - Fortran::lower::AddrAndBoundsInfo info = + fir::factory::AddrAndBoundsInfo info = Fortran::lower::gatherDataOperandAddrAndBounds< mlir::acc::DataBoundsOp, mlir::acc::DataBoundsType>( converter, builder, semanticsContext, stmtCtx, symbol, designator, @@ -855,7 +855,7 @@ genPrivatizations(const Fortran::parser::AccObjectList &objectList, Fortran::semantics::Symbol &symbol = getSymbolFromAccObject(accObject); Fortran::semantics::MaybeExpr designator = Fortran::common::visit( [&](auto &&s) { return ea.Analyze(s); }, accObject.u); - Fortran::lower::AddrAndBoundsInfo info = + fir::factory::AddrAndBoundsInfo info = Fortran::lower::gatherDataOperandAddrAndBounds< mlir::acc::DataBoundsOp, mlir::acc::DataBoundsType>( converter, builder, semanticsContext, stmtCtx, symbol, designator, @@ -1436,7 +1436,7 @@ genReductions(const Fortran::parser::AccObjectListWithReduction &objectList, Fortran::semantics::Symbol &symbol = getSymbolFromAccObject(accObject); Fortran::semantics::MaybeExpr designator = Fortran::common::visit( [&](auto &&s) { return ea.Analyze(s); }, accObject.u); - Fortran::lower::AddrAndBoundsInfo info = + fir::factory::AddrAndBoundsInfo info = Fortran::lower::gatherDataOperandAddrAndBounds< mlir::acc::DataBoundsOp, mlir::acc::DataBoundsType>( converter, builder, semanticsContext, stmtCtx, symbol, designator, diff --git a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp index fb8e007c7af57..299d9d438f115 100644 --- a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp +++ b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp @@ -949,7 +949,7 @@ void ClauseProcessor::processMapObjects( std::stringstream asFortran; std::optional parentObj; - lower::AddrAndBoundsInfo info = + fir::factory::AddrAndBoundsInfo info = lower::gatherDataOperandAddrAndBounds( converter, firOpBuilder, semaCtx, stmtCtx, *object.sym(), diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp index 39b4de919c8ba..1434bcd6330e0 100644 --- a/flang/lib/Lower/OpenMP/OpenMP.cpp +++ b/flang/lib/Lower/OpenMP/OpenMP.cpp @@ -1346,11 +1346,12 @@ static void genBodyOfTargetOp( firOpBuilder.createTemporary(val.getLoc(), val.getType()); firOpBuilder.createStoreWithConvert(copyVal.getLoc(), val, copyVal); - lower::AddrAndBoundsInfo info = lower::getDataOperandBaseAddr( - firOpBuilder, val, /*isOptional=*/false, val.getLoc()); + fir::factory::AddrAndBoundsInfo info = + fir::factory::getDataOperandBaseAddr( + firOpBuilder, val, /*isOptional=*/false, val.getLoc()); llvm::SmallVector bounds = - Fortran::lower::genImplicitBoundsOps( + fir::factory::genImplicitBoundsOps( firOpBuilder, info, hlfir::translateToExtendedValue(val.getLoc(), firOpBuilder, hlfir::Entity{val}) @@ -2188,11 +2189,12 @@ genTargetOp(lower::AbstractConverter &converter, lower::SymMap &symTable, fir::ExtendedValue dataExv = converter.getSymbolExtendedValue(sym); name << sym.name().ToString(); - lower::AddrAndBoundsInfo info = getDataOperandBaseAddr( - converter, firOpBuilder, sym, converter.getCurrentLocation()); + fir::factory::AddrAndBoundsInfo info = + Fortran::lower::getDataOperandBaseAddr( + converter, firOpBuilder, sym, converter.getCurrentLocation()); llvm::SmallVector bounds = - lower::genImplicitBoundsOps( + fir::factory::genImplicitBoundsOps( firOpBuilder, info, dataExv, semantics::IsAssumedSizeArray(sym.GetUltimate()), converter.getCurrentLocation()); @@ -2511,7 +2513,7 @@ static void genStandaloneDo(lower::AbstractConverter &converter, DataSharingProcessor dsp(converter, semaCtx, item->clauses, eval, /*shouldCollectPreDeterminedSymbols=*/true, - enableDelayedPrivatization, symTable); + enableDelayedPrivatizationStaging, symTable); dsp.processStep1(&wsloopClauseOps); mlir::omp::LoopNestOperands loopNestClauseOps; diff --git a/flang/lib/Lower/OpenMP/Utils.cpp b/flang/lib/Lower/OpenMP/Utils.cpp index 9971dc8e0b001..35722fa7d1b12 100644 --- a/flang/lib/Lower/OpenMP/Utils.cpp +++ b/flang/lib/Lower/OpenMP/Utils.cpp @@ -310,8 +310,9 @@ mlir::Value createParentSymAndGenIntermediateMaps( }; // Generate the access to the original parent base address. - lower::AddrAndBoundsInfo parentBaseAddr = lower::getDataOperandBaseAddr( - converter, firOpBuilder, *objectList[0].sym(), clauseLocation); + fir::factory::AddrAndBoundsInfo parentBaseAddr = + lower::getDataOperandBaseAddr(converter, firOpBuilder, + *objectList[0].sym(), clauseLocation); mlir::Value curValue = parentBaseAddr.addr; // Iterate over all objects in the objectList, this should consist of all @@ -560,7 +561,7 @@ void insertChildMapInfoIntoParent( // Create parent to emplace and bind members llvm::SmallVector bounds; std::stringstream asFortran; - lower::AddrAndBoundsInfo info = + fir::factory::AddrAndBoundsInfo info = lower::gatherDataOperandAddrAndBounds( converter, firOpBuilder, semaCtx, converter.getFctCtx(), diff --git a/flang/lib/Optimizer/CodeGen/CMakeLists.txt b/flang/lib/Optimizer/CodeGen/CMakeLists.txt index 81c8a68b95367..553c20bb85d38 100644 --- a/flang/lib/Optimizer/CodeGen/CMakeLists.txt +++ b/flang/lib/Optimizer/CodeGen/CMakeLists.txt @@ -11,11 +11,13 @@ add_flang_library(FIRCodeGen TypeConverter.cpp DEPENDS + CUFAttrs FIRDialect FIROptCodeGenPassIncGen CGOpsIncGen LINK_LIBS + CUFAttrs FIRAnalysis FIRBuilder FIRDialect diff --git a/flang/lib/Optimizer/CodeGen/CodeGen.cpp b/flang/lib/Optimizer/CodeGen/CodeGen.cpp index 5ba93fefab3f9..43c0e2686a8c3 100644 --- a/flang/lib/Optimizer/CodeGen/CodeGen.cpp +++ b/flang/lib/Optimizer/CodeGen/CodeGen.cpp @@ -1725,15 +1725,35 @@ struct EmboxOpConversion : public EmboxCommonConversion { } }; -static bool isDeviceAllocation(mlir::Value val) { +static bool isDeviceAllocation(mlir::Value val, mlir::Value adaptorVal) { if (auto loadOp = mlir::dyn_cast_or_null(val.getDefiningOp())) - return isDeviceAllocation(loadOp.getMemref()); + return isDeviceAllocation(loadOp.getMemref(), {}); if (auto boxAddrOp = mlir::dyn_cast_or_null(val.getDefiningOp())) - return isDeviceAllocation(boxAddrOp.getVal()); + return isDeviceAllocation(boxAddrOp.getVal(), {}); if (auto convertOp = mlir::dyn_cast_or_null(val.getDefiningOp())) - return isDeviceAllocation(convertOp.getValue()); + return isDeviceAllocation(convertOp.getValue(), {}); + if (!val.getDefiningOp() && adaptorVal) { + if (auto blockArg = llvm::cast(adaptorVal)) { + if (blockArg.getOwner() && blockArg.getOwner()->getParentOp() && + blockArg.getOwner()->isEntryBlock()) { + if (auto func = mlir::dyn_cast_or_null( + *blockArg.getOwner()->getParentOp())) { + auto argAttrs = func.getArgAttrs(blockArg.getArgNumber()); + for (auto attr : argAttrs) { + if (attr.getName().getValue().ends_with(cuf::getDataAttrName())) { + auto dataAttr = + mlir::dyn_cast(attr.getValue()); + if (dataAttr.getValue() != cuf::DataAttribute::Pinned && + dataAttr.getValue() != cuf::DataAttribute::Unified) + return true; + } + } + } + } + } + } if (auto callOp = mlir::dyn_cast_or_null(val.getDefiningOp())) if (callOp.getCallee() && (callOp.getCallee().value().getRootReference().getValue().starts_with( @@ -1928,7 +1948,8 @@ struct XEmboxOpConversion : public EmboxCommonConversion { if (fir::isDerivedTypeWithLenParams(boxTy)) TODO(loc, "fir.embox codegen of derived with length parameters"); mlir::Value result = placeInMemoryIfNotGlobalInit( - rewriter, loc, boxTy, dest, isDeviceAllocation(xbox.getMemref())); + rewriter, loc, boxTy, dest, + isDeviceAllocation(xbox.getMemref(), adaptor.getMemref())); rewriter.replaceOp(xbox, result); return mlir::success(); } @@ -2052,9 +2073,9 @@ struct XReboxOpConversion : public EmboxCommonConversion { dest = insertStride(rewriter, loc, dest, dim, std::get<1>(iter.value())); } dest = insertBaseAddress(rewriter, loc, dest, base); - mlir::Value result = - placeInMemoryIfNotGlobalInit(rewriter, rebox.getLoc(), destBoxTy, dest, - isDeviceAllocation(rebox.getBox())); + mlir::Value result = placeInMemoryIfNotGlobalInit( + rewriter, rebox.getLoc(), destBoxTy, dest, + isDeviceAllocation(rebox.getBox(), rebox.getBox())); rewriter.replaceOp(rebox, result); return mlir::success(); } diff --git a/flang/lib/Optimizer/OpenACC/FIROpenACCTypeInterfaces.cpp b/flang/lib/Optimizer/OpenACC/FIROpenACCTypeInterfaces.cpp index e6a484923c706..94ab31de1763d 100644 --- a/flang/lib/Optimizer/OpenACC/FIROpenACCTypeInterfaces.cpp +++ b/flang/lib/Optimizer/OpenACC/FIROpenACCTypeInterfaces.cpp @@ -11,8 +11,8 @@ //===----------------------------------------------------------------------===// #include "flang/Optimizer/OpenACC/FIROpenACCTypeInterfaces.h" -#include "flang/Lower/DirectivesCommon.h" #include "flang/Optimizer/Builder/BoxValue.h" +#include "flang/Optimizer/Builder/DirectivesCommon.h" #include "flang/Optimizer/Builder/FIRBuilder.h" #include "flang/Optimizer/Builder/HLFIRTools.h" #include "flang/Optimizer/Dialect/FIROps.h" @@ -180,10 +180,10 @@ OpenACCMappableModel::generateAccBounds( } // TODO: Handle Fortran optional. const mlir::Value isPresent; - Fortran::lower::AddrAndBoundsInfo info(box, boxRef, isPresent, - box.getType()); - return Fortran::lower::genBoundsOpsFromBox( + fir::factory::AddrAndBoundsInfo info(box, boxRef, isPresent, + box.getType()); + return fir::factory::genBoundsOpsFromBox( firBuilder, loc, exv, info); } assert(false && "array with unknown dimension expected to have descriptor"); @@ -200,8 +200,8 @@ OpenACCMappableModel::generateAccBounds( auto res = hlfir::translateToExtendedValue(loc, firBuilder, hlfir::Entity(valToCheck)); fir::ExtendedValue exv = res.first; - return Fortran::lower::genBaseBoundsOps( + return fir::factory::genBaseBoundsOps( firBuilder, loc, exv, /*isAssumedSize=*/isAssumedSize); } diff --git a/flang/lib/Optimizer/OpenMP/CMakeLists.txt b/flang/lib/Optimizer/OpenMP/CMakeLists.txt index 9fe2d3947c26d..c8509ccc7fea5 100644 --- a/flang/lib/Optimizer/OpenMP/CMakeLists.txt +++ b/flang/lib/Optimizer/OpenMP/CMakeLists.txt @@ -22,7 +22,6 @@ add_flang_library(FlangOpenMPTransforms FIRDialectSupport FIRSupport FortranCommon - FortranEvaluate HLFIRDialect MLIR_LIBS diff --git a/flang/lib/Optimizer/OpenMP/GenericLoopConversion.cpp b/flang/lib/Optimizer/OpenMP/GenericLoopConversion.cpp index c3c1f3b2848b8..555601c5e92df 100644 --- a/flang/lib/Optimizer/OpenMP/GenericLoopConversion.cpp +++ b/flang/lib/Optimizer/OpenMP/GenericLoopConversion.cpp @@ -30,19 +30,39 @@ class GenericLoopConversionPattern : public mlir::OpConversionPattern { public: enum class GenericLoopCombinedInfo { - None, + Standalone, TargetTeamsLoop, TargetParallelLoop }; using mlir::OpConversionPattern::OpConversionPattern; + explicit GenericLoopConversionPattern(mlir::MLIRContext *ctx) + : mlir::OpConversionPattern{ctx} { + // Enable rewrite recursion to make sure nested `loop` directives are + // handled. + this->setHasBoundedRewriteRecursion(true); + } + mlir::LogicalResult matchAndRewrite(mlir::omp::LoopOp loopOp, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const override { assert(mlir::succeeded(checkLoopConversionSupportStatus(loopOp))); - rewriteToDistributeParallelDo(loopOp, rewriter); + GenericLoopCombinedInfo combinedInfo = findGenericLoopCombineInfo(loopOp); + + switch (combinedInfo) { + case GenericLoopCombinedInfo::Standalone: + rewriteToSimdLoop(loopOp, rewriter); + break; + case GenericLoopCombinedInfo::TargetParallelLoop: + llvm_unreachable("not yet implemented: `parallel loop` direcitve"); + break; + case GenericLoopCombinedInfo::TargetTeamsLoop: + rewriteToDistributeParallelDo(loopOp, rewriter); + break; + } + rewriter.eraseOp(loopOp); return mlir::success(); } @@ -52,9 +72,8 @@ class GenericLoopConversionPattern GenericLoopCombinedInfo combinedInfo = findGenericLoopCombineInfo(loopOp); switch (combinedInfo) { - case GenericLoopCombinedInfo::None: - return loopOp.emitError( - "not yet implemented: Standalone `omp loop` directive"); + case GenericLoopCombinedInfo::Standalone: + break; case GenericLoopCombinedInfo::TargetParallelLoop: return loopOp.emitError( "not yet implemented: Combined `omp target parallel loop` directive"); @@ -86,7 +105,7 @@ class GenericLoopConversionPattern static GenericLoopCombinedInfo findGenericLoopCombineInfo(mlir::omp::LoopOp loopOp) { mlir::Operation *parentOp = loopOp->getParentOp(); - GenericLoopCombinedInfo result = GenericLoopCombinedInfo::None; + GenericLoopCombinedInfo result = GenericLoopCombinedInfo::Standalone; if (auto teamsOp = mlir::dyn_cast_if_present(parentOp)) if (mlir::isa_and_present(teamsOp->getParentOp())) @@ -100,6 +119,62 @@ class GenericLoopConversionPattern return result; } + /// Rewrites standalone `loop` directives to equivalent `simd` constructs. + /// The reasoning behind this decision is that according to the spec (version + /// 5.2, section 11.7.1): + /// + /// "If the bind clause is not specified on a construct for which it may be + /// specified and the construct is closely nested inside a teams or parallel + /// construct, the effect is as if binding is teams or parallel. If none of + /// those conditions hold, the binding region is not defined." + /// + /// which means that standalone `loop` directives have undefined binding + /// region. Moreover, the spec says (in the next paragraph): + /// + /// "The specified binding region determines the binding thread set. + /// Specifically, if the binding region is a teams region, then the binding + /// thread set is the set of initial threads that are executing that region + /// while if the binding region is a parallel region, then the binding thread + /// set is the team of threads that are executing that region. If the binding + /// region is not defined, then the binding thread set is the encountering + /// thread." + /// + /// which means that the binding thread set for a standalone `loop` directive + /// is only the encountering thread. + /// + /// Since the encountering thread is the binding thread (set) for a + /// standalone `loop` directive, the best we can do in such case is to "simd" + /// the directive. + void rewriteToSimdLoop(mlir::omp::LoopOp loopOp, + mlir::ConversionPatternRewriter &rewriter) const { + loopOp.emitWarning("Detected standalone OpenMP `loop` directive, the " + "associated loop will be rewritten to `simd`."); + mlir::omp::SimdOperands simdClauseOps; + simdClauseOps.privateVars = loopOp.getPrivateVars(); + + auto privateSyms = loopOp.getPrivateSyms(); + if (privateSyms) + simdClauseOps.privateSyms.assign(privateSyms->begin(), + privateSyms->end()); + + Fortran::common::openmp::EntryBlockArgs simdArgs; + simdArgs.priv.vars = simdClauseOps.privateVars; + + auto simdOp = + rewriter.create(loopOp.getLoc(), simdClauseOps); + mlir::Block *simdBlock = + genEntryBlock(rewriter, simdArgs, simdOp.getRegion()); + + mlir::IRMapping mapper; + mlir::Block &loopBlock = *loopOp.getRegion().begin(); + + for (auto [loopOpArg, simdopArg] : + llvm::zip_equal(loopBlock.getArguments(), simdBlock->getArguments())) + mapper.map(loopOpArg, simdopArg); + + rewriter.clone(*loopOp.begin(), mapper); + } + void rewriteToDistributeParallelDo( mlir::omp::LoopOp loopOp, mlir::ConversionPatternRewriter &rewriter) const { diff --git a/flang/lib/Optimizer/OpenMP/MapInfoFinalization.cpp b/flang/lib/Optimizer/OpenMP/MapInfoFinalization.cpp index c63d2f4531a6f..98e325c307d97 100644 --- a/flang/lib/Optimizer/OpenMP/MapInfoFinalization.cpp +++ b/flang/lib/Optimizer/OpenMP/MapInfoFinalization.cpp @@ -24,7 +24,7 @@ /// indirectly via a parent object. //===----------------------------------------------------------------------===// -#include "flang/Lower/DirectivesCommon.h" +#include "flang/Optimizer/Builder/DirectivesCommon.h" #include "flang/Optimizer/Builder/FIRBuilder.h" #include "flang/Optimizer/Builder/HLFIRTools.h" #include "flang/Optimizer/Dialect/FIRType.h" @@ -598,12 +598,12 @@ class MapInfoFinalizationPass auto fieldCoord = builder.create( op.getLoc(), builder.getRefType(memTy), op.getVarPtr(), fieldIdxVal); - Fortran::lower::AddrAndBoundsInfo info = - Fortran::lower::getDataOperandBaseAddr( + fir::factory::AddrAndBoundsInfo info = + fir::factory::getDataOperandBaseAddr( builder, fieldCoord, /*isOptional=*/false, op.getLoc()); llvm::SmallVector bounds = - Fortran::lower::genImplicitBoundsOps( + fir::factory::genImplicitBoundsOps( builder, info, hlfir::translateToExtendedValue(op.getLoc(), builder, hlfir::Entity{fieldCoord}) diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp index f3c2a5bf094d0..aee0357333159 100644 --- a/flang/lib/Semantics/resolve-names.cpp +++ b/flang/lib/Semantics/resolve-names.cpp @@ -736,6 +736,8 @@ class ScopeHandler : public ImplicitRulesVisitor { std::vector *> equivalenceSets; // Names of all common block objects in the scope std::set commonBlockObjects; + // Names of all names that show in a declare target declaration + std::set declareTargetNames; // Info about SAVE statements and attributes in current scope struct { std::optional saveAll; // "SAVE" without entity list @@ -1223,6 +1225,7 @@ class DeclarationVisitor : public ArraySpecVisitor, const parser::Name *FindComponent(const parser::Name *, const parser::Name &); void Initialization(const parser::Name &, const parser::Initialization &, bool inComponentDecl); + bool FindAndMarkDeclareTargetSymbol(const parser::Name &); bool PassesLocalityChecks( const parser::Name &name, Symbol &symbol, Symbol::Flag flag); bool CheckForHostAssociatedImplicit(const parser::Name &); @@ -1524,7 +1527,47 @@ class OmpVisitor : public virtual DeclarationVisitor { return true; } void Post(const parser::OpenMPThreadprivate &) { SkipImplicitTyping(false); } - bool Pre(const parser::OpenMPDeclareTargetConstruct &) { + bool Pre(const parser::OpenMPDeclareTargetConstruct &x) { + const auto &spec{std::get(x.t)}; + auto populateDeclareTargetNames{ + [this](const parser::OmpObjectList &objectList) { + for (const auto &ompObject : objectList.v) { + common::visit( + common::visitors{ + [&](const parser::Designator &designator) { + if (const auto *name{ + semantics::getDesignatorNameIfDataRef( + designator)}) { + specPartState_.declareTargetNames.insert(name->source); + } + }, + [&](const parser::Name &name) { + specPartState_.declareTargetNames.insert(name.source); + }, + }, + ompObject.u); + } + }}; + + if (const auto *objectList{parser::Unwrap(spec.u)}) { + populateDeclareTargetNames(*objectList); + } else if (const auto *clauseList{ + parser::Unwrap(spec.u)}) { + for (const auto &clause : clauseList->v) { + if (const auto *toClause{ + std::get_if(&clause.u)}) { + populateDeclareTargetNames( + std::get(toClause->v.t)); + } else if (const auto *linkClause{ + std::get_if(&clause.u)}) { + populateDeclareTargetNames(linkClause->v); + } else if (const auto *enterClause{ + std::get_if(&clause.u)}) { + populateDeclareTargetNames(enterClause->v); + } + } + } + SkipImplicitTyping(true); return true; } @@ -8126,7 +8169,12 @@ const parser::Name *DeclarationVisitor::ResolveDataRef( // If implicit types are allowed, ensure name is in the symbol table. // Otherwise, report an error if it hasn't been declared. const parser::Name *DeclarationVisitor::ResolveName(const parser::Name &name) { - FindSymbol(name); + if (!FindSymbol(name)) { + if (FindAndMarkDeclareTargetSymbol(name)) { + return &name; + } + } + if (CheckForHostAssociatedImplicit(name)) { NotePossibleBadForwardRef(name); return &name; @@ -8313,6 +8361,47 @@ const parser::Name *DeclarationVisitor::FindComponent( return nullptr; } +bool DeclarationVisitor::FindAndMarkDeclareTargetSymbol( + const parser::Name &name) { + if (!specPartState_.declareTargetNames.empty()) { + if (specPartState_.declareTargetNames.count(name.source)) { + if (!currScope().IsTopLevel()) { + // Search preceding scopes until we find a matching symbol or run out + // of scopes to search, we skip the current scope as it's already been + // designated as implicit here. + for (auto *scope = &currScope().parent();; scope = &scope->parent()) { + if (Symbol * symbol{scope->FindSymbol(name.source)}) { + if (symbol->test(Symbol::Flag::Subroutine) || + symbol->test(Symbol::Flag::Function)) { + const auto [sym, success]{currScope().try_emplace( + symbol->name(), Attrs{}, HostAssocDetails{*symbol})}; + assert(success && + "FindAndMarkDeclareTargetSymbol could not emplace new " + "subroutine/function symbol"); + name.symbol = &*sym->second; + symbol->test(Symbol::Flag::Subroutine) + ? name.symbol->set(Symbol::Flag::Subroutine) + : name.symbol->set(Symbol::Flag::Function); + return true; + } + // if we find a symbol that is not a function or subroutine, we + // currently escape without doing anything. + break; + } + + // This is our loop exit condition, as parent() has an inbuilt assert + // if you call it on a top level scope, rather than returning a null + // value. + if (scope->IsTopLevel()) { + return false; + } + } + } + } + } + return false; +} + void DeclarationVisitor::Initialization(const parser::Name &name, const parser::Initialization &init, bool inComponentDecl) { // Traversal of the initializer was deferred to here so that the diff --git a/flang/test/Fir/CUDA/cuda-code-gen.mlir b/flang/test/Fir/CUDA/cuda-code-gen.mlir index 3ad28fa7bd517..7ac89836a3ff1 100644 --- a/flang/test/Fir/CUDA/cuda-code-gen.mlir +++ b/flang/test/Fir/CUDA/cuda-code-gen.mlir @@ -170,3 +170,20 @@ module attributes {dlti.dl_spec = #dlti.dl_spec = dense<32> : vec // CHECK-LABEL: llvm.func @_QQmain() // CHECK-COUNT-3: llvm.call @_FortranACUFAllocDescriptor + +// ----- + +module attributes {dlti.dl_spec = #dlti.dl_spec = dense<32> : vector<4xi64>, f128 = dense<128> : vector<2xi64>, f64 = dense<64> : vector<2xi64>, f16 = dense<16> : vector<2xi64>, i32 = dense<32> : vector<2xi64>, i64 = dense<64> : vector<2xi64>, !llvm.ptr<272> = dense<64> : vector<4xi64>, !llvm.ptr<271> = dense<32> : vector<4xi64>, f80 = dense<128> : vector<2xi64>, i128 = dense<128> : vector<2xi64>, i16 = dense<16> : vector<2xi64>, i8 = dense<8> : vector<2xi64>, !llvm.ptr = dense<64> : vector<4xi64>, i1 = dense<8> : vector<2xi64>, "dlti.endianness" = "little", "dlti.stack_alignment" = 128 : i64>, fir.defaultkind = "a1c4d8i4l4r4", fir.kindmap = "", gpu.container_module, llvm.data_layout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128", llvm.ident = "flang version 20.0.0 (git@github.com:clementval/llvm-project.git efc2415bcce8e8a9e73e77aa122c8aba1c1fbbd2)", llvm.target_triple = "x86_64-unknown-linux-gnu"} { + func.func @_QPouter(%arg0: !fir.ref> {cuf.data_attr = #cuf.cuda, fir.bindc_name = "a"}) { + %c0_i32 = arith.constant 0 : i32 + %c100 = arith.constant 100 : index + %0 = fir.alloca tuple>> + %1 = fir.coordinate_of %0, %c0_i32 : (!fir.ref>>>, i32) -> !fir.ref>> + %2 = fircg.ext_embox %arg0(%c100, %c100) : (!fir.ref>, index, index) -> !fir.box> + fir.store %2 to %1 : !fir.ref>> + return + } +} + +// CHECK-LABEL: llvm.func @_QPouter +// CHECK: _FortranACUFAllocDescriptor diff --git a/flang/test/HLFIR/unroll-loops.fir b/flang/test/HLFIR/unroll-loops.fir index d8f820263ffd0..4494cfa570dd7 100644 --- a/flang/test/HLFIR/unroll-loops.fir +++ b/flang/test/HLFIR/unroll-loops.fir @@ -4,7 +4,7 @@ // RUN: %flang_fc1 -emit-llvm -O1 -mllvm -force-vector-width=2 -o- %s | FileCheck %s --check-prefixes=CHECK,NO-UNROLL // FIXME: https://github.com/llvm/llvm-project/issues/123668 -// XFAIL: powerpc64-target-arch +// XFAIL: target=powerpc64{{.*}} // CHECK-LABEL: @unroll // CHECK-SAME: (ptr nocapture writeonly %[[ARG0:.*]]) diff --git a/flang/test/Integration/unroll-loops.f90 b/flang/test/Integration/unroll-loops.f90 index 4a356c1ec5e9a..4b4a394502881 100644 --- a/flang/test/Integration/unroll-loops.f90 +++ b/flang/test/Integration/unroll-loops.f90 @@ -4,7 +4,7 @@ ! RUN: %flang_fc1 -emit-llvm -O1 -mllvm -force-vector-width=2 -o- %s | FileCheck %s --check-prefixes=CHECK,NO-UNROLL ! FIXME: https://github.com/llvm/llvm-project/issues/123668 -! XFAIL: powerpc64-target-arch +! XFAIL: target=powerpc64{{.*}} ! CHECK-LABEL: @unroll ! CHECK-SAME: (ptr nocapture writeonly %[[ARG0:.*]]) diff --git a/flang/test/Lower/OpenMP/DelayedPrivatization/wsloop.f90 b/flang/test/Lower/OpenMP/DelayedPrivatization/wsloop.f90 index c98850b8000d3..66fd120085c78 100644 --- a/flang/test/Lower/OpenMP/DelayedPrivatization/wsloop.f90 +++ b/flang/test/Lower/OpenMP/DelayedPrivatization/wsloop.f90 @@ -1,6 +1,6 @@ -! RUN: %flang_fc1 -emit-hlfir -fopenmp \ +! RUN: %flang_fc1 -emit-hlfir -fopenmp -mmlir --openmp-enable-delayed-privatization-staging \ ! RUN: -o - %s 2>&1 | FileCheck %s -! RUN: bbc -emit-hlfir -fopenmp -o - %s 2>&1 \ +! RUN: bbc -emit-hlfir -fopenmp --openmp-enable-delayed-privatization-staging -o - %s 2>&1 \ ! RUN: | FileCheck %s subroutine wsloop_private diff --git a/flang/test/Lower/OpenMP/Todo/allocate-clause-allocator.f90 b/flang/test/Lower/OpenMP/Todo/allocate-clause-allocator.f90 index 90158a61f7503..45b3aa8ee77f9 100644 --- a/flang/test/Lower/OpenMP/Todo/allocate-clause-allocator.f90 +++ b/flang/test/Lower/OpenMP/Todo/allocate-clause-allocator.f90 @@ -1,11 +1,10 @@ ! REQUIRES: openmp_runtime -! RUN: %not_todo_cmd %flang_fc1 -emit-llvm -fopenmp -fopenmp-version=51 -o - %s 2>&1 | FileCheck %s +! RUN: %not_todo_cmd %flang_fc1 -emit-llvm %openmp_flags -fopenmp-version=51 -o - %s 2>&1 | FileCheck %s ! CHECK: not yet implemented: Unhandled clause allocate in omp.parallel ! CHECK: LLVM Translation failed for operation: omp.parallel program p - !use omp_lib - integer(8),parameter::omp_default_mem_alloc=1_8 + use omp_lib integer :: x integer :: a integer :: i diff --git a/flang/test/Lower/OpenMP/Todo/omp-default-clause-inner-loop.f90 b/flang/test/Lower/OpenMP/Todo/omp-default-clause-inner-loop.f90 index 10879c53dc0c5..77a1304f39a48 100644 --- a/flang/test/Lower/OpenMP/Todo/omp-default-clause-inner-loop.f90 +++ b/flang/test/Lower/OpenMP/Todo/omp-default-clause-inner-loop.f90 @@ -9,10 +9,11 @@ ! The string "EXPECTED" denotes the expected FIR ! CHECK: omp.parallel private(@{{.*}} %{{.*}} -> %[[PRIVATE_Y:.*]], @{{.*}} %{{.*}} -> %[[PRIVATE_Y:.*]] : !fir.ref, !fir.ref) { +! CHECK: %[[TEMP:.*]] = fir.alloca i32 {bindc_name = "x", pinned, {{.*}}} ! CHECK: %[[const_1:.*]] = arith.constant 1 : i32 ! CHECK: %[[const_2:.*]] = arith.constant 10 : i32 ! CHECK: %[[const_3:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}} -> %[[TEMP:.*]] : !fir.ref) { +! CHECK: omp.wsloop { ! CHECK-NEXT: omp.loop_nest (%[[ARG:.*]]) : i32 = (%[[const_1]]) to (%[[const_2]]) inclusive step (%[[const_3]]) { ! CHECK: fir.store %[[ARG]] to %[[TEMP]] : !fir.ref ! EXPECTED: %[[temp_1:.*]] = fir.load %[[PRIVATE_Z]] : !fir.ref diff --git a/flang/test/Lower/OpenMP/associate.f90 b/flang/test/Lower/OpenMP/associate.f90 index d497b4ade782e..4964890a6842c 100644 --- a/flang/test/Lower/OpenMP/associate.f90 +++ b/flang/test/Lower/OpenMP/associate.f90 @@ -6,12 +6,12 @@ !CHECK: omp.parallel { !CHECK-NOT: hlfir.declare {{.*}} {uniq_name = "_QFtest_parallel_assocEa"} !CHECK-NOT: hlfir.declare {{.*}} {uniq_name = "_QFtest_parallel_assocEb"} -!CHECK: omp.wsloop private({{.*}}) { +!CHECK: omp.wsloop { !CHECK: } !CHECK: } !CHECK: omp.parallel {{.*}} { !CHECK-NOT: hlfir.declare {{.*}} {uniq_name = "_QFtest_parallel_assocEb"} -!CHECK: omp.wsloop private({{.*}}) { +!CHECK: omp.wsloop { !CHECK: } !CHECK: } subroutine test_parallel_assoc() diff --git a/flang/test/Lower/OpenMP/copyin.f90 b/flang/test/Lower/OpenMP/copyin.f90 index 5ad45f1f5ba6f..9e9ccf8e3d914 100644 --- a/flang/test/Lower/OpenMP/copyin.f90 +++ b/flang/test/Lower/OpenMP/copyin.f90 @@ -154,13 +154,14 @@ subroutine copyin_derived_type() ! CHECK: omp.barrier +! CHECK: %[[VAL_6:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_7:.*]]:2 = hlfir.declare %[[VAL_6]] {uniq_name = "_QFcombined_parallel_worksharing_loopEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_11:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_12:.*]] = fir.load %[[VAL_9]]#0 : !fir.ref ! CHECK: %[[VAL_13:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}} -> %[[VAL_6:.*]] : !fir.ref) { +! CHECK: omp.wsloop { ! CHECK-NEXT: omp.loop_nest (%[[VAL_14:.*]]) : i32 = (%[[VAL_11]]) to (%[[VAL_12]]) inclusive step (%[[VAL_13]]) { -! CHECK: %[[VAL_7:.*]]:2 = hlfir.declare %[[VAL_6]] {uniq_name = "_QFcombined_parallel_worksharing_loopEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: fir.store %[[VAL_14]] to %[[VAL_7]]#1 : !fir.ref ! CHECK: fir.call @_QPsub4(%[[VAL_9]]#1) fastmath : (!fir.ref) -> () ! CHECK: omp.yield @@ -320,12 +321,15 @@ subroutine common_1() ! CHECK: %[[VAL_33:.*]] = fir.load %[[VAL_18]]#0 : !fir.ref ! CHECK: hlfir.assign %[[VAL_33]] to %[[VAL_31]]#0 : i32, !fir.ref ! CHECK: omp.barrier + +! CHECK: %[[VAL_19:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_20:.*]]:2 = hlfir.declare %[[VAL_19]] {uniq_name = "_QFcommon_2Ei"} : (!fir.ref) -> (!fir.ref, !fir.ref) + ! CHECK: %[[VAL_34:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_35:.*]] = fir.load %[[VAL_26]]#0 : !fir.ref ! CHECK: %[[VAL_36:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}} -> %[[VAL_19:.*]] : !fir.ref) { +! CHECK: omp.wsloop { ! CHECK-NEXT: omp.loop_nest (%[[VAL_37:.*]]) : i32 = (%[[VAL_34]]) to (%[[VAL_35]]) inclusive step (%[[VAL_36]]) { -! CHECK: %[[VAL_20:.*]]:2 = hlfir.declare %[[VAL_19]] {uniq_name = "_QFcommon_2Ei"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: fir.store %[[VAL_37]] to %[[VAL_20]]#1 : !fir.ref ! CHECK: %[[VAL_38:.*]] = fir.load %[[VAL_31]]#0 : !fir.ref ! CHECK: %[[VAL_39:.*]] = fir.load %[[VAL_20]]#0 : !fir.ref diff --git a/flang/test/Lower/OpenMP/critical.f90 b/flang/test/Lower/OpenMP/critical.f90 index 99a4426ab0453..051d378210646 100644 --- a/flang/test/Lower/OpenMP/critical.f90 +++ b/flang/test/Lower/OpenMP/critical.f90 @@ -38,10 +38,11 @@ subroutine predetermined_privatization() !CHECK: omp.parallel !$omp parallel do + !CHECK: %[[PRIV_I_ALLOC:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} + !CHECK: %[[PRIV_I_DECL:.*]]:2 = hlfir.declare %[[PRIV_I_ALLOC]] do i = 2, 10 - !CHECK: omp.wsloop private(@{{.*}} %{{.*}} -> %[[PRIV_I_ALLOC:.*]] : !fir.ref) + !CHECK: omp.wsloop !CHECK: omp.loop_nest (%[[IV:[^[:space:]]+]]) - !CHECK: %[[PRIV_I_DECL:.*]]:2 = hlfir.declare %[[PRIV_I_ALLOC]] !CHECK: fir.store %[[IV]] to %[[PRIV_I_DECL]]#1 !CHECK: omp.critical !$omp critical diff --git a/flang/test/Lower/OpenMP/default-clause-byref.f90 b/flang/test/Lower/OpenMP/default-clause-byref.f90 index 10e62005f42ba..654c13ada9e39 100644 --- a/flang/test/Lower/OpenMP/default-clause-byref.f90 +++ b/flang/test/Lower/OpenMP/default-clause-byref.f90 @@ -346,7 +346,7 @@ subroutine skipped_default_clause_checks() type(it)::iii !CHECK: omp.parallel {{.*}} { -!CHECK: omp.wsloop private({{.*}}) reduction(byref @min_byref_i32 %[[VAL_Z_DECLARE]]#0 -> %[[PRV:.+]] : !fir.ref) { +!CHECK: omp.wsloop reduction(byref @min_byref_i32 %[[VAL_Z_DECLARE]]#0 -> %[[PRV:.+]] : !fir.ref) { !CHECK-NEXT: omp.loop_nest (%[[ARG:.*]]) {{.*}} { !CHECK: omp.yield !CHECK: } diff --git a/flang/test/Lower/OpenMP/default-clause.f90 b/flang/test/Lower/OpenMP/default-clause.f90 index fcc8d033eea0f..c004813a911f7 100644 --- a/flang/test/Lower/OpenMP/default-clause.f90 +++ b/flang/test/Lower/OpenMP/default-clause.f90 @@ -284,13 +284,16 @@ subroutine nested_default_clause_test4 !CHECK-LABEL: func @_QPnested_default_clause_test5 !CHECK: omp.parallel { +!CHECK: %[[X_ALLOCA:.*]] = fir.alloca i32 {bindc_name = "x", pinned, uniq_name = "_QFnested_default_clause_test5Ex"} +!CHECK: %[[X_DECLARE:.*]]:2 = hlfir.declare %[[X_ALLOCA]] {{.*}} + +!CHECK: %[[LOOP_VAR_ALLOCA:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +!CHECK: %[[LOOP_VAR_DECLARE:.*]]:2 = hlfir.declare %[[LOOP_VAR_ALLOCA]] {{.*}} + !CHECK: %[[CONST_LB:.*]] = arith.constant 1 : i32 !CHECK: %[[CONST_UB:.*]] = arith.constant 50 : i32 !CHECK: %[[CONST_STEP:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}} -> %[[X_ALLOCA:.*]], @{{.*}} %{{.*}} -> %[[LOOP_VAR_ALLOCA:.*]] : !fir.ref, !fir.ref) { !CHECK: omp.loop_nest (%[[ARG:.*]]) : i32 = (%[[CONST_LB]]) to (%[[CONST_UB]]) inclusive step (%[[CONST_STEP]]) { -!CHECK: %[[X_DECLARE:.*]]:2 = hlfir.declare %[[X_ALLOCA]] {{.*}} -!CHECK: %[[LOOP_VAR_DECLARE:.*]]:2 = hlfir.declare %[[LOOP_VAR_ALLOCA]] {{.*}} !CHECK: fir.store %[[ARG]] to %[[LOOP_VAR_DECLARE]]#1 : !fir.ref !CHECK: %[[LOADED_X:.*]] = fir.load %[[X_DECLARE]]#0 : !fir.ref !CHECK: %[[CONST:.*]] = arith.constant 1 : i32 @@ -318,12 +321,13 @@ subroutine nested_default_clause_test5 !CHECK: %[[Z_VAR_DECLARE:.*]]:2 = hlfir.declare %[[Z_VAR]] {{.*}} +!CHECK: %[[LOOP_VAR:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +!CHECK: %[[LOOP_VAR_DECLARE:.*]]:2 = hlfir.declare %[[LOOP_VAR]] {{.*}} + !CHECK: %[[CONST_LB:.*]] = arith.constant 1 : i32 !CHECK: %[[CONST_UB:.*]] = arith.constant 10 : i32 !CHECK: %[[CONST_STEP:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}} -> %[[LOOP_VAR:.*]] : !fir.ref) { !CHECK: omp.loop_nest (%[[ARG:.*]]) : i32 = (%[[CONST_LB]]) to (%[[CONST_UB]]) inclusive step (%[[CONST_STEP]]) { -!CHECK: %[[LOOP_VAR_DECLARE:.*]]:2 = hlfir.declare %[[LOOP_VAR]] {{.*}} !CHECK: fir.store %[[ARG]] to %[[LOOP_VAR_DECLARE]]#1 : !fir.ref !CHECK: %[[LOADED_X:.*]] = fir.load %[[X_VAR_DECLARE]]#0 : !fir.ref !CHECK: %[[CONST:.*]] = arith.constant 1 : i32 @@ -382,7 +386,7 @@ subroutine skipped_default_clause_checks() type(it)::iii !CHECK: omp.parallel {{.*}} { -!CHECK: omp.wsloop private({{.*}}) reduction(@min_i32 %[[VAL_Z_DECLARE]]#0 -> %[[PRV:.+]] : !fir.ref) { +!CHECK: omp.wsloop reduction(@min_i32 %[[VAL_Z_DECLARE]]#0 -> %[[PRV:.+]] : !fir.ref) { !CHECK-NEXT: omp.loop_nest (%[[ARG:.*]]) {{.*}} { !CHECK: omp.yield !CHECK: } diff --git a/flang/test/Lower/OpenMP/hlfir-wsloop.f90 b/flang/test/Lower/OpenMP/hlfir-wsloop.f90 index 786ab916d000c..f7b0ba681efeb 100644 --- a/flang/test/Lower/OpenMP/hlfir-wsloop.f90 +++ b/flang/test/Lower/OpenMP/hlfir-wsloop.f90 @@ -10,11 +10,12 @@ subroutine simple_loop ! CHECK-DAG: %[[WS_END:.*]] = arith.constant 9 : i32 ! CHECK: omp.parallel !$OMP PARALLEL - ! CHECK: omp.wsloop private(@{{.*}} %{{.*}} -> %[[ALLOCA_IV:.*]] : !fir.ref) { + ! CHECK-DAG: %[[ALLOCA_IV:.*]] = fir.alloca i32 {{{.*}}, pinned, {{.*}}} + ! CHECK: %[[IV:.*]] = fir.declare %[[ALLOCA_IV]] {uniq_name = "_QFsimple_loopEi"} : (!fir.ref) -> !fir.ref + ! CHECK: omp.wsloop { ! CHECK-NEXT: omp.loop_nest (%[[I:.*]]) : i32 = (%[[WS_ST]]) to (%[[WS_END]]) inclusive step (%[[WS_ST]]) { !$OMP DO do i=1, 9 - ! CHECK: %[[IV:.*]] = fir.declare %[[ALLOCA_IV]] {uniq_name = "_QFsimple_loopEi"} : (!fir.ref) -> !fir.ref ! CHECK: fir.store %[[I]] to %[[IV:.*]] : !fir.ref ! CHECK: %[[LOAD_IV:.*]] = fir.load %[[IV]] : !fir.ref ! CHECK: fir.call @_FortranAioOutputInteger32({{.*}}, %[[LOAD_IV]]) {{.*}}: (!fir.ref, i32) -> i1 diff --git a/flang/test/Lower/OpenMP/lastprivate-allocatable.f90 b/flang/test/Lower/OpenMP/lastprivate-allocatable.f90 index fd8338393dd88..6b7d849fde93c 100644 --- a/flang/test/Lower/OpenMP/lastprivate-allocatable.f90 +++ b/flang/test/Lower/OpenMP/lastprivate-allocatable.f90 @@ -8,11 +8,12 @@ ! CHECK: fir.store %[[VAL_2]] to %[[VAL_0]] : !fir.ref>> ! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_0]] {fortran_attrs = {{.*}}, uniq_name = "_QFEa"} : (!fir.ref>>) -> (!fir.ref>>, !fir.ref>>) ! CHECK: omp.parallel { -! CHECK: omp.wsloop private(@{{.*}} %{{.*}} -> %{{.*}}, @{{.*}} %{{.*}} -> %[[VAL_17:.*]] : !fir.ref>>, !fir.ref) { +! create original copy of private variable +! CHECK: %[[VAL_16:.*]]:2 = hlfir.declare %{{.*}} {fortran_attrs = {{.*}}, uniq_name = "_QFEa"} : (!fir.ref>>) -> (!fir.ref>>, !fir.ref>>) +! CHECK: %[[VAL_17:.*]] = fir.alloca i32 {bindc_name = "i", pinned, uniq_name = "_QFEi"} +! CHECK: %[[VAL_18:.*]]:2 = hlfir.declare %[[VAL_17]] {uniq_name = "_QFEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: omp.wsloop { ! CHECK: omp.loop_nest -! CHECK: %[[VAL_16:.*]]:2 = hlfir.declare %{{.*}} {fortran_attrs = {{.*}}, uniq_name = "_QFEa"} : (!fir.ref>>) -> (!fir.ref>>, !fir.ref>>) -! CHECK: %[[VAL_18:.*]]:2 = hlfir.declare %[[VAL_17]] {uniq_name = "_QFEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) - ! [...] ! if this is the last iteration ! CHECK: fir.if %{{.*}} { diff --git a/flang/test/Lower/OpenMP/lastprivate-commonblock.f90 b/flang/test/Lower/OpenMP/lastprivate-commonblock.f90 index c059382bf634c..faa3d3e053f34 100644 --- a/flang/test/Lower/OpenMP/lastprivate-commonblock.f90 +++ b/flang/test/Lower/OpenMP/lastprivate-commonblock.f90 @@ -11,10 +11,12 @@ !CHECK: %[[CB_C_Y_COOR:.*]] = fir.coordinate_of %[[CB_C_REF_CVT]], %{{.*}} : (!fir.ref>, index) -> !fir.ref !CHECK: %[[CB_C_Y_ADDR:.*]] = fir.convert %[[CB_C_Y_COOR]] : (!fir.ref) -> !fir.ref !CHECK: %[[Y_DECL:.*]]:2 = hlfir.declare %[[CB_C_Y_ADDR]] {uniq_name = "_QFlastprivate_commonEy"} : (!fir.ref) -> (!fir.ref, !fir.ref) -!CHECK: omp.wsloop private(@{{.*}} %{{.*}} -> %[[PRIVATE_X_REF:.*]], @{{.*}} %{{.*}} -> %[[PRIVATE_Y_REF:.*]], @{{.*}} %{{.*}} -> %{{.*}} : !{{.*}}, !{{.*}}, !{{.*}}) { -!CHECK-NEXT: omp.loop_nest (%[[I:.*]]) : i32 = (%{{.*}}) to (%{{.*}}) inclusive step (%{{.*}}) { +!CHECK: %[[PRIVATE_X_REF:.*]] = fir.alloca f32 {bindc_name = "x", pinned, uniq_name = "_QFlastprivate_commonEx"} !CHECK: %[[PRIVATE_X_DECL:.*]]:2 = hlfir.declare %[[PRIVATE_X_REF]] {uniq_name = "_QFlastprivate_commonEx"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK: %[[PRIVATE_Y_REF:.*]] = fir.alloca f32 {bindc_name = "y", pinned, uniq_name = "_QFlastprivate_commonEy"} !CHECK: %[[PRIVATE_Y_DECL:.*]]:2 = hlfir.declare %[[PRIVATE_Y_REF]] {uniq_name = "_QFlastprivate_commonEy"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK: omp.wsloop { +!CHECK-NEXT: omp.loop_nest (%[[I:.*]]) : i32 = (%{{.*}}) to (%{{.*}}) inclusive step (%{{.*}}) { !CHECK: %[[V:.*]] = arith.addi %[[I]], %{{.*}} : i32 !CHECK: %[[C0:.*]] = arith.constant 0 : i32 !CHECK: %[[NEG_STEP:.*]] = arith.cmpi slt, %{{.*}}, %[[C0]] : i32 diff --git a/flang/test/Lower/OpenMP/lastprivate-iv.f90 b/flang/test/Lower/OpenMP/lastprivate-iv.f90 index aacefd8b59c0f..63a81e818bc8b 100644 --- a/flang/test/Lower/OpenMP/lastprivate-iv.f90 +++ b/flang/test/Lower/OpenMP/lastprivate-iv.f90 @@ -6,12 +6,14 @@ !CHECK: %[[I2_MEM:.*]] = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFlastprivate_iv_incEi"} !CHECK: %[[I2:.*]]:2 = hlfir.declare %[[I2_MEM]] {uniq_name = "_QFlastprivate_iv_incEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK: %[[I_MEM:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +!CHECK: %[[I:.*]]:2 = hlfir.declare %[[I_MEM]] {uniq_name = "_QFlastprivate_iv_incEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) + !CHECK: %[[LB:.*]] = arith.constant 4 : i32 !CHECK: %[[UB:.*]] = arith.constant 10 : i32 !CHECK: %[[STEP:.*]] = arith.constant 3 : i32 -!CHECK: omp.wsloop private(@{{.*}} %{{.*}} -> %[[I_MEM:.*]] : !fir.ref) { +!CHECK: omp.wsloop { !CHECK-NEXT: omp.loop_nest (%[[IV:.*]]) : i32 = (%[[LB]]) to (%[[UB]]) inclusive step (%[[STEP]]) { -!CHECK: %[[I:.*]]:2 = hlfir.declare %[[I_MEM]] {uniq_name = "_QFlastprivate_iv_incEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) !CHECK: fir.store %[[IV]] to %[[I]]#1 : !fir.ref !CHECK: %[[V:.*]] = arith.addi %[[IV]], %[[STEP]] : i32 !CHECK: %[[C0:.*]] = arith.constant 0 : i32 @@ -40,12 +42,15 @@ subroutine lastprivate_iv_inc() !CHECK: %[[I2_MEM:.*]] = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFlastprivate_iv_decEi"} !CHECK: %[[I2:.*]]:2 = hlfir.declare %[[I2_MEM]] {uniq_name = "_QFlastprivate_iv_decEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) + +!CHECK: %[[I_MEM:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +!CHECK: %[[I:.*]]:2 = hlfir.declare %[[I_MEM]] {uniq_name = "_QFlastprivate_iv_decEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) + !CHECK: %[[LB:.*]] = arith.constant 10 : i32 !CHECK: %[[UB:.*]] = arith.constant 1 : i32 !CHECK: %[[STEP:.*]] = arith.constant -3 : i32 -!CHECK: omp.wsloop private(@{{.*}} %{{.*}} -> %[[I_MEM:.*]] : !fir.ref) { +!CHECK: omp.wsloop { !CHECK-NEXT: omp.loop_nest (%[[IV:.*]]) : i32 = (%[[LB]]) to (%[[UB]]) inclusive step (%[[STEP]]) { -!CHECK: %[[I:.*]]:2 = hlfir.declare %[[I_MEM]] {uniq_name = "_QFlastprivate_iv_decEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) !CHECK: fir.store %[[IV]] to %[[I]]#1 : !fir.ref !CHECK: %[[V:.*]] = arith.addi %[[IV]], %[[STEP]] : i32 !CHECK: %[[C0:.*]] = arith.constant 0 : i32 @@ -75,7 +80,7 @@ subroutine lastprivate_iv_dec() subroutine lastprivate_iv_i1 integer*1 :: i1 i1=0 -!CHECK: omp.wsloop private({{.*}}) +!CHECK: omp.wsloop !CHECK: omp.loop_nest !CHECK: fir.if %{{.*}} { !CHECK: %[[I8_VAL:.*]] = fir.convert %{{.*}} : (i32) -> i8 diff --git a/flang/test/Lower/OpenMP/location.f90 b/flang/test/Lower/OpenMP/location.f90 index fc7dd43499863..2dab22a1c1f90 100644 --- a/flang/test/Lower/OpenMP/location.f90 +++ b/flang/test/Lower/OpenMP/location.f90 @@ -28,7 +28,7 @@ subroutine sub_target() !CHECK-LABEL: sub_loop subroutine sub_loop() -!CHECK: omp.wsloop private({{.*}}) { +!CHECK: omp.wsloop { !CHECK-NEXT: omp.loop_nest {{.*}} { !$omp do do i=1,10 diff --git a/flang/test/Lower/OpenMP/loop-directive.f90 b/flang/test/Lower/OpenMP/loop-directive.f90 index 4b4d640e449ee..9fa0de3bfe171 100644 --- a/flang/test/Lower/OpenMP/loop-directive.f90 +++ b/flang/test/Lower/OpenMP/loop-directive.f90 @@ -11,7 +11,7 @@ subroutine test_no_clauses() integer :: i, j, dummy = 1 - ! CHECK: omp.loop private(@[[I_PRIV]] %{{.*}}#0 -> %[[ARG:.*]] : !fir.ref) { + ! CHECK: omp.simd private(@[[I_PRIV]] %{{.*}}#0 -> %[[ARG:.*]] : !fir.ref) { ! CHECK-NEXT: omp.loop_nest (%[[IV:.*]]) : i32 = (%{{.*}}) to (%{{.*}}) {{.*}} { ! CHECK: %[[ARG_DECL:.*]]:2 = hlfir.declare %[[ARG]] ! CHECK: fir.store %[[IV]] to %[[ARG_DECL]]#1 : !fir.ref @@ -27,7 +27,7 @@ subroutine test_no_clauses() ! CHECK-LABEL: func.func @_QPtest_collapse subroutine test_collapse() integer :: i, j, dummy = 1 - ! CHECK: omp.loop private(@{{.*}} %{{.*}}#0 -> %{{.*}}, @{{.*}} %{{.*}}#0 -> %{{.*}} : {{.*}}) { + ! CHECK: omp.simd private(@{{.*}} %{{.*}}#0 -> %{{.*}}, @{{.*}} %{{.*}}#0 -> %{{.*}} : {{.*}}) { ! CHECK-NEXT: omp.loop_nest (%{{.*}}, %{{.*}}) : i32 {{.*}} { ! CHECK: } ! CHECK: } @@ -43,7 +43,7 @@ subroutine test_collapse() ! CHECK-LABEL: func.func @_QPtest_private subroutine test_private() integer :: i, dummy = 1 - ! CHECK: omp.loop private(@[[DUMMY_PRIV]] %{{.*}}#0 -> %[[DUMMY_ARG:.*]], @{{.*}} %{{.*}}#0 -> %{{.*}} : {{.*}}) { + ! CHECK: omp.simd private(@[[DUMMY_PRIV]] %{{.*}}#0 -> %[[DUMMY_ARG:.*]], @{{.*}} %{{.*}}#0 -> %{{.*}} : {{.*}}) { ! CHECK-NEXT: omp.loop_nest (%{{.*}}) : i32 = (%{{.*}}) to (%{{.*}}) {{.*}} { ! CHECK: %[[DUMMY_DECL:.*]]:2 = hlfir.declare %[[DUMMY_ARG]] {uniq_name = "_QFtest_privateEdummy"} ! CHECK: %{{.*}} = fir.load %[[DUMMY_DECL]]#0 @@ -100,3 +100,42 @@ subroutine test_bind() end do !$omp end loop end subroutine + +! CHECK-LABEL: func.func @_QPtest_nested_directives +subroutine test_nested_directives + implicit none + integer, parameter :: N = 100000 + integer a(N), b(N), c(N) + integer j,i, num, flag; + num = N + + ! CHECK: omp.teams { + + ! Verify the first `loop` directive was combined with `target teams` into + ! `target teams distribute parallel do`. + ! CHECK: omp.parallel {{.*}} { + ! CHECK: omp.distribute { + ! CHECK: omp.wsloop { + ! CHECK: omp.loop_nest {{.*}} { + + ! Very the second `loop` directive was rewritten to `simd`. + ! CHECK: omp.simd {{.*}} { + ! CHECK: omp.loop_nest {{.*}} { + ! CHECK: } + ! CHECK: } + + ! CHECK: } + ! CHECK: } {omp.composite} + ! CHECK: } {omp.composite} + ! CHECK: } {omp.composite} + ! CHECK: } + !$omp target teams map(to: a,b) map(from: c) + !$omp loop + do j=1,1000 + !$omp loop + do i=1,N + c(i) = a(i) * b(i) + end do + end do + !$omp end target teams +end subroutine diff --git a/flang/test/Lower/OpenMP/order-clause.f90 b/flang/test/Lower/OpenMP/order-clause.f90 index 1f678e02708da..a30d82979021d 100644 --- a/flang/test/Lower/OpenMP/order-clause.f90 +++ b/flang/test/Lower/OpenMP/order-clause.f90 @@ -20,15 +20,15 @@ end subroutine simd_order !CHECK-LABEL: func.func @_QPdo_order() { subroutine do_order - !CHECK: omp.wsloop order(reproducible:concurrent) private({{.*}}) { + !CHECK: omp.wsloop order(reproducible:concurrent) { !$omp do order(concurrent) do i = 1, 10 end do - !CHECK: omp.wsloop order(reproducible:concurrent) private({{.*}}) { + !CHECK: omp.wsloop order(reproducible:concurrent) { !$omp do order(reproducible:concurrent) do i = 1, 10 end do - !CHECK: omp.wsloop order(unconstrained:concurrent) private({{.*}}) { + !CHECK: omp.wsloop order(unconstrained:concurrent) { !$omp do order(unconstrained:concurrent) do i = 1, 10 end do diff --git a/flang/test/Lower/OpenMP/parallel-lastprivate-clause-scalar.f90 b/flang/test/Lower/OpenMP/parallel-lastprivate-clause-scalar.f90 index 531413c124f81..86309a24f91a0 100644 --- a/flang/test/Lower/OpenMP/parallel-lastprivate-clause-scalar.f90 +++ b/flang/test/Lower/OpenMP/parallel-lastprivate-clause-scalar.f90 @@ -10,12 +10,12 @@ !CHECK-DAG: %[[ARG1_DECL:.*]]:2 = hlfir.declare %[[ARG1_REF]] typeparams %[[FIVE]] dummy_scope %{{[0-9]+}} {uniq_name = "_QFlastprivate_characterEarg1"} : (!fir.ref>, index, !fir.dscope) -> (!fir.ref>, !fir.ref>) !CHECK: omp.parallel { +!CHECK-DAG: %[[ARG1_PVT:.*]] = fir.alloca !fir.char<1,5> {bindc_name = "arg1", pinned, {{.*}}} +!CHECK-DAG: %[[ARG1_PVT_DECL:.*]]:2 = hlfir.declare %[[ARG1_PVT]] typeparams %[[FIVE]] {uniq_name = "_QFlastprivate_characterEarg1"} : (!fir.ref>, index) -> (!fir.ref>, !fir.ref>) ! Check that we are accessing the clone inside the loop -!CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[ARG1_PVT:.*]], @{{.*}} %{{.*}}#0 -> %{{.*}} : !fir.ref>, !{{.*}}) { +!CHECK: omp.wsloop { !CHECK-NEXT: omp.loop_nest (%[[INDX_WS:.*]]) : {{.*}} { -!CHECK: %[[FIVE:.*]] = arith.constant 5 : index -!CHECK: %[[ARG1_PVT_DECL:.*]]:2 = hlfir.declare %[[ARG1_PVT]] typeparams %[[FIVE]] {uniq_name = "_QFlastprivate_characterEarg1"} : (!fir.ref>, index) -> (!fir.ref>, !fir.ref>) !CHECK: %[[UNIT:.*]] = arith.constant 6 : i32 !CHECK-NEXT: %[[ADDR:.*]] = fir.address_of(@_QQclX !CHECK-NEXT: %[[CVT0:.*]] = fir.convert %[[ADDR]] @@ -58,9 +58,10 @@ subroutine lastprivate_character(arg1) !CHECK: func @_QPlastprivate_int(%[[ARG1:.*]]: !fir.ref {fir.bindc_name = "arg1"}) { !CHECK: %[[ARG1_DECL:.*]]:2 = hlfir.declare %[[ARG1]] dummy_scope %{{[0-9]+}} {uniq_name = "_QFlastprivate_intEarg1"} : (!fir.ref, !fir.dscope) -> (!fir.ref, !fir.ref) !CHECK-DAG: omp.parallel { -!CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[CLONE:.*]], @{{.*}} %{{.*}}#0 -> %{{.*}} : !fir.ref, !{{.*}}) { +!CHECK-DAG: %[[CLONE:.*]] = fir.alloca i32 {bindc_name = "arg1", pinned, {{.*}}} +!CHECK-DAG: %[[CLONE_DECL:.*]]:2 = hlfir.declare %[[CLONE]] {uniq_name = "_QFlastprivate_intEarg1"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK: omp.wsloop { !CHECK-NEXT: omp.loop_nest (%[[INDX_WS:.*]]) : {{.*}} { -!CHECK: %[[CLONE_DECL:.*]]:2 = hlfir.declare %[[CLONE]] {uniq_name = "_QFlastprivate_intEarg1"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! Testing last iteration check !CHECK: %[[V:.*]] = arith.addi %[[INDX_WS]], %{{.*}} : i32 @@ -97,10 +98,12 @@ subroutine lastprivate_int(arg1) !CHECK: %[[ARG1_DECL:.*]]:2 = hlfir.declare %[[ARG1]] dummy_scope %{{[0-9]+}} {uniq_name = "_QFmult_lastprivate_intEarg1"} : (!fir.ref, !fir.dscope) -> (!fir.ref, !fir.ref) !CHECK: %[[ARG2_DECL:.*]]:2 = hlfir.declare %[[ARG2]] dummy_scope %{{[0-9]+}} {uniq_name = "_QFmult_lastprivate_intEarg2"} : (!fir.ref, !fir.dscope) -> (!fir.ref, !fir.ref) !CHECK: omp.parallel { -!CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[CLONE1:.*]], @{{.*}} %{{.*}}#0 -> %[[CLONE2:.*]], @{{.*}} %{{.*}}#0 -> %{{.*}} : !fir.ref, !fir.ref, !{{.*}}) { -!CHECK-NEXT: omp.loop_nest (%[[INDX_WS:.*]]) : {{.*}} { +!CHECK-DAG: %[[CLONE1:.*]] = fir.alloca i32 {bindc_name = "arg1", pinned, {{.*}}} !CHECK-DAG: %[[CLONE1_DECL:.*]]:2 = hlfir.declare %[[CLONE1]] {uniq_name = "_QFmult_lastprivate_intEarg1"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK-DAG: %[[CLONE2:.*]] = fir.alloca i32 {bindc_name = "arg2", pinned, {{.*}}} !CHECK-DAG: %[[CLONE2_DECL:.*]]:2 = hlfir.declare %[[CLONE2]] {uniq_name = "_QFmult_lastprivate_intEarg2"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK: omp.wsloop { +!CHECK-NEXT: omp.loop_nest (%[[INDX_WS:.*]]) : {{.*}} { ! Testing last iteration check !CHECK: %[[V:.*]] = arith.addi %[[INDX_WS]], %{{.*}} : i32 @@ -139,10 +142,12 @@ subroutine mult_lastprivate_int(arg1, arg2) !CHECK: %[[ARG1_DECL:.*]]:2 = hlfir.declare %[[ARG1]] dummy_scope %{{[0-9]+}} {uniq_name = "_QFmult_lastprivate_int2Earg1"} : (!fir.ref, !fir.dscope) -> (!fir.ref, !fir.ref) !CHECK: %[[ARG2_DECL:.*]]:2 = hlfir.declare %[[ARG2]] dummy_scope %{{[0-9]+}} {uniq_name = "_QFmult_lastprivate_int2Earg2"} : (!fir.ref, !fir.dscope) -> (!fir.ref, !fir.ref) !CHECK: omp.parallel { -!CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[CLONE1:.*]], @{{.*}} %{{.*}}#0 -> %[[CLONE2:.*]], @{{.*}} %{{.*}}#0 -> %{{.*}} : !fir.ref, !fir.ref, !{{.*}}) { -!CHECK-NEXT: omp.loop_nest (%[[INDX_WS:.*]]) : {{.*}} { -!CHECK-DAG: %[[CLONE1_DECL:.*]]:2 = hlfir.declare %[[CLONE1]] {uniq_name = "_QFmult_lastprivate_int2Earg1"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK-DAG: %[[CLONE2:.*]] = fir.alloca i32 {bindc_name = "arg2", pinned, {{.*}}} !CHECK-DAG: %[[CLONE2_DECL:.*]]:2 = hlfir.declare %[[CLONE2]] {uniq_name = "_QFmult_lastprivate_int2Earg2"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK-DAG: %[[CLONE1:.*]] = fir.alloca i32 {bindc_name = "arg1", pinned, {{.*}}} +!CHECK-DAG: %[[CLONE1_DECL:.*]]:2 = hlfir.declare %[[CLONE1]] {uniq_name = "_QFmult_lastprivate_int2Earg1"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK: omp.wsloop { +!CHECK-NEXT: omp.loop_nest (%[[INDX_WS:.*]]) : {{.*}} { !Testing last iteration check !CHECK: %[[V:.*]] = arith.addi %[[INDX_WS]], %{{.*}} : i32 @@ -182,11 +187,16 @@ subroutine mult_lastprivate_int2(arg1, arg2) !CHECK: %[[ARG2_DECL:.*]]:2 = hlfir.declare %[[ARG2]] dummy_scope %{{[0-9]+}} {uniq_name = "_QFfirstpriv_lastpriv_intEarg2"} : (!fir.ref, !fir.dscope) -> (!fir.ref, !fir.ref) !CHECK: omp.parallel { ! Firstprivate update -!CHECK-NOT: omp.barrier -!CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[CLONE1:.*]], @{{.*}} %{{.*}}#0 -> %[[CLONE2:.*]], @{{.*}} %{{.*}}#0 -> %{{.*}} : !fir.ref, !fir.ref, !{{.*}}) { -!CHECK-NEXT: omp.loop_nest (%[[INDX_WS:.*]]) : {{.*}} { +!CHECK: %[[CLONE1:.*]] = fir.alloca i32 {bindc_name = "arg1", pinned, {{.*}}} !CHECK: %[[CLONE1_DECL:.*]]:2 = hlfir.declare %[[CLONE1]] {uniq_name = "_QFfirstpriv_lastpriv_intEarg1"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK: %[[FPV_LD:.*]] = fir.load %[[ARG1_DECL]]#0 : !fir.ref +!CHECK: hlfir.assign %[[FPV_LD]] to %[[CLONE1_DECL]]#0 : i32, !fir.ref +! Lastprivate Allocation +!CHECK: %[[CLONE2:.*]] = fir.alloca i32 {bindc_name = "arg2", pinned, {{.*}}} !CHECK: %[[CLONE2_DECL:.*]]:2 = hlfir.declare %[[CLONE2]] {uniq_name = "_QFfirstpriv_lastpriv_intEarg2"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK-NOT: omp.barrier +!CHECK: omp.wsloop { +!CHECK-NEXT: omp.loop_nest (%[[INDX_WS:.*]]) : {{.*}} { ! Testing last iteration check !CHECK: %[[V:.*]] = arith.addi %[[INDX_WS]], %{{.*}} : i32 @@ -224,14 +234,17 @@ subroutine firstpriv_lastpriv_int(arg1, arg2) !CHECK: omp.parallel { ! Firstprivate update +!CHECK: %[[CLONE1:.*]] = fir.alloca i32 {bindc_name = "arg1", pinned, {{.*}}} +!CHECK: %[[CLONE1_DECL:.*]]:2 = hlfir.declare %[[CLONE1]] {uniq_name = "_QFfirstpriv_lastpriv_int2Earg1"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK-NEXT: %[[FPV_LD:.*]] = fir.load %[[ARG1_DECL]]#0 : !fir.ref +!CHECK-NEXT: hlfir.assign %[[FPV_LD]] to %[[CLONE1_DECL]]#0 : i32, !fir.ref +!CHECK-NEXT: %[[IV:.*]] = fir.alloca i32 {bindc_name = "n", pinned, {{.*}}} +!CHECK-NEXT: hlfir.declare %[[IV]] !CHECK-NEXT: omp.barrier -!CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[CLONE1:.*]], @{{.*}} %{{.*}}#0 -> %[[IV:.*]] : !fir.ref, !fir.ref) { +!CHECK: omp.wsloop { !CHECK-NEXT: omp.loop_nest (%[[INDX_WS:.*]]) : {{.*}} { -!CHECK: %[[CLONE1_DECL:.*]]:2 = hlfir.declare %[[CLONE1]] {uniq_name = "_QFfirstpriv_lastpriv_int2Earg1"} : (!fir.ref) -> (!fir.ref, !fir.ref) - -!CHECK-NEXT: hlfir.declare %[[IV]] ! Testing last iteration check !CHECK: %[[V:.*]] = arith.addi %[[INDX_WS]], %{{.*}} : i32 !CHECK: %[[C0:.*]] = arith.constant 0 : i32 diff --git a/flang/test/Lower/OpenMP/parallel-private-clause-fixes.f90 b/flang/test/Lower/OpenMP/parallel-private-clause-fixes.f90 index e8ac8e7f62122..99323e69113bc 100644 --- a/flang/test/Lower/OpenMP/parallel-private-clause-fixes.f90 +++ b/flang/test/Lower/OpenMP/parallel-private-clause-fixes.f90 @@ -56,15 +56,17 @@ ! CHECK-DAG: %[[VAL_2:.*]] = fir.alloca i32 {bindc_name = "x", uniq_name = "_QFmultiple_private_fixEx"} ! CHECK-DAG: %[[X_DECL:.*]]:2 = hlfir.declare %[[VAL_2]] {uniq_name = "_QFmultiple_private_fixEx"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: omp.parallel { - +! CHECK-DAG: %[[PRIV_I:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK-DAG: %[[PRIV_I_DECL:.*]]:2 = hlfir.declare %[[PRIV_I]] {uniq_name = "_QFmultiple_private_fixEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK-DAG: %[[PRIV_J:.*]] = fir.alloca i32 {bindc_name = "j", pinned, uniq_name = "_QFmultiple_private_fixEj"} +! CHECK-DAG: %[[PRIV_J_DECL:.*]]:2 = hlfir.declare %[[PRIV_J]] {uniq_name = "_QFmultiple_private_fixEj"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK-DAG: %[[PRIV_X:.*]] = fir.alloca i32 {bindc_name = "x", pinned, {{.*}}} +! CHECK-DAG: %[[PRIV_X_DECL:.*]]:2 = hlfir.declare %[[PRIV_X]] {uniq_name = "_QFmultiple_private_fixEx"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[ONE:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_3:.*]] = fir.load %[[GAMA_DECL]]#0 : !fir.ref ! CHECK: %[[VAL_5:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[PRIV_J:.*]], @{{.*}} %{{.*}}#0 -> %[[PRIV_X:.*]], @{{.*}} %{{.*}}#0 -> %[[PRIV_I:.*]] : !fir.ref, !fir.ref, !fir.ref) { +! CHECK: omp.wsloop { ! CHECK-NEXT: omp.loop_nest (%[[VAL_6:.*]]) : i32 = (%[[ONE]]) to (%[[VAL_3]]) inclusive step (%[[VAL_5]]) { -! CHECK-DAG: %[[PRIV_I_DECL:.*]]:2 = hlfir.declare %[[PRIV_I]] {uniq_name = "_QFmultiple_private_fixEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) -! CHECK-DAG: %[[PRIV_J_DECL:.*]]:2 = hlfir.declare %[[PRIV_J]] {uniq_name = "_QFmultiple_private_fixEj"} : (!fir.ref) -> (!fir.ref, !fir.ref) -! CHECK-DAG: %[[PRIV_X_DECL:.*]]:2 = hlfir.declare %[[PRIV_X]] {uniq_name = "_QFmultiple_private_fixEx"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: fir.store %[[VAL_6]] to %[[PRIV_I_DECL]]#1 : !fir.ref ! CHECK: %[[VAL_7:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_8:.*]] = fir.convert %[[VAL_7]] : (i32) -> index diff --git a/flang/test/Lower/OpenMP/parallel-private-clause.f90 b/flang/test/Lower/OpenMP/parallel-private-clause.f90 index f26b97b55d51a..7114314df05d3 100644 --- a/flang/test/Lower/OpenMP/parallel-private-clause.f90 +++ b/flang/test/Lower/OpenMP/parallel-private-clause.f90 @@ -271,16 +271,17 @@ subroutine simple_loop_1 !$OMP PARALLEL PRIVATE(r) ! FIRDialect: %[[R_DECL:.*]]:2 = hlfir.declare %[[R]] {fortran_attrs = #fir.var_attrs, uniq_name = "_QFsimple_loop_1Er"} : (!fir.ref>>) -> (!fir.ref>>, !fir.ref>>) + ! FIRDialect: %[[ALLOCA_IV:.*]] = fir.alloca i32 {{{.*}}, pinned, {{.*}}} + ! FIRDialect: %[[ALLOCA_IV_DECL:.*]]:2 = hlfir.declare %[[ALLOCA_IV]] {uniq_name = "_QFsimple_loop_1Ei"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! FIRDialect: %[[WS_LB:.*]] = arith.constant 1 : i32 ! FIRDialect: %[[WS_UB:.*]] = arith.constant 9 : i32 ! FIRDialect: %[[WS_STEP:.*]] = arith.constant 1 : i32 - ! FIRDialect: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[ALLOCA_IV:.*]] : !fir.ref) { + ! FIRDialect: omp.wsloop { ! FIRDialect-NEXT: omp.loop_nest (%[[I:.*]]) : i32 = (%[[WS_LB]]) to (%[[WS_UB]]) inclusive step (%[[WS_STEP]]) { !$OMP DO do i=1, 9 - ! FIRDialect: %[[ALLOCA_IV_DECL:.*]]:2 = hlfir.declare %[[ALLOCA_IV]] {uniq_name = "_QFsimple_loop_1Ei"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! FIRDialect: fir.store %[[I]] to %[[ALLOCA_IV_DECL]]#1 : !fir.ref ! FIRDialect: %[[LOAD_IV:.*]] = fir.load %[[ALLOCA_IV_DECL]]#0 : !fir.ref ! FIRDialect: fir.call @_FortranAioOutputInteger32({{.*}}, %[[LOAD_IV]]) {{.*}} : (!fir.ref, i32) -> i1 @@ -298,23 +299,34 @@ subroutine simple_loop_2 real, allocatable :: r; ! FIRDialect: omp.parallel !$OMP PARALLEL + ! FIRDialect: [[R:%.*]] = fir.alloca !fir.box> {bindc_name = "r", pinned, uniq_name = "{{.*}}Er"} + ! FIRDialect: fir.store {{%.*}} to [[R]] : !fir.ref>> + ! FIRDialect: fir.store {{%.*}} to [[R]] : !fir.ref>> + ! FIRDialect: %[[R_DECL:.*]]:2 = hlfir.declare [[R]] {fortran_attrs = #fir.var_attrs, uniq_name = "{{.*}}Er"} : (!fir.ref>>) -> (!fir.ref>>, !fir.ref>>) + + ! FIRDialect: %[[ALLOCA_IV:.*]] = fir.alloca i32 {{{.*}}, pinned, {{.*}}} + ! FIRDialect: %[[ALLOCA_IV_DECL:.*]]:2 = hlfir.declare %[[ALLOCA_IV]] {uniq_name = "{{.*}}Ei"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! FIRDialect: %[[WS_LB:.*]] = arith.constant 1 : i32 ! FIRDialect: %[[WS_UB:.*]] = arith.constant 9 : i32 ! FIRDialect: %[[WS_STEP:.*]] = arith.constant 1 : i32 - ! FIRDialect: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[R:.*]], @{{.*}} %{{.*}}#0 -> %[[ALLOCA_IV:.*]] : !fir.ref>>, !fir.ref) { + ! FIRDialect: omp.wsloop { ! FIRDialect-NEXT: omp.loop_nest (%[[I:.*]]) : i32 = (%[[WS_LB]]) to (%[[WS_UB]]) inclusive step (%[[WS_STEP]]) { !$OMP DO PRIVATE(r) do i=1, 9 - ! FIRDialect: %[[R_DECL:.*]]:2 = hlfir.declare %[[R]] {fortran_attrs = #fir.var_attrs, uniq_name = "{{.*}}Er"} : (!fir.ref>>) -> (!fir.ref>>, !fir.ref>>) - ! FIRDialect: %[[ALLOCA_IV_DECL:.*]]:2 = hlfir.declare %[[ALLOCA_IV]] {uniq_name = "{{.*}}Ei"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! FIRDialect: fir.store %[[I]] to %[[ALLOCA_IV_DECL]]#1 : !fir.ref ! FIRDialect: %[[LOAD_IV:.*]] = fir.load %[[ALLOCA_IV_DECL]]#0 : !fir.ref ! FIRDialect: fir.call @_FortranAioOutputInteger32({{.*}}, %[[LOAD_IV]]) {{.*}}: (!fir.ref, i32) -> i1 print*, i end do ! FIRDialect: omp.yield + ! FIRDialect: {{%.*}} = fir.load %[[R_DECL]]#0 : !fir.ref>> + ! FIRDialect: fir.if {{%.*}} { + ! FIRDialect: [[LD:%.*]] = fir.load %[[R_DECL]]#0 : !fir.ref>> + ! FIRDialect: [[AD:%.*]] = fir.box_addr [[LD]] : (!fir.box>) -> !fir.heap + ! FIRDialect: fir.freemem [[AD]] : !fir.heap + ! FIRDialect: fir.store {{%.*}} to %[[R_DECL]]#0 : !fir.ref>> !$OMP END DO ! FIRDialect: omp.terminator !$OMP END PARALLEL @@ -325,24 +337,35 @@ subroutine simple_loop_3 integer :: i real, allocatable :: r; ! FIRDialect: omp.parallel + + ! FIRDialect: [[R:%.*]] = fir.alloca !fir.box> {bindc_name = "r", pinned, uniq_name = "{{.*}}Er"} + ! FIRDialect: fir.store {{%.*}} to [[R]] : !fir.ref>> + ! FIRDialect: fir.store {{%.*}} to [[R]] : !fir.ref>> + ! FIRDialect: [[R_DECL:%.*]]:2 = hlfir.declare [[R]] {fortran_attrs = #fir.var_attrs, uniq_name = "{{.*}}Er"} : (!fir.ref>>) -> (!fir.ref>>, !fir.ref>>) + + ! FIRDialect: %[[ALLOCA_IV:.*]] = fir.alloca i32 {{{.*}}, pinned, {{.*}}} + ! FIRDialect: %[[ALLOCA_IV_DECL:.*]]:2 = hlfir.declare %[[ALLOCA_IV]] {uniq_name = "{{.*}}Ei"} : (!fir.ref) -> (!fir.ref, !fir.ref) + ! FIRDialect: %[[WS_LB:.*]] = arith.constant 1 : i32 ! FIRDialect: %[[WS_UB:.*]] = arith.constant 9 : i32 ! FIRDialect: %[[WS_STEP:.*]] = arith.constant 1 : i32 - ! FIRDialect: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[R:.*]], @{{.*}} %{{.*}}#0 -> %[[ALLOCA_IV:.*]] : !fir.ref>>, !fir.ref) { + ! FIRDialect: omp.wsloop { ! FIRDialect-NEXT: omp.loop_nest (%[[I:.*]]) : i32 = (%[[WS_LB]]) to (%[[WS_UB]]) inclusive step (%[[WS_STEP]]) { !$OMP PARALLEL DO PRIVATE(r) do i=1, 9 - ! FIRDialect: [[R_DECL:%.*]]:2 = hlfir.declare %[[R]] {fortran_attrs = #fir.var_attrs, uniq_name = "{{.*}}Er"} : (!fir.ref>>) -> (!fir.ref>>, !fir.ref>>) - - ! FIRDialect: %[[ALLOCA_IV_DECL:.*]]:2 = hlfir.declare %[[ALLOCA_IV]] {uniq_name = "{{.*}}Ei"} : (!fir.ref) -> (!fir.ref, !fir.ref) - ! FIRDialect: fir.store %[[I]] to %[[ALLOCA_IV_DECL:.*]]#1 : !fir.ref ! FIRDialect: %[[LOAD_IV:.*]] = fir.load %[[ALLOCA_IV_DECL]]#0 : !fir.ref ! FIRDialect: fir.call @_FortranAioOutputInteger32({{.*}}, %[[LOAD_IV]]) {{.*}}: (!fir.ref, i32) -> i1 print*, i end do ! FIRDialect: omp.yield + ! FIRDialect: {{%.*}} = fir.load [[R_DECL]]#0 : !fir.ref>> + ! FIRDialect: fir.if {{%.*}} { + ! FIRDialect: [[LD:%.*]] = fir.load [[R_DECL]]#0 : !fir.ref>> + ! FIRDialect: [[AD:%.*]] = fir.box_addr [[LD]] : (!fir.box>) -> !fir.heap + ! FIRDialect: fir.freemem [[AD]] : !fir.heap + ! FIRDialect: fir.store {{%.*}} to [[R_DECL]]#0 : !fir.ref>> !$OMP END PARALLEL DO ! FIRDialect: omp.terminator end subroutine diff --git a/flang/test/Lower/OpenMP/parallel-reduction-allocatable-array.f90 b/flang/test/Lower/OpenMP/parallel-reduction-allocatable-array.f90 index 11d5682209676..dabd495d733b5 100644 --- a/flang/test/Lower/OpenMP/parallel-reduction-allocatable-array.f90 +++ b/flang/test/Lower/OpenMP/parallel-reduction-allocatable-array.f90 @@ -92,12 +92,13 @@ program reduce ! CHECK: %[[VAL_11:.*]] = fir.embox %[[VAL_9]](%[[VAL_10]]) : (!fir.heap>, !fir.shape<1>) -> !fir.box>> ! CHECK: fir.store %[[VAL_11]] to %[[VAL_3]]#1 : !fir.ref>>> ! CHECK: omp.parallel { +! CHECK: %[[VAL_12:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_13:.*]]:2 = hlfir.declare %[[VAL_12]] {uniq_name = "_QFEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_14:.*]] = arith.constant 0 : i32 ! CHECK: %[[VAL_15:.*]] = arith.constant 10 : i32 ! CHECK: %[[VAL_16:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_12:.*]] : !fir.ref) reduction(byref @add_reduction_byref_box_heap_Uxi32 %[[VAL_3]]#0 -> %[[VAL_17:.*]] : !fir.ref>>>) { +! CHECK: omp.wsloop reduction(byref @add_reduction_byref_box_heap_Uxi32 %[[VAL_3]]#0 -> %[[VAL_17:.*]] : !fir.ref>>>) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_18:.*]]) : i32 = (%[[VAL_14]]) to (%[[VAL_15]]) inclusive step (%[[VAL_16]]) { -! CHECK: %[[VAL_13:.*]]:2 = hlfir.declare %[[VAL_12]] {uniq_name = "_QFEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_19:.*]]:2 = hlfir.declare %[[VAL_17]] {fortran_attrs = {{.*}}, uniq_name = "_QFEr"} : (!fir.ref>>>) -> (!fir.ref>>>, !fir.ref>>>) ! CHECK: fir.store %[[VAL_18]] to %[[VAL_13]]#1 : !fir.ref ! CHECK: %[[VAL_20:.*]] = fir.load %[[VAL_13]]#0 : !fir.ref diff --git a/flang/test/Lower/OpenMP/parallel-reduction-pointer-array.f90 b/flang/test/Lower/OpenMP/parallel-reduction-pointer-array.f90 index 54fe53b5d6f6a..1e07018a68877 100644 --- a/flang/test/Lower/OpenMP/parallel-reduction-pointer-array.f90 +++ b/flang/test/Lower/OpenMP/parallel-reduction-pointer-array.f90 @@ -104,12 +104,13 @@ program reduce ! CHECK: %[[VAL_20:.*]] = fir.convert %[[VAL_6]] : (!fir.ref>) -> !fir.ref ! CHECK: %[[VAL_21:.*]] = fir.call @_FortranAPointerAllocate(%[[VAL_19]], %[[VAL_4]], %[[VAL_5]], %[[VAL_20]], %[[VAL_7]]) fastmath : (!fir.ref>, i1, !fir.box, !fir.ref, i32) -> i32 ! CHECK: omp.parallel { +! CHECK: %[[VAL_22:.*]] = fir.alloca i32 {bindc_name = "i", pinned, uniq_name = "_QFEi"} +! CHECK: %[[VAL_23:.*]]:2 = hlfir.declare %[[VAL_22]] {uniq_name = "_QFEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_24:.*]] = arith.constant 0 : i32 ! CHECK: %[[VAL_25:.*]] = arith.constant 10 : i32 ! CHECK: %[[VAL_26:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_22:.*]] : !fir.ref) reduction(byref @add_reduction_byref_box_ptr_Uxi32 %[[VAL_3]]#0 -> %[[VAL_27:.*]] : !fir.ref>>>) { +! CHECK: omp.wsloop reduction(byref @add_reduction_byref_box_ptr_Uxi32 %[[VAL_3]]#0 -> %[[VAL_27:.*]] : !fir.ref>>>) { ! CHECK: omp.loop_nest (%[[VAL_28:.*]]) : i32 = (%[[VAL_24]]) to (%[[VAL_25]]) inclusive step (%[[VAL_26]]) { -! CHECK: %[[VAL_23:.*]]:2 = hlfir.declare %[[VAL_22]] {uniq_name = "_QFEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_29:.*]]:2 = hlfir.declare %[[VAL_27]] {fortran_attrs = {{.*}}, uniq_name = "_QFEr"} : (!fir.ref>>>) -> (!fir.ref>>>, !fir.ref>>>) ! CHECK: fir.store %[[VAL_28]] to %[[VAL_23]]#1 : !fir.ref ! CHECK: %[[VAL_30:.*]] = fir.load %[[VAL_23]]#0 : !fir.ref diff --git a/flang/test/Lower/OpenMP/parallel-reduction3.f90 b/flang/test/Lower/OpenMP/parallel-reduction3.f90 index 194b3fdd98201..bb45206e36ee5 100644 --- a/flang/test/Lower/OpenMP/parallel-reduction3.f90 +++ b/flang/test/Lower/OpenMP/parallel-reduction3.f90 @@ -71,12 +71,13 @@ ! CHECK: omp.parallel { ! CHECK: %[[VAL_14:.*]] = fir.alloca !fir.box> ! CHECK: fir.store %[[VAL_12]]#0 to %[[VAL_14]] : !fir.ref>> +! CHECK: %[[VAL_15:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_16:.*]]:2 = hlfir.declare %[[VAL_15]] {uniq_name = "_QFsEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_17:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_18:.*]] = arith.constant 100 : i32 ! CHECK: %[[VAL_19:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_15:.*]] : !fir.ref) reduction(byref @add_reduction_byref_box_Uxi32 %[[VAL_14]] -> %[[VAL_20:.*]] : !fir.ref>>) { +! CHECK: omp.wsloop reduction(byref @add_reduction_byref_box_Uxi32 %[[VAL_14]] -> %[[VAL_20:.*]] : !fir.ref>>) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_21:.*]]) : i32 = (%[[VAL_17]]) to (%[[VAL_18]]) inclusive step (%[[VAL_19]]) { -! CHECK: %[[VAL_16:.*]]:2 = hlfir.declare %[[VAL_15]] {uniq_name = "_QFsEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_22:.*]]:2 = hlfir.declare %[[VAL_20]] {uniq_name = "_QFsEc"} : (!fir.ref>>) -> (!fir.ref>>, !fir.ref>>) ! CHECK: fir.store %[[VAL_21]] to %[[VAL_16]]#1 : !fir.ref ! CHECK: %[[VAL_23:.*]] = fir.load %[[VAL_22]]#0 : !fir.ref>> diff --git a/flang/test/Lower/OpenMP/parallel-wsloop-firstpriv.f90 b/flang/test/Lower/OpenMP/parallel-wsloop-firstpriv.f90 index a0cdaaa4c7b09..4e7c2c15df743 100644 --- a/flang/test/Lower/OpenMP/parallel-wsloop-firstpriv.f90 +++ b/flang/test/Lower/OpenMP/parallel-wsloop-firstpriv.f90 @@ -11,13 +11,20 @@ subroutine omp_do_firstprivate(a) n = a+1 !$omp parallel do firstprivate(a) ! CHECK: omp.parallel { + + ! CHECK: %[[A_PVT_REF:.*]] = fir.alloca i32 {bindc_name = "a", pinned, uniq_name = "_QFomp_do_firstprivateEa"} + ! CHECK: %[[A_PVT_DECL:.*]]:2 = hlfir.declare %[[A_PVT_REF]] {uniq_name = "_QFomp_do_firstprivateEa"} : (!fir.ref) -> (!fir.ref, !fir.ref) + ! CHECK-NEXT: %[[LD:.*]] = fir.load %[[ARG0_DECL]]#0 : !fir.ref + ! CHECK-NEXT: hlfir.assign %[[LD]] to %[[A_PVT_DECL]]#0 : i32, !fir.ref + + ! CHECK: %[[I_PVT_REF:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} + ! CHECK: %[[I_PVT_DECL:.*]]:2 = hlfir.declare %[[I_PVT_REF]] {uniq_name = "_QFomp_do_firstprivateEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) + ! CHECK: %[[LB:.*]] = arith.constant 1 : i32 - ! CHECK-NEXT: %[[UB:.*]] = fir.load %[[ARG0_DECL]]#0 : !fir.ref + ! CHECK-NEXT: %[[UB:.*]] = fir.load %[[A_PVT_DECL]]#0 : !fir.ref ! CHECK-NEXT: %[[STEP:.*]] = arith.constant 1 : i32 - ! CHECK-NEXT: omp.wsloop private(@{{.*a_firstprivate_ref_i32.*}} %{{.*}}#0 -> %[[A_PVT_REF:.*]], @{{.*i_private_ref_i32.*}} %{{.*}}#0 -> %[[I_PVT_REF:.*]] : !fir.ref, !fir.ref) { + ! CHECK-NEXT: omp.wsloop { ! CHECK-NEXT: omp.loop_nest (%[[ARG1:.*]]) : i32 = (%[[LB]]) to (%[[UB]]) inclusive step (%[[STEP]]) { - ! CHECK: %[[A_PVT_DECL:.*]]:2 = hlfir.declare %[[A_PVT_REF]] {uniq_name = "_QFomp_do_firstprivateEa"} : (!fir.ref) -> (!fir.ref, !fir.ref) - ! CHECK: %[[I_PVT_DECL:.*]]:2 = hlfir.declare %[[I_PVT_REF]] {uniq_name = "_QFomp_do_firstprivateEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK-NEXT: fir.store %[[ARG1]] to %[[I_PVT_DECL]]#1 : !fir.ref ! CHECK-NEXT: fir.call @_QPfoo(%[[I_PVT_DECL]]#1, %[[A_PVT_DECL]]#1) {{.*}}: (!fir.ref, !fir.ref) -> () ! CHECK-NEXT: omp.yield @@ -40,14 +47,25 @@ subroutine omp_do_firstprivate2(a, n) n = a+1 !$omp parallel do firstprivate(a, n) ! CHECK: omp.parallel { - ! CHECK: %[[LB:.*]] = fir.load %[[ARG0_DECL]]#0 : !fir.ref - ! CHECK: %[[UB:.*]] = fir.load %[[ARG1_DECL]]#0 : !fir.ref - ! CHECK: %[[STEP:.*]] = arith.constant 1 : i32 - ! CHECK: omp.wsloop private(@{{.*a_firstprivate_ref_i32}} %{{.*}}#0 -> %[[A_PVT_REF:.*]], @{{.*n_firstprivate_ref_i32}} %{{.*}}#0 -> %[[N_PVT_REF:.*]], @{{.*i_private_ref_i32}} %{{.*}}#0 -> %[[I_PVT_REF:.*]] : !fir.ref, !fir.ref, !fir.ref) { - ! CHECK-NEXT: omp.loop_nest (%[[ARG2:.*]]) : i32 = (%[[LB]]) to (%[[UB]]) inclusive step (%[[STEP]]) { + + ! CHECK: %[[A_PVT_REF:.*]] = fir.alloca i32 {bindc_name = "a", pinned, {{.*}}} ! CHECK: %[[A_PVT_DECL:.*]]:2 = hlfir.declare %[[A_PVT_REF]] {uniq_name = "_QFomp_do_firstprivate2Ea"} : (!fir.ref) -> (!fir.ref, !fir.ref) + ! CHECK: %[[LD:.*]] = fir.load %[[ARG0_DECL]]#0 : !fir.ref + ! CHECK: hlfir.assign %[[LD]] to %[[A_PVT_DECL]]#0 : i32, !fir.ref + + ! CHECK: %[[N_PVT_REF:.*]] = fir.alloca i32 {bindc_name = "n", pinned, uniq_name = "_QFomp_do_firstprivate2En"} ! CHECK: %[[N_PVT_DECL:.*]]:2 = hlfir.declare %[[N_PVT_REF]] {uniq_name = "_QFomp_do_firstprivate2En"} : (!fir.ref) -> (!fir.ref, !fir.ref) + ! CHECK: %[[LD1:.*]] = fir.load %[[ARG1_DECL]]#0 : !fir.ref + ! CHECK: hlfir.assign %[[LD1]] to %[[N_PVT_DECL]]#0 : i32, !fir.ref + + ! CHECK: %[[I_PVT_REF:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} ! CHECK: %[[I_PVT_DECL:.*]]:2 = hlfir.declare %[[I_PVT_REF]] {uniq_name = "_QFomp_do_firstprivate2Ei"} : (!fir.ref) -> (!fir.ref, !fir.ref) + + ! CHECK: %[[LB:.*]] = fir.load %[[A_PVT_DECL]]#0 : !fir.ref + ! CHECK: %[[UB:.*]] = fir.load %[[N_PVT_DECL]]#0 : !fir.ref + ! CHECK: %[[STEP:.*]] = arith.constant 1 : i32 + ! CHECK: omp.wsloop { + ! CHECK-NEXT: omp.loop_nest (%[[ARG2:.*]]) : i32 = (%[[LB]]) to (%[[UB]]) inclusive step (%[[STEP]]) { ! CHECK: fir.store %[[ARG2]] to %[[I_PVT_DECL]]#1 : !fir.ref ! CHECK: fir.call @_QPfoo(%[[I_PVT_DECL]]#1, %[[A_PVT_DECL]]#1) {{.*}}: (!fir.ref, !fir.ref) -> () ! CHECK: omp.yield diff --git a/flang/test/Lower/OpenMP/parallel-wsloop-lastpriv.f90 b/flang/test/Lower/OpenMP/parallel-wsloop-lastpriv.f90 index a7c0dc3b1b406..dbde5291c01c8 100644 --- a/flang/test/Lower/OpenMP/parallel-wsloop-lastpriv.f90 +++ b/flang/test/Lower/OpenMP/parallel-wsloop-lastpriv.f90 @@ -12,15 +12,17 @@ subroutine omp_do_lastprivate(a) !$omp parallel do lastprivate(a) ! CHECK: omp.parallel { + ! CHECK: %[[A_PVT_REF:.*]] = fir.alloca i32 {bindc_name = "a", pinned, uniq_name = "_QFomp_do_lastprivateEa"} + ! CHECK: %[[A_PVT_DECL:.*]]:2 = hlfir.declare %[[A_PVT_REF]] {uniq_name = "_QFomp_do_lastprivateEa"} : (!fir.ref) -> (!fir.ref, !fir.ref) + + ! CHECK: %[[I_PVT_REF:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} + ! CHECK: %[[I_PVT_DECL:.*]]:2 = hlfir.declare %[[I_PVT_REF]] {uniq_name = "_QFomp_do_lastprivateEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[LB:.*]] = arith.constant 1 : i32 - ! CHECK-NEXT: %[[UB:.*]] = fir.load %[[ARG0_DECL]]#0 : !fir.ref + ! CHECK-NEXT: %[[UB:.*]] = fir.load %[[A_PVT_DECL]]#0 : !fir.ref ! CHECK-NEXT: %[[STEP:.*]] = arith.constant 1 : i32 - ! CHECK-NEXT: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[A_PVT_REF:.*]], @{{.*}} %{{.*}}#0 -> %[[I_PVT_REF:.*]] : !fir.ref, !fir.ref) { + ! CHECK-NEXT: omp.wsloop { ! CHECK-NEXT: omp.loop_nest (%[[ARG1:.*]]) : i32 = (%[[LB]]) to (%[[UB]]) inclusive step (%[[STEP]]) { - ! CHECK: %[[A_PVT_DECL:.*]]:2 = hlfir.declare %[[A_PVT_REF]] {uniq_name = "_QFomp_do_lastprivateEa"} : (!fir.ref) -> (!fir.ref, !fir.ref) - ! CHECK: %[[I_PVT_DECL:.*]]:2 = hlfir.declare %[[I_PVT_REF]] {uniq_name = "_QFomp_do_lastprivateEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) - ! CHECK-NEXT: fir.store %[[ARG1]] to %[[I_PVT_DECL]]#1 : !fir.ref ! CHECK-NEXT: fir.call @_QPfoo(%[[I_PVT_DECL]]#1, %[[A_PVT_DECL]]#1) {{.*}}: (!fir.ref, !fir.ref) -> () ! CHECK: %[[NEXT_ARG1:.*]] = arith.addi %[[ARG1]], %[[STEP]] : i32 @@ -56,15 +58,20 @@ subroutine omp_do_lastprivate2(a, n) !$omp parallel do lastprivate(a, n) ! CHECK: omp.parallel { - ! CHECK: %[[LB:.*]] = fir.load %[[ARG0_DECL]]#0 : !fir.ref - ! CHECK: %[[UB:.*]] = fir.load %[[ARG1_DECL]]#0 : !fir.ref - ! CHECK: %[[STEP:.*]] = arith.constant 1 : i32 - ! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[A_PVT_REF:.*]], @{{.*}} %{{.*}}#0 -> %[[N_PVT_REF:.*]], @{{.*}} %{{.*}}#0 -> %[[I_PVT_REF:.*]] : !fir.ref, !fir.ref, !fir.ref) { - ! CHECK-NEXT: omp.loop_nest (%[[ARG2:.*]]) : i32 = (%[[LB]]) to (%[[UB]]) inclusive step (%[[STEP]]) { + ! CHECK: %[[A_PVT_REF:.*]] = fir.alloca i32 {bindc_name = "a", pinned, {{.*}}} ! CHECK: %[[A_PVT_DECL:.*]]:2 = hlfir.declare %[[A_PVT_REF]] {uniq_name = "_QFomp_do_lastprivate2Ea"} : (!fir.ref) -> (!fir.ref, !fir.ref) + + ! CHECK: %[[N_PVT_REF:.*]] = fir.alloca i32 {bindc_name = "n", pinned, uniq_name = "_QFomp_do_lastprivate2En"} ! CHECK: %[[N_PVT_DECL:.*]]:2 = hlfir.declare %[[N_PVT_REF]] {uniq_name = "_QFomp_do_lastprivate2En"} : (!fir.ref) -> (!fir.ref, !fir.ref) + + ! CHECK: %[[I_PVT_REF:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} ! CHECK: %[[I_PVT_DECL:.*]]:2 = hlfir.declare %[[I_PVT_REF]] {uniq_name = "_QFomp_do_lastprivate2Ei"} : (!fir.ref) -> (!fir.ref, !fir.ref) + ! CHECK: %[[LB:.*]] = fir.load %[[A_PVT_DECL]]#0 : !fir.ref + ! CHECK: %[[UB:.*]] = fir.load %[[N_PVT_DECL]]#0 : !fir.ref + ! CHECK: %[[STEP:.*]] = arith.constant 1 : i32 + ! CHECK: omp.wsloop { + ! CHECK-NEXT: omp.loop_nest (%[[ARG2:.*]]) : i32 = (%[[LB]]) to (%[[UB]]) inclusive step (%[[STEP]]) { ! CHECK: fir.store %[[ARG2]] to %[[I_PVT_DECL]]#1 : !fir.ref ! CHECK: fir.call @_QPfoo(%[[I_PVT_DECL]]#1, %[[A_PVT_DECL]]#1) {{.*}}: (!fir.ref, !fir.ref) -> () ! CHECK: %[[NEXT_ARG2:.*]] = arith.addi %[[ARG2]], %[[STEP]] : i32 @@ -97,18 +104,23 @@ subroutine omp_do_lastprivate_collapse2(a) !$omp parallel do lastprivate(a) collapse(2) ! CHECK: omp.parallel { + ! CHECK: %[[A_PVT_REF:.*]] = fir.alloca i32 {bindc_name = "a", pinned, uniq_name = "_QFomp_do_lastprivate_collapse2Ea"} + ! CHECK: %[[A_PVT_DECL:.*]]:2 = hlfir.declare %[[A_PVT_REF]] {uniq_name = "_QFomp_do_lastprivate_collapse2Ea"} : (!fir.ref) -> (!fir.ref, !fir.ref) + + ! CHECK: %[[I_PVT_REF:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} + ! CHECK: %[[I_PVT_DECL:.*]]:2 = hlfir.declare %[[I_PVT_REF]] {uniq_name = "_QFomp_do_lastprivate_collapse2Ei"} : (!fir.ref) -> (!fir.ref, !fir.ref) + ! + ! CHECK: %[[J_PVT_REF:.*]] = fir.alloca i32 {bindc_name = "j", pinned, {{.*}}} + ! CHECK: %[[J_PVT_DECL:.*]]:2 = hlfir.declare %[[J_PVT_REF]] {uniq_name = "_QFomp_do_lastprivate_collapse2Ej"} : (!fir.ref) -> (!fir.ref, !fir.ref) + ! CHECK: %[[LB1:.*]] = arith.constant 1 : i32 - ! CHECK-NEXT: %[[UB1:.*]] = fir.load %[[ARG0_DECL]]#0 : !fir.ref + ! CHECK-NEXT: %[[UB1:.*]] = fir.load %[[A_PVT_DECL]]#0 : !fir.ref ! CHECK-NEXT: %[[STEP1:.*]] = arith.constant 1 : i32 ! CHECK: %[[LB2:.*]] = arith.constant 1 : i32 - ! CHECK-NEXT: %[[UB2:.*]] = fir.load %[[ARG0_DECL]]#0 : !fir.ref + ! CHECK-NEXT: %[[UB2:.*]] = fir.load %[[A_PVT_DECL]]#0 : !fir.ref ! CHECK-NEXT: %[[STEP2:.*]] = arith.constant 1 : i32 - ! CHECK-NEXT: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[A_PVT_REF:.*]], @{{.*}} %{{.*}}#0 -> %[[I_PVT_REF:.*]], @{{.*}} %{{.*}}#0 -> %[[J_PVT_REF:.*]] : !fir.ref, !fir.ref, !fir.ref) { + ! CHECK-NEXT: omp.wsloop { ! CHECK-NEXT: omp.loop_nest (%[[ARG1:.*]], %[[ARG2:.*]]) : i32 = (%[[LB1]], %[[LB2]]) to (%[[UB1]], %[[UB2]]) inclusive step (%[[STEP1]], %[[STEP2]]) { - ! CHECK: %[[A_PVT_DECL:.*]]:2 = hlfir.declare %[[A_PVT_REF]] {uniq_name = "_QFomp_do_lastprivate_collapse2Ea"} : (!fir.ref) -> (!fir.ref, !fir.ref) - ! CHECK: %[[I_PVT_DECL:.*]]:2 = hlfir.declare %[[I_PVT_REF]] {uniq_name = "_QFomp_do_lastprivate_collapse2Ei"} : (!fir.ref) -> (!fir.ref, !fir.ref) - ! CHECK: %[[J_PVT_DECL:.*]]:2 = hlfir.declare %[[J_PVT_REF]] {uniq_name = "_QFomp_do_lastprivate_collapse2Ej"} : (!fir.ref) -> (!fir.ref, !fir.ref) - ! CHECK-NEXT: fir.store %[[ARG1]] to %[[I_PVT_DECL]]#1 : !fir.ref ! CHECK-NEXT: fir.store %[[ARG2]] to %[[J_PVT_DECL]]#1 : !fir.ref ! CHECK-NEXT: fir.call @_QPfoo(%[[I_PVT_DECL]]#1, %[[A_PVT_DECL]]#1) {{.*}}: (!fir.ref, !fir.ref) -> () @@ -152,23 +164,29 @@ subroutine omp_do_lastprivate_collapse3(a) !$omp parallel do lastprivate(a) collapse(3) ! CHECK: omp.parallel { + ! CHECK: %[[A_PVT_REF:.*]] = fir.alloca i32 {bindc_name = "a", pinned, uniq_name = "_QFomp_do_lastprivate_collapse3Ea"} + ! CHECK: %[[A_PVT_DECL:.*]]:2 = hlfir.declare %[[A_PVT_REF]] {uniq_name = "_QFomp_do_lastprivate_collapse3Ea"} : (!fir.ref) -> (!fir.ref, !fir.ref) + + ! CHECK: %[[I_PVT_REF:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} + ! CHECK: %[[I_PVT_DECL:.*]]:2 = hlfir.declare %[[I_PVT_REF]] {uniq_name = "_QFomp_do_lastprivate_collapse3Ei"} : (!fir.ref) -> (!fir.ref, !fir.ref) + + ! CHECK: %[[J_PVT_REF:.*]] = fir.alloca i32 {bindc_name = "j", pinned, {{.*}}} + ! CHECK: %[[J_PVT_DECL:.*]]:2 = hlfir.declare %[[J_PVT_REF]] {uniq_name = "_QFomp_do_lastprivate_collapse3Ej"} : (!fir.ref) -> (!fir.ref, !fir.ref) + + ! CHECK: %[[K_PVT_REF:.*]] = fir.alloca i32 {bindc_name = "k", pinned, {{.*}}} + ! CHECK: %[[K_PVT_DECL:.*]]:2 = hlfir.declare %[[K_PVT_REF]] {uniq_name = "_QFomp_do_lastprivate_collapse3Ek"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[LB1:.*]] = arith.constant 1 : i32 - ! CHECK-NEXT: %[[UB1:.*]] = fir.load %[[ARG0_DECL]]#0 : !fir.ref + ! CHECK-NEXT: %[[UB1:.*]] = fir.load %[[A_PVT_DECL]]#0 : !fir.ref ! CHECK-NEXT: %[[STEP1:.*]] = arith.constant 1 : i32 ! CHECK: %[[LB2:.*]] = arith.constant 1 : i32 - ! CHECK-NEXT: %[[UB2:.*]] = fir.load %[[ARG0_DECL]]#0 : !fir.ref + ! CHECK-NEXT: %[[UB2:.*]] = fir.load %[[A_PVT_DECL]]#0 : !fir.ref ! CHECK-NEXT: %[[STEP2:.*]] = arith.constant 1 : i32 ! CHECK: %[[LB3:.*]] = arith.constant 1 : i32 - ! CHECK-NEXT: %[[UB3:.*]] = fir.load %[[ARG0_DECL]]#0 : !fir.ref + ! CHECK-NEXT: %[[UB3:.*]] = fir.load %[[A_PVT_DECL]]#0 : !fir.ref ! CHECK-NEXT: %[[STEP3:.*]] = arith.constant 1 : i32 - ! CHECK-NEXT: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[A_PVT_REF:.*]], @{{.*}} %{{.*}}#0 -> %[[I_PVT_REF:.*]], @{{.*}} %{{.*}}#0 -> %[[J_PVT_REF:.*]], @{{.*}} %{{.*}}#0 -> %[[K_PVT_REF:.*]] : !fir.ref, !fir.ref, !fir.ref, !fir.ref) { + ! CHECK-NEXT: omp.wsloop { ! CHECK-NEXT: omp.loop_nest (%[[ARG1:.*]], %[[ARG2:.*]], %[[ARG3:.*]]) : i32 = (%[[LB1]], %[[LB2]], %[[LB3]]) to (%[[UB1]], %[[UB2]], %[[UB3]]) inclusive step (%[[STEP1]], %[[STEP2]], %[[STEP3]]) { - ! CHECK: %[[A_PVT_DECL:.*]]:2 = hlfir.declare %[[A_PVT_REF]] {uniq_name = "_QFomp_do_lastprivate_collapse3Ea"} : (!fir.ref) -> (!fir.ref, !fir.ref) - ! CHECK: %[[I_PVT_DECL:.*]]:2 = hlfir.declare %[[I_PVT_REF]] {uniq_name = "_QFomp_do_lastprivate_collapse3Ei"} : (!fir.ref) -> (!fir.ref, !fir.ref) - ! CHECK: %[[J_PVT_DECL:.*]]:2 = hlfir.declare %[[J_PVT_REF]] {uniq_name = "_QFomp_do_lastprivate_collapse3Ej"} : (!fir.ref) -> (!fir.ref, !fir.ref) - ! CHECK: %[[K_PVT_DECL:.*]]:2 = hlfir.declare %[[K_PVT_REF]] {uniq_name = "_QFomp_do_lastprivate_collapse3Ek"} : (!fir.ref) -> (!fir.ref, !fir.ref) - ! CHECK-NEXT: fir.store %[[ARG1]] to %[[I_PVT_DECL]]#1 : !fir.ref ! CHECK-NEXT: fir.store %[[ARG2]] to %[[J_PVT_DECL]]#1 : !fir.ref ! CHECK-NEXT: fir.store %[[ARG3]] to %[[K_PVT_DECL]]#1 : !fir.ref diff --git a/flang/test/Lower/OpenMP/parallel-wsloop-reduction-byref.f90 b/flang/test/Lower/OpenMP/parallel-wsloop-reduction-byref.f90 index 3f44f292cb6a0..99c521406a777 100644 --- a/flang/test/Lower/OpenMP/parallel-wsloop-reduction-byref.f90 +++ b/flang/test/Lower/OpenMP/parallel-wsloop-reduction-byref.f90 @@ -4,7 +4,7 @@ ! RUN: flang -fc1 -fopenmp -mmlir --force-byref-reduction -emit-hlfir %s -o - | FileCheck %s ! CHECK: omp.parallel { -! CHECK: omp.wsloop private({{.*}}) reduction(byref @add_reduction_byref_i32 +! CHECK: omp.wsloop reduction(byref @add_reduction_byref_i32 subroutine sb integer :: x x = 0 diff --git a/flang/test/Lower/OpenMP/parallel-wsloop-reduction.f90 b/flang/test/Lower/OpenMP/parallel-wsloop-reduction.f90 index a206eef52da5a..cfeb5de83f4e8 100644 --- a/flang/test/Lower/OpenMP/parallel-wsloop-reduction.f90 +++ b/flang/test/Lower/OpenMP/parallel-wsloop-reduction.f90 @@ -4,7 +4,7 @@ ! RUN: flang -fc1 -fopenmp -emit-hlfir %s -o - | FileCheck %s ! CHECK: omp.parallel { -! CHECK: omp.wsloop private({{.*}}) reduction(@add_reduction_i32 +! CHECK: omp.wsloop reduction(@add_reduction_i32 subroutine sb integer :: x x = 0 diff --git a/flang/test/Lower/OpenMP/parallel-wsloop.f90 b/flang/test/Lower/OpenMP/parallel-wsloop.f90 index 7116069e8daa6..cba5209f85989 100644 --- a/flang/test/Lower/OpenMP/parallel-wsloop.f90 +++ b/flang/test/Lower/OpenMP/parallel-wsloop.f90 @@ -10,7 +10,7 @@ subroutine simple_parallel_do ! CHECK: %[[WS_LB:.*]] = arith.constant 1 : i32 ! CHECK: %[[WS_UB:.*]] = arith.constant 9 : i32 ! CHECK: %[[WS_STEP:.*]] = arith.constant 1 : i32 - ! CHECK: omp.wsloop private({{.*}}) { + ! CHECK: omp.wsloop { ! CHECK-NEXT: omp.loop_nest (%[[I:.*]]) : i32 = (%[[WS_LB]]) to (%[[WS_UB]]) inclusive step (%[[WS_STEP]]) { !$OMP PARALLEL DO do i=1, 9 @@ -39,7 +39,7 @@ subroutine parallel_do_with_parallel_clauses(cond, nt) ! CHECK: %[[WS_LB:.*]] = arith.constant 1 : i32 ! CHECK: %[[WS_UB:.*]] = arith.constant 9 : i32 ! CHECK: %[[WS_STEP:.*]] = arith.constant 1 : i32 - ! CHECK: omp.wsloop private({{.*}}) { + ! CHECK: omp.wsloop { ! CHECK-NEXT: omp.loop_nest (%[[I:.*]]) : i32 = (%[[WS_LB]]) to (%[[WS_UB]]) inclusive step (%[[WS_STEP]]) { !$OMP PARALLEL DO IF(cond) NUM_THREADS(nt) PROC_BIND(close) do i=1, 9 @@ -64,7 +64,7 @@ subroutine parallel_do_with_clauses(nt) ! CHECK: %[[WS_LB:.*]] = arith.constant 1 : i32 ! CHECK: %[[WS_UB:.*]] = arith.constant 9 : i32 ! CHECK: %[[WS_STEP:.*]] = arith.constant 1 : i32 - ! CHECK: omp.wsloop schedule(dynamic) private({{.*}}) { + ! CHECK: omp.wsloop schedule(dynamic) { ! CHECK-NEXT: omp.loop_nest (%[[I:.*]]) : i32 = (%[[WS_LB]]) to (%[[WS_UB]]) inclusive step (%[[WS_STEP]]) { !$OMP PARALLEL DO NUM_THREADS(nt) SCHEDULE(dynamic) do i=1, 9 @@ -92,16 +92,19 @@ subroutine parallel_do_with_privatisation_clauses(cond,nt) integer :: nt integer :: i ! CHECK: omp.parallel - + ! CHECK: %[[PRIVATE_COND_REF:.*]] = fir.alloca !fir.logical<4> {bindc_name = "cond", pinned, uniq_name = "_QFparallel_do_with_privatisation_clausesEcond"} + ! CHECK: %[[PRIVATE_COND_DECL:.*]]:2 = hlfir.declare %[[PRIVATE_COND_REF]] {uniq_name = "_QFparallel_do_with_privatisation_clausesEcond"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) + ! CHECK: %[[PRIVATE_NT_REF:.*]] = fir.alloca i32 {bindc_name = "nt", pinned, uniq_name = "_QFparallel_do_with_privatisation_clausesEnt"} + ! CHECK: %[[PRIVATE_NT_DECL:.*]]:2 = hlfir.declare %[[PRIVATE_NT_REF]] {uniq_name = "_QFparallel_do_with_privatisation_clausesEnt"} : (!fir.ref) -> (!fir.ref, !fir.ref) + ! CHECK: %[[NT_VAL:.*]] = fir.load %[[NT_DECL]]#0 : !fir.ref + ! CHECK: hlfir.assign %[[NT_VAL]] to %[[PRIVATE_NT_DECL]]#0 : i32, !fir.ref ! CHECK: %[[WS_LB:.*]] = arith.constant 1 : i32 ! CHECK: %[[WS_UB:.*]] = arith.constant 9 : i32 ! CHECK: %[[WS_STEP:.*]] = arith.constant 1 : i32 - ! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[PRIVATE_COND_REF:.*]], @{{.*}} %{{.*}}#0 -> %[[PRIVATE_NT_REF:.*]], @{{.*}} %3#0 -> %{{.*}} : !fir.ref>, !fir.ref, !fir.ref) { + ! CHECK: omp.wsloop { ! CHECK-NEXT: omp.loop_nest (%[[I:.*]]) : i32 = (%[[WS_LB]]) to (%[[WS_UB]]) inclusive step (%[[WS_STEP]]) { !$OMP PARALLEL DO PRIVATE(cond) FIRSTPRIVATE(nt) do i=1, 9 - ! CHECK: %[[PRIVATE_COND_DECL:.*]]:2 = hlfir.declare %[[PRIVATE_COND_REF]] {uniq_name = "_QFparallel_do_with_privatisation_clausesEcond"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) - ! CHECK: %[[PRIVATE_NT_DECL:.*]]:2 = hlfir.declare %[[PRIVATE_NT_REF]] {uniq_name = "_QFparallel_do_with_privatisation_clausesEnt"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: fir.store %[[I]] to %[[IV_ADDR:.*]]#1 : !fir.ref ! CHECK: %[[LOAD_IV:.*]] = fir.load %[[IV_ADDR]]#0 : !fir.ref ! CHECK: fir.call @_FortranAioOutputInteger32({{.*}}, %[[LOAD_IV]]) {{.*}}: (!fir.ref, i32) -> i1 @@ -146,12 +149,14 @@ end subroutine parallel_private_do ! CHECK: %[[NT_PRIV_DECL:.*]]:2 = hlfir.declare %[[NT_PRIV_ADDR]] {uniq_name = "_QFparallel_private_doEnt"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %[[I_PRIV:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[I_PRIV_DECL:.*]]:2 = hlfir.declare %[[I_PRIV]] {uniq_name = "_QFparallel_private_doEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) + ! CHECK: %[[VAL_7:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_8:.*]] = arith.constant 9 : i32 ! CHECK: %[[VAL_9:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[I_PRIV:.*]] : !fir.ref) { +! CHECK: omp.wsloop { ! CHECK-NEXT: omp.loop_nest (%[[I:.*]]) : i32 = (%[[VAL_7]]) to (%[[VAL_8]]) inclusive step (%[[VAL_9]]) { -! CHECK: %[[I_PRIV_DECL:.*]]:2 = hlfir.declare %[[I_PRIV]] {uniq_name = "_QFparallel_private_doEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: fir.store %[[I]] to %[[I_PRIV_DECL]]#1 : !fir.ref ! CHECK: fir.call @_QPfoo(%[[I_PRIV_DECL]]#1, %[[COND_DECL]]#1, %[[NT_PRIV_DECL]]#1) {{.*}}: (!fir.ref, !fir.ref>, !fir.ref) -> () ! CHECK: omp.yield @@ -190,13 +195,14 @@ end subroutine omp_parallel_multiple_firstprivate_do ! CHECK: %[[B_PRIV_DECL:.*]]:2 = hlfir.declare %[[B_PRIV_ADDR]] {uniq_name = "_QFomp_parallel_multiple_firstprivate_doEb"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %[[I_PRIV_ADDR:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[I_PRIV_DECL:.*]]:2 = hlfir.declare %[[I_PRIV_ADDR]] {uniq_name = "_QFomp_parallel_multiple_firstprivate_doEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_8:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_9:.*]] = arith.constant 10 : i32 ! CHECK: %[[VAL_10:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[I_PRIV_ADDR:.*]] : !fir.ref) { +! CHECK: omp.wsloop { ! CHECK-NEXT: omp.loop_nest (%[[I:.*]]) : i32 = (%[[VAL_8]]) to (%[[VAL_9]]) inclusive step (%[[VAL_10]]) { -! CHECK: %[[I_PRIV_DECL:.*]]:2 = hlfir.declare %[[I_PRIV_ADDR]] {uniq_name = "_QFomp_parallel_multiple_firstprivate_doEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: fir.store %[[I]] to %[[I_PRIV_DECL]]#1 : !fir.ref ! CHECK: fir.call @_QPbar(%[[I_PRIV_DECL]]#1, %[[A_PRIV_DECL]]#1) {{.*}}: (!fir.ref, !fir.ref) -> () ! CHECK: omp.yield @@ -231,15 +237,23 @@ end subroutine parallel_do_private ! CHECK-SAME: %[[VAL_1:.*]]: !fir.ref {fir.bindc_name = "nt"}) { ! CHECK: %[[NT_DECL:.*]]:2 = hlfir.declare %[[VAL_1]] dummy_scope %{{[0-9]+}} {uniq_name = "_QFparallel_do_privateEnt"} : (!fir.ref, !fir.dscope) -> (!fir.ref, !fir.ref) ! CHECK: omp.parallel { + +! CHECK: %[[COND_PRIV_ADDR:.*]] = fir.alloca !fir.logical<4> {bindc_name = "cond", pinned, uniq_name = "_QFparallel_do_privateEcond"} +! CHECK: %[[COND_PRIV_DECL:.*]]:2 = hlfir.declare %[[COND_PRIV_ADDR]] {uniq_name = "_QFparallel_do_privateEcond"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) + +! CHECK: %[[NT_PRIV_ADDR:.*]] = fir.alloca i32 {bindc_name = "nt", pinned, uniq_name = "_QFparallel_do_privateEnt"} +! CHECK: %[[NT_PRIV_DECL:.*]]:2 = hlfir.declare %[[NT_PRIV_ADDR]] {uniq_name = "_QFparallel_do_privateEnt"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %[[NT_VAL:.*]] = fir.load %[[NT_DECL]]#0 : !fir.ref +! CHECK: hlfir.assign %[[NT_VAL]] to %[[NT_PRIV_DECL]]#0 : i32, !fir.ref + +! CHECK: %[[I_PRIV_ADDR:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[I_PRIV_DECL:.*]]:2 = hlfir.declare %[[I_PRIV_ADDR]] {uniq_name = "_QFparallel_do_privateEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) + ! CHECK: %[[VAL_7:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_8:.*]] = arith.constant 9 : i32 ! CHECK: %[[VAL_9:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[COND_PRIV_ADDR:.*]], @{{.*}} %{{.*}}#0 -> %[[NT_PRIV_ADDR:.*]], @{{.*}} %3#0 -> %[[I_PRIV_ADDR:.*]] : !fir.ref>, !fir.ref, !fir.ref) { +! CHECK: omp.wsloop { ! CHECK-NEXT: omp.loop_nest (%[[I:.*]]) : i32 = (%[[VAL_7]]) to (%[[VAL_8]]) inclusive step (%[[VAL_9]]) { -! CHECK: %[[COND_PRIV_DECL:.*]]:2 = hlfir.declare %[[COND_PRIV_ADDR]] {uniq_name = "_QFparallel_do_privateEcond"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) -! CHECK: %[[NT_PRIV_DECL:.*]]:2 = hlfir.declare %[[NT_PRIV_ADDR]] {uniq_name = "_QFparallel_do_privateEnt"} : (!fir.ref) -> (!fir.ref, !fir.ref) -! CHECK: %[[I_PRIV_DECL:.*]]:2 = hlfir.declare %[[I_PRIV_ADDR]] {uniq_name = "_QFparallel_do_privateEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) - ! CHECK: fir.store %[[I]] to %[[I_PRIV_DECL]]#1 : !fir.ref ! CHECK: fir.call @_QPfoo(%[[I_PRIV_DECL]]#1, %[[COND_PRIV_DECL]]#1, %[[NT_PRIV_DECL]]#1) {{.*}}: (!fir.ref, !fir.ref>, !fir.ref) -> () ! CHECK: omp.yield @@ -273,15 +287,25 @@ end subroutine omp_parallel_do_multiple_firstprivate ! CHECK: %[[A_DECL:.*]]:2 = hlfir.declare %[[A_ADDR]] dummy_scope %{{[0-9]+}} {uniq_name = "_QFomp_parallel_do_multiple_firstprivateEa"} : (!fir.ref, !fir.dscope) -> (!fir.ref, !fir.ref) ! CHECK: %[[B_DECL:.*]]:2 = hlfir.declare %[[B_ADDR]] dummy_scope %{{[0-9]+}} {uniq_name = "_QFomp_parallel_do_multiple_firstprivateEb"} : (!fir.ref, !fir.dscope) -> (!fir.ref, !fir.ref ! CHECK: omp.parallel { + +! CHECK: %[[A_PRIV_ADDR:.*]] = fir.alloca i32 {bindc_name = "a", pinned, uniq_name = "_QFomp_parallel_do_multiple_firstprivateEa"} +! CHECK: %[[A_PRIV_DECL:.*]]:2 = hlfir.declare %[[A_PRIV_ADDR]] {uniq_name = "_QFomp_parallel_do_multiple_firstprivateEa"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %[[A:.*]] = fir.load %[[A_DECL]]#0 : !fir.ref +! CHECK: hlfir.assign %[[A]] to %[[A_PRIV_DECL]]#0 : i32, !fir.ref + +! CHECK: %[[B_PRIV_ADDR:.*]] = fir.alloca i32 {bindc_name = "b", pinned, uniq_name = "_QFomp_parallel_do_multiple_firstprivateEb"} +! CHECK: %[[B_PRIV_DECL:.*]]:2 = hlfir.declare %[[B_PRIV_ADDR]] {uniq_name = "_QFomp_parallel_do_multiple_firstprivateEb"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %[[B:.*]] = fir.load %[[B_DECL]]#0 : !fir.ref +! CHECK: hlfir.assign %[[B]] to %[[B_PRIV_DECL]]#0 : i32, !fir.ref + +! CHECK: %[[I_PRIV_ADDR:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[I_PRIV_DECL:.*]]:2 = hlfir.declare %[[I_PRIV_ADDR]] {uniq_name = "_QFomp_parallel_do_multiple_firstprivateEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) + ! CHECK: %[[VAL_8:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_9:.*]] = arith.constant 10 : i32 ! CHECK: %[[VAL_10:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[A_PRIV_ADDR:.*]], @{{.*}} %{{.}}#0 -> %[[B_PRIV_ADDR:.*]], @{{.*}} %{{.}}#0 -> %[[I_PRIV_ADDR:.*]] : !fir.ref, !fir.ref, !fir.ref) { +! CHECK: omp.wsloop { ! CHECK-NEXT: omp.loop_nest (%[[I:.*]]) : i32 = (%[[VAL_8]]) to (%[[VAL_9]]) inclusive step (%[[VAL_10]]) { -! CHECK: %[[A_PRIV_DECL:.*]]:2 = hlfir.declare %[[A_PRIV_ADDR]] {uniq_name = "_QFomp_parallel_do_multiple_firstprivateEa"} : (!fir.ref) -> (!fir.ref, !fir.ref) -! CHECK: %[[B_PRIV_DECL:.*]]:2 = hlfir.declare %[[B_PRIV_ADDR]] {uniq_name = "_QFomp_parallel_do_multiple_firstprivateEb"} : (!fir.ref) -> (!fir.ref, !fir.ref) -! CHECK: %[[I_PRIV_DECL:.*]]:2 = hlfir.declare %[[I_PRIV_ADDR]] {uniq_name = "_QFomp_parallel_do_multiple_firstprivateEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) - ! CHECK: fir.store %[[I]] to %[[I_PRIV_DECL]]#1 : !fir.ref ! CHECK: fir.call @_QPbar(%[[I_PRIV_DECL]]#1, %[[A_PRIV_DECL]]#1) {{.*}}: (!fir.ref, !fir.ref) -> () ! CHECK: omp.yield diff --git a/flang/test/Lower/OpenMP/private-derived-type.f90 b/flang/test/Lower/OpenMP/private-derived-type.f90 index 7e0a3f14639f6..df1c7c3f92227 100644 --- a/flang/test/Lower/OpenMP/private-derived-type.f90 +++ b/flang/test/Lower/OpenMP/private-derived-type.f90 @@ -1,5 +1,5 @@ -! RUN: %flang_fc1 -emit-hlfir -fopenmp -o - %s | FileCheck %s -! RUN: bbc -emit-hlfir -fopenmp -o - %s | FileCheck %s +! RUN: %flang_fc1 -emit-hlfir -fopenmp -mmlir --openmp-enable-delayed-privatization-staging=true -o - %s | FileCheck %s +! RUN: bbc -emit-hlfir -fopenmp --openmp-enable-delayed-privatization-staging=true -o - %s | FileCheck %s subroutine s4 type y3 diff --git a/flang/test/Lower/OpenMP/same_var_first_lastprivate.f90 b/flang/test/Lower/OpenMP/same_var_first_lastprivate.f90 index c49a0908b721e..e8e4a0802e00d 100644 --- a/flang/test/Lower/OpenMP/same_var_first_lastprivate.f90 +++ b/flang/test/Lower/OpenMP/same_var_first_lastprivate.f90 @@ -1,4 +1,4 @@ -! RUN: %flang_fc1 -fopenmp -emit-hlfir %s -o - | FileCheck %s +! RUN: %flang_fc1 -fopenmp -mmlir --openmp-enable-delayed-privatization-staging=true -emit-hlfir %s -o - | FileCheck %s subroutine first_and_lastprivate integer i diff --git a/flang/test/Lower/OpenMP/stop-stmt-in-region.f90 b/flang/test/Lower/OpenMP/stop-stmt-in-region.f90 index d817c4e771b31..f174caa7fa4fd 100644 --- a/flang/test/Lower/OpenMP/stop-stmt-in-region.f90 +++ b/flang/test/Lower/OpenMP/stop-stmt-in-region.f90 @@ -80,13 +80,14 @@ subroutine test_stop_in_region3() ! CHECK: %[[VAL_2:.*]] = fir.alloca i32 {bindc_name = "x", uniq_name = "_QFtest_stop_in_region4Ex"} ! CHECK: %[[VAL_2_DECL:.*]]:2 = hlfir.declare %[[VAL_2]] {uniq_name = "_QFtest_stop_in_region4Ex"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %[[VAL_0:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_0_DECL:.*]]:2 = hlfir.declare %[[VAL_0]] {uniq_name = "_QFtest_stop_in_region4Ei"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_3:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_4:.*]] = arith.constant 10 : i32 ! CHECK: %[[VAL_5:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_0:.*]] : !fir.ref) { +! CHECK: omp.wsloop { ! CHECK-NEXT: omp.loop_nest (%[[VAL_6:.*]]) : i32 = (%[[VAL_3]]) to (%[[VAL_4]]) inclusive step (%[[VAL_5]]) { -! CHECK: %[[VAL_0_DECL:.*]]:2 = hlfir.declare %[[VAL_0]] {uniq_name = "_QFtest_stop_in_region4Ei"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: fir.store %[[VAL_6]] to %[[VAL_0_DECL]]#1 : !fir.ref ! CHECK: cf.br ^bb1 ! CHECK: ^bb1: diff --git a/flang/test/Lower/OpenMP/target.f90 b/flang/test/Lower/OpenMP/target.f90 index bf801e69405b9..04764be2293c1 100644 --- a/flang/test/Lower/OpenMP/target.f90 +++ b/flang/test/Lower/OpenMP/target.f90 @@ -586,10 +586,11 @@ subroutine omp_target_parallel_do !CHECK: %[[VAL_0_DECL:.*]]:2 = hlfir.declare %[[ARG_0]](%{{.*}}) {uniq_name = "_QFomp_target_parallel_doEa"} : (!fir.ref>, !fir.shape<1>) -> (!fir.ref>, !fir.ref>) !CHECK: omp.parallel !$omp target parallel do map(tofrom: a) - !CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[I_PVT_ALLOCA:.*]] : !fir.ref) { + !CHECK: %[[I_PVT_ALLOCA:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} + !CHECK: %[[I_PVT_DECL:.*]]:2 = hlfir.declare %[[I_PVT_ALLOCA]] {uniq_name = "_QFomp_target_parallel_doEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) + !CHECK: omp.wsloop { !CHECK-NEXT: omp.loop_nest (%[[I_VAL:.*]]) : i32 do i = 1, 1024 - !CHECK: %[[I_PVT_DECL:.*]]:2 = hlfir.declare %[[I_PVT_ALLOCA]] {uniq_name = "_QFomp_target_parallel_doEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) !CHECK: fir.store %[[I_VAL]] to %[[I_PVT_DECL]]#1 : !fir.ref !CHECK: %[[C10:.*]] = arith.constant 10 : i32 !CHECK: %[[I_PVT_VAL:.*]] = fir.load %[[I_PVT_DECL]]#0 : !fir.ref diff --git a/flang/test/Lower/OpenMP/unstructured.f90 b/flang/test/Lower/OpenMP/unstructured.f90 index a9925a484eb1c..a0955c8440c1c 100644 --- a/flang/test/Lower/OpenMP/unstructured.f90 +++ b/flang/test/Lower/OpenMP/unstructured.f90 @@ -69,9 +69,10 @@ subroutine ss2(n) ! unstructured OpenMP construct; loop exit inside construct ! CHECK: cond_br %{{[0-9]*}}, ^bb2, ^bb4 ! CHECK: ^bb2: // pred: ^bb1 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[ALLOCA_2:.*]] : !fir.ref) { +! CHECK: %[[ALLOCA_2:.*]] = fir.alloca i32 {{{.*}}, pinned, {{.*}}} +! CHECK: %[[OMP_LOOP_K_DECL:.*]]:2 = hlfir.declare %[[ALLOCA_2]] {uniq_name = "_QFss3Ek"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: omp.wsloop { ! CHECK: omp.loop_nest (%[[ARG1:.*]]) : {{.*}} { -! CHECK: %[[OMP_LOOP_K_DECL:.*]]:2 = hlfir.declare %[[ALLOCA_2]] {uniq_name = "_QFss3Ek"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: fir.store %[[ARG1]] to %[[OMP_LOOP_K_DECL]]#1 : !fir.ref ! CHECK: @_FortranAioBeginExternalListOutput ! CHECK: %[[LOAD_1:.*]] = fir.load %[[OMP_LOOP_K_DECL]]#0 : !fir.ref @@ -80,9 +81,11 @@ subroutine ss2(n) ! unstructured OpenMP construct; loop exit inside construct ! CHECK: } ! CHECK: } -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[ALLOCA_1:.*]] : !fir.ref) { +! CHECK: %[[ALLOCA_1:.*]] = fir.alloca i32 {{{.*}}, pinned, {{.*}}} +! CHECK: %[[OMP_LOOP_J_DECL:.*]]:2 = hlfir.declare %[[ALLOCA_1]] {uniq_name = "_QFss3Ej"} : (!fir.ref) -> (!fir.ref, !fir.ref) + +! CHECK: omp.wsloop { ! CHECK: omp.loop_nest (%[[ARG2:.*]]) : {{.*}} { -! CHECK: %[[OMP_LOOP_J_DECL:.*]]:2 = hlfir.declare %[[ALLOCA_1]] {uniq_name = "_QFss3Ej"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: fir.store %[[ARG2]] to %[[OMP_LOOP_J_DECL]]#1 : !fir.ref ! CHECK: br ^bb1 ! CHECK: ^bb2: // 2 preds: ^bb1, ^bb5 @@ -125,9 +128,10 @@ subroutine ss3(n) ! nested unstructured OpenMP constructs ! CHECK-LABEL: func @_QPss4{{.*}} { ! CHECK: omp.parallel private(@{{.*}} %{{.*}}#0 -> %{{.*}} : {{.*}}) { -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[ALLOCA:.*]] : !fir.ref) { +! CHECK: %[[ALLOCA:.*]] = fir.alloca i32 {{{.*}}, pinned, uniq_name = "_QFss4Ej"} +! CHECK: %[[OMP_LOOP_J_DECL:.*]]:2 = hlfir.declare %[[ALLOCA]] {uniq_name = "_QFss4Ej"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: omp.wsloop { ! CHECK-NEXT: omp.loop_nest (%[[ARG:.*]]) : {{.*}} { -! CHECK: %[[OMP_LOOP_J_DECL:.*]]:2 = hlfir.declare %[[ALLOCA]] {uniq_name = "_QFss4Ej"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: fir.store %[[ARG]] to %[[OMP_LOOP_J_DECL]]#1 : !fir.ref ! CHECK: %[[COND:.*]] = arith.cmpi eq, %{{.*}}, %{{.*}} ! CHECK: %[[COND_XOR:.*]] = arith.xori %[[COND]], %{{.*}} @@ -156,7 +160,7 @@ subroutine ss4(n) ! CYCLE in OpenMP wsloop constructs ! CHECK-LABEL: func @_QPss5() { ! CHECK: omp.parallel private(@{{.*}} %{{.*}}#0 -> %{{.*}} : {{.*}}) { -! CHECK: omp.wsloop private({{.*}}) { +! CHECK: omp.wsloop { ! CHECK: omp.loop_nest {{.*}} { ! CHECK: br ^[[BB1:.*]] ! CHECK: ^[[BB1]]: @@ -198,7 +202,7 @@ subroutine ss5() ! EXIT inside OpenMP wsloop (inside parallel) ! CHECK: ^[[BB1_OUTER]]: ! CHECK: cond_br %{{.*}}, ^[[BB2_OUTER:.*]], ^[[BB3_OUTER:.*]] ! CHECK: ^[[BB2_OUTER]]: -! CHECK: omp.wsloop private({{.*}}) { +! CHECK: omp.wsloop { ! CHECK: omp.loop_nest {{.*}} { ! CHECK: br ^[[BB1:.*]] ! CHECK: ^[[BB1]]: @@ -244,7 +248,7 @@ subroutine ss6() ! EXIT inside OpenMP wsloop in a do loop (inside parallel) ! CHECK: cond_br %{{.*}}, ^[[BB2_OUTER:.*]], ^[[BB3_OUTER:.*]] ! CHECK-NEXT: ^[[BB2_OUTER:.*]]: ! CHECK: omp.parallel { -! CHECK: omp.wsloop private({{.*}}) { +! CHECK: omp.wsloop { ! CHECK: omp.loop_nest {{.*}} { ! CHECK: br ^[[BB1:.*]] ! CHECK-NEXT: ^[[BB1]]: @@ -284,7 +288,7 @@ subroutine ss7() ! EXIT inside OpenMP parallel do (inside do loop) ! CHECK-LABEL: func @_QPss8() { ! CHECK: omp.parallel { -! CHECK: omp.wsloop private({{.*}}) { +! CHECK: omp.wsloop { ! CHECK: omp.loop_nest {{.*}} { ! CHECK: br ^[[BB1:.*]] ! CHECK-NEXT: ^[[BB1]]: diff --git a/flang/test/Lower/OpenMP/wsloop-chunks.f90 b/flang/test/Lower/OpenMP/wsloop-chunks.f90 index 0a2b962761acb..0fb7d6f1b64fa 100644 --- a/flang/test/Lower/OpenMP/wsloop-chunks.f90 +++ b/flang/test/Lower/OpenMP/wsloop-chunks.f90 @@ -20,7 +20,7 @@ program wsloop ! CHECK: %[[VAL_3:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_4:.*]] = arith.constant 9 : i32 ! CHECK: %[[VAL_5:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop nowait schedule(static = %[[VAL_2]] : i32) private({{.*}}) { +! CHECK: omp.wsloop nowait schedule(static = %[[VAL_2]] : i32) { ! CHECK-NEXT: omp.loop_nest (%[[ARG0:.*]]) : i32 = (%[[VAL_3]]) to (%[[VAL_4]]) inclusive step (%[[VAL_5]]) { ! CHECK: fir.store %[[ARG0]] to %[[STORE_IV:.*]]#1 : !fir.ref ! CHECK: %[[LOAD_IV:.*]] = fir.load %[[STORE_IV]]#0 : !fir.ref @@ -40,7 +40,7 @@ program wsloop ! CHECK: %[[VAL_15:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_16:.*]] = arith.constant 9 : i32 ! CHECK: %[[VAL_17:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop nowait schedule(static = %[[VAL_14]] : i32) private({{.*}}) { +! CHECK: omp.wsloop nowait schedule(static = %[[VAL_14]] : i32) { ! CHECK-NEXT: omp.loop_nest (%[[ARG1:.*]]) : i32 = (%[[VAL_15]]) to (%[[VAL_16]]) inclusive step (%[[VAL_17]]) { ! CHECK: fir.store %[[ARG1]] to %[[STORE_IV1:.*]]#1 : !fir.ref ! CHECK: %[[VAL_24:.*]] = arith.constant 2 : i32 @@ -66,7 +66,7 @@ program wsloop ! CHECK: %[[VAL_30:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_31:.*]] = arith.constant 9 : i32 ! CHECK: %[[VAL_32:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop nowait schedule(static = %[[VAL_29]] : i32) private({{.*}}) { +! CHECK: omp.wsloop nowait schedule(static = %[[VAL_29]] : i32) { ! CHECK-NEXT: omp.loop_nest (%[[ARG2:.*]]) : i32 = (%[[VAL_30]]) to (%[[VAL_31]]) inclusive step (%[[VAL_32]]) { ! CHECK: fir.store %[[ARG2]] to %[[STORE_IV2:.*]]#1 : !fir.ref ! CHECK: %[[VAL_39:.*]] = arith.constant 3 : i32 diff --git a/flang/test/Lower/OpenMP/wsloop-collapse.f90 b/flang/test/Lower/OpenMP/wsloop-collapse.f90 index 6d9862e625400..61ee76d589107 100644 --- a/flang/test/Lower/OpenMP/wsloop-collapse.f90 +++ b/flang/test/Lower/OpenMP/wsloop-collapse.f90 @@ -38,6 +38,15 @@ program wsloop_collapse !CHECK: %[[VAL_23:.*]] = arith.constant 0 : i32 !CHECK: hlfir.assign %[[VAL_23]] to %[[VAL_19]]#0 : i32, !fir.ref +!CHECK: %[[VAL_4:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +!CHECK: %[[VAL_5:.*]]:2 = hlfir.declare %[[VAL_4]] {uniq_name = "_QFEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) + +!CHECK: %[[VAL_2:.*]] = fir.alloca i32 {bindc_name = "j", pinned, {{.*}}} +!CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_2]] {uniq_name = "_QFEj"} : (!fir.ref) -> (!fir.ref, !fir.ref) + +!CHECK: %[[VAL_0:.*]] = fir.alloca i32 {bindc_name = "k", pinned, {{.*}}} +!CHECK: %[[VAL_1:.*]]:2 = hlfir.declare %[[VAL_0]] {uniq_name = "_QFEk"} : (!fir.ref) -> (!fir.ref, !fir.ref) + integer :: i, j, k integer :: a, b, c integer :: x @@ -56,17 +65,12 @@ program wsloop_collapse !CHECK: %[[VAL_30:.*]] = arith.constant 1 : i32 !CHECK: %[[VAL_31:.*]] = fir.load %[[VAL_11]]#0 : !fir.ref !CHECK: %[[VAL_32:.*]] = arith.constant 1 : i32 -!CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_4:.*]], @{{.*}} %{{.*}}#0 -> %[[VAL_2:.*]], @{{.*}} %{{.*}}#0 -> %[[VAL_0:.*]] : !fir.ref, !fir.ref, !fir.ref) { +!CHECK: omp.wsloop { !CHECK-NEXT: omp.loop_nest (%[[VAL_33:.*]], %[[VAL_34:.*]], %[[VAL_35:.*]]) : i32 = (%[[VAL_24]], %[[VAL_27]], %[[VAL_30]]) to (%[[VAL_25]], %[[VAL_28]], %[[VAL_31]]) inclusive step (%[[VAL_26]], %[[VAL_29]], %[[VAL_32]]) { !$omp do collapse(3) do i = 1, a do j= 1, b do k = 1, c - -!CHECK: %[[VAL_5:.*]]:2 = hlfir.declare %[[VAL_4]] {uniq_name = "_QFEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) -!CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_2]] {uniq_name = "_QFEj"} : (!fir.ref) -> (!fir.ref, !fir.ref) -!CHECK: %[[VAL_1:.*]]:2 = hlfir.declare %[[VAL_0]] {uniq_name = "_QFEk"} : (!fir.ref) -> (!fir.ref, !fir.ref) - !CHECK: fir.store %[[VAL_33]] to %[[VAL_5]]#1 : !fir.ref !CHECK: fir.store %[[VAL_34]] to %[[VAL_3]]#1 : !fir.ref !CHECK: fir.store %[[VAL_35]] to %[[VAL_1]]#1 : !fir.ref diff --git a/flang/test/Lower/OpenMP/wsloop-monotonic.f90 b/flang/test/Lower/OpenMP/wsloop-monotonic.f90 index e21aa4c678f42..9659fff2d42e7 100644 --- a/flang/test/Lower/OpenMP/wsloop-monotonic.f90 +++ b/flang/test/Lower/OpenMP/wsloop-monotonic.f90 @@ -11,10 +11,11 @@ program wsloop_dynamic !CHECK: omp.parallel { !$OMP DO SCHEDULE(monotonic:dynamic) +!CHECK: %[[ALLOCA_IV:.*]] = fir.alloca i32 {{{.*}}, pinned, {{.*}}} !CHECK: %[[WS_LB:.*]] = arith.constant 1 : i32 !CHECK: %[[WS_UB:.*]] = arith.constant 9 : i32 !CHECK: %[[WS_STEP:.*]] = arith.constant 1 : i32 -!CHECK: omp.wsloop nowait schedule(dynamic, monotonic) private({{.*}}) { +!CHECK: omp.wsloop nowait schedule(dynamic, monotonic) { !CHECK-NEXT: omp.loop_nest (%[[I:.*]]) : i32 = (%[[WS_LB]]) to (%[[WS_UB]]) inclusive step (%[[WS_STEP]]) { !CHECK: fir.store %[[I]] to %[[ALLOCA_IV:.*]]#1 : !fir.ref diff --git a/flang/test/Lower/OpenMP/wsloop-nonmonotonic.f90 b/flang/test/Lower/OpenMP/wsloop-nonmonotonic.f90 index 23d3c49c00786..b1bea525ff489 100644 --- a/flang/test/Lower/OpenMP/wsloop-nonmonotonic.f90 +++ b/flang/test/Lower/OpenMP/wsloop-nonmonotonic.f90 @@ -12,12 +12,13 @@ program wsloop_dynamic !CHECK: omp.parallel { !$OMP DO SCHEDULE(nonmonotonic:dynamic) +!CHECK: %[[I_REF:.*]] = fir.alloca i32 {{{.*}}, pinned, {{.*}}} +!CHECK: %[[ALLOCA_IV:.*]]:2 = hlfir.declare %[[I_REF]] {uniq_name = "_QFEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) !CHECK: %[[WS_LB:.*]] = arith.constant 1 : i32 !CHECK: %[[WS_UB:.*]] = arith.constant 9 : i32 !CHECK: %[[WS_STEP:.*]] = arith.constant 1 : i32 -!CHECK: omp.wsloop nowait schedule(dynamic, nonmonotonic) private(@{{.*}} %{{.*}}#0 -> %[[I_REF:.*]] : !fir.ref) { +!CHECK: omp.wsloop nowait schedule(dynamic, nonmonotonic) { !CHECK-NEXT: omp.loop_nest (%[[I:.*]]) : i32 = (%[[WS_LB]]) to (%[[WS_UB]]) inclusive step (%[[WS_STEP]]) { -!CHECK: %[[ALLOCA_IV:.*]]:2 = hlfir.declare %[[I_REF]] {uniq_name = "_QFEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) !CHECK: fir.store %[[I]] to %[[ALLOCA_IV]]#1 : !fir.ref do i=1, 9 diff --git a/flang/test/Lower/OpenMP/wsloop-ordered.f90 b/flang/test/Lower/OpenMP/wsloop-ordered.f90 index 4862b7296a9bc..5fa53f7b28447 100644 --- a/flang/test/Lower/OpenMP/wsloop-ordered.f90 +++ b/flang/test/Lower/OpenMP/wsloop-ordered.f90 @@ -6,7 +6,7 @@ subroutine wsloop_ordered_no_para() integer :: a(10), i -! CHECK: omp.wsloop ordered(0) private({{.*}}) { +! CHECK: omp.wsloop ordered(0) { ! CHECK-NEXT: omp.loop_nest (%{{.*}}) : i32 = (%{{.*}}) to (%{{.*}}) inclusive step (%{{.*}}) { ! CHECK: omp.yield ! CHECK: } @@ -27,7 +27,7 @@ subroutine wsloop_ordered_with_para() integer :: a(10), i ! CHECK: func @_QPwsloop_ordered_with_para() { -! CHECK: omp.wsloop ordered(1) private({{.*}}) { +! CHECK: omp.wsloop ordered(1) { ! CHECK-NEXT: omp.loop_nest (%{{.*}}) : i32 = (%{{.*}}) to (%{{.*}}) inclusive step (%{{.*}}) { ! CHECK: omp.yield ! CHECK: } diff --git a/flang/test/Lower/OpenMP/wsloop-reduction-add-byref.f90 b/flang/test/Lower/OpenMP/wsloop-reduction-add-byref.f90 index bc021e7a3b273..c38a79191bc4e 100644 --- a/flang/test/Lower/OpenMP/wsloop-reduction-add-byref.f90 +++ b/flang/test/Lower/OpenMP/wsloop-reduction-add-byref.f90 @@ -85,12 +85,13 @@ ! CHECK: %[[VAL_4:.*]] = arith.constant 0 : i32 ! CHECK: hlfir.assign %[[VAL_4]] to %[[VAL_3]]#0 : i32, !fir.ref ! CHECK: omp.parallel { +! CHECK: %[[VAL_5:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_5]] {uniq_name = "_QFsimple_int_reductionEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_7:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_8:.*]] = arith.constant 100 : i32 ! CHECK: %[[VAL_9:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_5:.*]] : !fir.ref) reduction(byref @add_reduction_byref_i32 %[[VAL_3]]#0 -> %[[VAL_10:.*]] : !fir.ref) { +! CHECK: omp.wsloop reduction(byref @add_reduction_byref_i32 %[[VAL_3]]#0 -> %[[VAL_10:.*]] : !fir.ref) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_11:.*]]) : i32 = (%[[VAL_7]]) to (%[[VAL_8]]) inclusive step (%[[VAL_9]]) { -! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_5]] {uniq_name = "_QFsimple_int_reductionEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_12:.*]]:2 = hlfir.declare %[[VAL_10]] {uniq_name = "_QFsimple_int_reductionEx"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: fir.store %[[VAL_11]] to %[[VAL_6]]#1 : !fir.ref ! CHECK: %[[VAL_13:.*]] = fir.load %[[VAL_12]]#0 : !fir.ref @@ -126,12 +127,13 @@ subroutine simple_int_reduction ! CHECK: %[[VAL_4:.*]] = arith.constant 0.000000e+00 : f32 ! CHECK: hlfir.assign %[[VAL_4]] to %[[VAL_3]]#0 : f32, !fir.ref ! CHECK: omp.parallel { +! CHECK: %[[VAL_5:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_5]] {uniq_name = "_QFsimple_real_reductionEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_7:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_8:.*]] = arith.constant 100 : i32 ! CHECK: %[[VAL_9:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_5:.*]] : !fir.ref) reduction(byref @add_reduction_byref_f32 %[[VAL_3]]#0 -> %[[VAL_10:.*]] : !fir.ref) { +! CHECK: omp.wsloop reduction(byref @add_reduction_byref_f32 %[[VAL_3]]#0 -> %[[VAL_10:.*]] : !fir.ref) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_11:.*]]) : i32 = (%[[VAL_7]]) to (%[[VAL_8]]) inclusive step (%[[VAL_9]]) { -! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_5]] {uniq_name = "_QFsimple_real_reductionEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_12:.*]]:2 = hlfir.declare %[[VAL_10]] {uniq_name = "_QFsimple_real_reductionEx"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: fir.store %[[VAL_11]] to %[[VAL_6]]#1 : !fir.ref ! CHECK: %[[VAL_13:.*]] = fir.load %[[VAL_12]]#0 : !fir.ref @@ -168,12 +170,13 @@ subroutine simple_real_reduction ! CHECK: %[[VAL_4:.*]] = arith.constant 0 : i32 ! CHECK: hlfir.assign %[[VAL_4]] to %[[VAL_3]]#0 : i32, !fir.ref ! CHECK: omp.parallel { +! CHECK: %[[VAL_5:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_5]] {uniq_name = "_QFsimple_int_reduction_switch_orderEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_7:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_8:.*]] = arith.constant 100 : i32 ! CHECK: %[[VAL_9:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_5:.*]] : !fir.ref) reduction(byref @add_reduction_byref_i32 %[[VAL_3]]#0 -> %[[VAL_10:.*]] : !fir.ref) { +! CHECK: omp.wsloop reduction(byref @add_reduction_byref_i32 %[[VAL_3]]#0 -> %[[VAL_10:.*]] : !fir.ref) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_11:.*]]) : i32 = (%[[VAL_7]]) to (%[[VAL_8]]) inclusive step (%[[VAL_9]]) { -! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_5]] {uniq_name = "_QFsimple_int_reduction_switch_orderEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_12:.*]]:2 = hlfir.declare %[[VAL_10]] {uniq_name = "_QFsimple_int_reduction_switch_orderEx"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: fir.store %[[VAL_11]] to %[[VAL_6]]#1 : !fir.ref ! CHECK: %[[VAL_13:.*]] = fir.load %[[VAL_6]]#0 : !fir.ref @@ -208,12 +211,13 @@ subroutine simple_int_reduction_switch_order ! CHECK: %[[VAL_4:.*]] = arith.constant 0.000000e+00 : f32 ! CHECK: hlfir.assign %[[VAL_4]] to %[[VAL_3]]#0 : f32, !fir.ref ! CHECK: omp.parallel { +! CHECK: %[[VAL_5:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_5]] {uniq_name = "_QFsimple_real_reduction_switch_orderEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_7:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_8:.*]] = arith.constant 100 : i32 ! CHECK: %[[VAL_9:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_5:.*]] : !fir.ref) reduction(byref @add_reduction_byref_f32 %[[VAL_3]]#0 -> %[[VAL_10:.*]] : !fir.ref) { +! CHECK: omp.wsloop reduction(byref @add_reduction_byref_f32 %[[VAL_3]]#0 -> %[[VAL_10:.*]] : !fir.ref) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_11:.*]]) : i32 = (%[[VAL_7]]) to (%[[VAL_8]]) inclusive step (%[[VAL_9]]) { -! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_5]] {uniq_name = "_QFsimple_real_reduction_switch_orderEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_12:.*]]:2 = hlfir.declare %[[VAL_10]] {uniq_name = "_QFsimple_real_reduction_switch_orderEx"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: fir.store %[[VAL_11]] to %[[VAL_6]]#1 : !fir.ref ! CHECK: %[[VAL_13:.*]] = fir.load %[[VAL_6]]#0 : !fir.ref @@ -257,12 +261,13 @@ subroutine simple_real_reduction_switch_order ! CHECK: %[[VAL_10:.*]] = arith.constant 0 : i32 ! CHECK: hlfir.assign %[[VAL_10]] to %[[VAL_7]]#0 : i32, !fir.ref ! CHECK: omp.parallel { +! CHECK: %[[VAL_11:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_12:.*]]:2 = hlfir.declare %[[VAL_11]] {uniq_name = "_QFmultiple_int_reductions_same_typeEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_13:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_14:.*]] = arith.constant 100 : i32 ! CHECK: %[[VAL_15:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_11:.*]] : !fir.ref) reduction(byref @add_reduction_byref_i32 %[[VAL_3]]#0 -> %[[VAL_16:.*]], byref @add_reduction_byref_i32 %[[VAL_5]]#0 -> %[[VAL_17:.*]], byref @add_reduction_byref_i32 %[[VAL_7]]#0 -> %[[VAL_18:.*]] : !fir.ref, !fir.ref, !fir.ref) { +! CHECK: omp.wsloop reduction(byref @add_reduction_byref_i32 %[[VAL_3]]#0 -> %[[VAL_16:.*]], byref @add_reduction_byref_i32 %[[VAL_5]]#0 -> %[[VAL_17:.*]], byref @add_reduction_byref_i32 %[[VAL_7]]#0 -> %[[VAL_18:.*]] : !fir.ref, !fir.ref, !fir.ref) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_19:.*]]) : i32 = (%[[VAL_13]]) to (%[[VAL_14]]) inclusive step (%[[VAL_15]]) { -! CHECK: %[[VAL_12:.*]]:2 = hlfir.declare %[[VAL_11]] {uniq_name = "_QFmultiple_int_reductions_same_typeEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_20:.*]]:2 = hlfir.declare %[[VAL_16]] {uniq_name = "_QFmultiple_int_reductions_same_typeEx"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_21:.*]]:2 = hlfir.declare %[[VAL_17]] {uniq_name = "_QFmultiple_int_reductions_same_typeEy"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_22:.*]]:2 = hlfir.declare %[[VAL_18]] {uniq_name = "_QFmultiple_int_reductions_same_typeEz"} : (!fir.ref) -> (!fir.ref, !fir.ref) @@ -319,12 +324,13 @@ subroutine multiple_int_reductions_same_type ! CHECK: %[[VAL_10:.*]] = arith.constant 0.000000e+00 : f32 ! CHECK: hlfir.assign %[[VAL_10]] to %[[VAL_7]]#0 : f32, !fir.ref ! CHECK: omp.parallel { +! CHECK: %[[VAL_11:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_12:.*]]:2 = hlfir.declare %[[VAL_11]] {uniq_name = "_QFmultiple_real_reductions_same_typeEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_13:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_14:.*]] = arith.constant 100 : i32 ! CHECK: %[[VAL_15:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_11:.*]] : !fir.ref) reduction(byref @add_reduction_byref_f32 %[[VAL_3]]#0 -> %[[VAL_16:.*]], byref @add_reduction_byref_f32 %[[VAL_5]]#0 -> %[[VAL_17:.*]], byref @add_reduction_byref_f32 %[[VAL_7]]#0 -> %[[VAL_18:.*]] : !fir.ref, !fir.ref, !fir.ref) { +! CHECK: omp.wsloop reduction(byref @add_reduction_byref_f32 %[[VAL_3]]#0 -> %[[VAL_16:.*]], byref @add_reduction_byref_f32 %[[VAL_5]]#0 -> %[[VAL_17:.*]], byref @add_reduction_byref_f32 %[[VAL_7]]#0 -> %[[VAL_18:.*]] : !fir.ref, !fir.ref, !fir.ref) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_19:.*]]) : i32 = (%[[VAL_13]]) to (%[[VAL_14]]) inclusive step (%[[VAL_15]]) { -! CHECK: %[[VAL_12:.*]]:2 = hlfir.declare %[[VAL_11]] {uniq_name = "_QFmultiple_real_reductions_same_typeEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_20:.*]]:2 = hlfir.declare %[[VAL_16]] {uniq_name = "_QFmultiple_real_reductions_same_typeEx"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_21:.*]]:2 = hlfir.declare %[[VAL_17]] {uniq_name = "_QFmultiple_real_reductions_same_typeEy"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_22:.*]]:2 = hlfir.declare %[[VAL_18]] {uniq_name = "_QFmultiple_real_reductions_same_typeEz"} : (!fir.ref) -> (!fir.ref, !fir.ref) @@ -388,12 +394,13 @@ subroutine multiple_real_reductions_same_type ! CHECK: %[[VAL_13:.*]] = arith.constant 0.000000e+00 : f64 ! CHECK: hlfir.assign %[[VAL_13]] to %[[VAL_3]]#0 : f64, !fir.ref ! CHECK: omp.parallel { +! CHECK: %[[VAL_14:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_15:.*]]:2 = hlfir.declare %[[VAL_14]] {uniq_name = "_QFmultiple_reductions_different_typeEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_16:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_17:.*]] = arith.constant 100 : i32 ! CHECK: %[[VAL_18:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_14:.*]] : !fir.ref) reduction(byref @add_reduction_byref_i32 %[[VAL_5]]#0 -> %[[VAL_19:.*]], byref @add_reduction_byref_i64 %[[VAL_7]]#0 -> %[[VAL_20:.*]], byref @add_reduction_byref_f32 %[[VAL_9]]#0 -> %[[VAL_21:.*]], byref @add_reduction_byref_f64 %[[VAL_3]]#0 -> %[[VAL_22:.*]] : !fir.ref, !fir.ref, !fir.ref, !fir.ref) { +! CHECK: omp.wsloop reduction(byref @add_reduction_byref_i32 %[[VAL_5]]#0 -> %[[VAL_19:.*]], byref @add_reduction_byref_i64 %[[VAL_7]]#0 -> %[[VAL_20:.*]], byref @add_reduction_byref_f32 %[[VAL_9]]#0 -> %[[VAL_21:.*]], byref @add_reduction_byref_f64 %[[VAL_3]]#0 -> %[[VAL_22:.*]] : !fir.ref, !fir.ref, !fir.ref, !fir.ref) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_23:.*]]) : i32 = (%[[VAL_16]]) to (%[[VAL_17]]) inclusive step (%[[VAL_18]]) { -! CHECK: %[[VAL_15:.*]]:2 = hlfir.declare %[[VAL_14]] {uniq_name = "_QFmultiple_reductions_different_typeEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_24:.*]]:2 = hlfir.declare %[[VAL_19]] {uniq_name = "_QFmultiple_reductions_different_typeEx"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_25:.*]]:2 = hlfir.declare %[[VAL_20]] {uniq_name = "_QFmultiple_reductions_different_typeEy"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_26:.*]]:2 = hlfir.declare %[[VAL_21]] {uniq_name = "_QFmultiple_reductions_different_typeEz"} : (!fir.ref) -> (!fir.ref, !fir.ref) diff --git a/flang/test/Lower/OpenMP/wsloop-reduction-add.f90 b/flang/test/Lower/OpenMP/wsloop-reduction-add.f90 index a355e968b4146..c5278e0ef8815 100644 --- a/flang/test/Lower/OpenMP/wsloop-reduction-add.f90 +++ b/flang/test/Lower/OpenMP/wsloop-reduction-add.f90 @@ -53,12 +53,13 @@ ! CHECK: %[[VAL_4:.*]] = arith.constant 0 : i32 ! CHECK: hlfir.assign %[[VAL_4]] to %[[VAL_3]]#0 : i32, !fir.ref ! CHECK: omp.parallel { +! CHECK: %[[VAL_5:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_5]] {uniq_name = "_QFsimple_int_reductionEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_7:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_8:.*]] = arith.constant 100 : i32 ! CHECK: %[[VAL_9:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_5:.*]] : !fir.ref) reduction(@add_reduction_i32 %[[VAL_3]]#0 -> %[[VAL_10:.*]] : !fir.ref) { +! CHECK: omp.wsloop reduction(@add_reduction_i32 %[[VAL_3]]#0 -> %[[VAL_10:.*]] : !fir.ref) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_11:.*]]) : i32 = (%[[VAL_7]]) to (%[[VAL_8]]) inclusive step (%[[VAL_9]]) { -! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_5]] {uniq_name = "_QFsimple_int_reductionEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_12:.*]]:2 = hlfir.declare %[[VAL_10]] {uniq_name = "_QFsimple_int_reductionEx"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: fir.store %[[VAL_11]] to %[[VAL_6]]#1 : !fir.ref ! CHECK: %[[VAL_13:.*]] = fir.load %[[VAL_12]]#0 : !fir.ref @@ -94,12 +95,13 @@ subroutine simple_int_reduction ! CHECK: %[[VAL_4:.*]] = arith.constant 0.000000e+00 : f32 ! CHECK: hlfir.assign %[[VAL_4]] to %[[VAL_3]]#0 : f32, !fir.ref ! CHECK: omp.parallel { +! CHECK: %[[VAL_5:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_5]] {uniq_name = "_QFsimple_real_reductionEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_7:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_8:.*]] = arith.constant 100 : i32 ! CHECK: %[[VAL_9:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_5:.*]] : !fir.ref) reduction(@add_reduction_f32 %[[VAL_3]]#0 -> %[[VAL_10:.*]] : !fir.ref) { +! CHECK: omp.wsloop reduction(@add_reduction_f32 %[[VAL_3]]#0 -> %[[VAL_10:.*]] : !fir.ref) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_11:.*]]) : i32 = (%[[VAL_7]]) to (%[[VAL_8]]) inclusive step (%[[VAL_9]]) { -! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_5]] {uniq_name = "_QFsimple_real_reductionEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_12:.*]]:2 = hlfir.declare %[[VAL_10]] {uniq_name = "_QFsimple_real_reductionEx"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: fir.store %[[VAL_11]] to %[[VAL_6]]#1 : !fir.ref ! CHECK: %[[VAL_13:.*]] = fir.load %[[VAL_12]]#0 : !fir.ref @@ -136,12 +138,13 @@ subroutine simple_real_reduction ! CHECK: %[[VAL_4:.*]] = arith.constant 0 : i32 ! CHECK: hlfir.assign %[[VAL_4]] to %[[VAL_3]]#0 : i32, !fir.ref ! CHECK: omp.parallel { +! CHECK: %[[VAL_5:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_5]] {uniq_name = "_QFsimple_int_reduction_switch_orderEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_7:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_8:.*]] = arith.constant 100 : i32 ! CHECK: %[[VAL_9:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_5:.*]] : !fir.ref) reduction(@add_reduction_i32 %[[VAL_3]]#0 -> %[[VAL_10:.*]] : !fir.ref) { +! CHECK: omp.wsloop reduction(@add_reduction_i32 %[[VAL_3]]#0 -> %[[VAL_10:.*]] : !fir.ref) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_11:.*]]) : i32 = (%[[VAL_7]]) to (%[[VAL_8]]) inclusive step (%[[VAL_9]]) { -! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_5]] {uniq_name = "_QFsimple_int_reduction_switch_orderEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_12:.*]]:2 = hlfir.declare %[[VAL_10]] {uniq_name = "_QFsimple_int_reduction_switch_orderEx"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: fir.store %[[VAL_11]] to %[[VAL_6]]#1 : !fir.ref ! CHECK: %[[VAL_13:.*]] = fir.load %[[VAL_6]]#0 : !fir.ref @@ -176,12 +179,13 @@ subroutine simple_int_reduction_switch_order ! CHECK: %[[VAL_4:.*]] = arith.constant 0.000000e+00 : f32 ! CHECK: hlfir.assign %[[VAL_4]] to %[[VAL_3]]#0 : f32, !fir.ref ! CHECK: omp.parallel { +! CHECK: %[[VAL_5:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_5]] {uniq_name = "_QFsimple_real_reduction_switch_orderEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_7:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_8:.*]] = arith.constant 100 : i32 ! CHECK: %[[VAL_9:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_5:.*]] : !fir.ref) reduction(@add_reduction_f32 %[[VAL_3]]#0 -> %[[VAL_10:.*]] : !fir.ref) { +! CHECK: omp.wsloop reduction(@add_reduction_f32 %[[VAL_3]]#0 -> %[[VAL_10:.*]] : !fir.ref) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_11:.*]]) : i32 = (%[[VAL_7]]) to (%[[VAL_8]]) inclusive step (%[[VAL_9]]) { -! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_5]] {uniq_name = "_QFsimple_real_reduction_switch_orderEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_12:.*]]:2 = hlfir.declare %[[VAL_10]] {uniq_name = "_QFsimple_real_reduction_switch_orderEx"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: fir.store %[[VAL_11]] to %[[VAL_6]]#1 : !fir.ref ! CHECK: %[[VAL_13:.*]] = fir.load %[[VAL_6]]#0 : !fir.ref @@ -225,12 +229,13 @@ subroutine simple_real_reduction_switch_order ! CHECK: %[[VAL_10:.*]] = arith.constant 0 : i32 ! CHECK: hlfir.assign %[[VAL_10]] to %[[VAL_7]]#0 : i32, !fir.ref ! CHECK: omp.parallel { +! CHECK: %[[VAL_11:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_12:.*]]:2 = hlfir.declare %[[VAL_11]] {uniq_name = "_QFmultiple_int_reductions_same_typeEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_13:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_14:.*]] = arith.constant 100 : i32 ! CHECK: %[[VAL_15:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_11:.*]] : !fir.ref) reduction(@add_reduction_i32 %[[VAL_3]]#0 -> %[[VAL_16:.*]], @add_reduction_i32 %[[VAL_5]]#0 -> %[[VAL_17:.*]], @add_reduction_i32 %[[VAL_7]]#0 -> %[[VAL_18:.*]] : !fir.ref, !fir.ref, !fir.ref) { +! CHECK: omp.wsloop reduction(@add_reduction_i32 %[[VAL_3]]#0 -> %[[VAL_16:.*]], @add_reduction_i32 %[[VAL_5]]#0 -> %[[VAL_17:.*]], @add_reduction_i32 %[[VAL_7]]#0 -> %[[VAL_18:.*]] : !fir.ref, !fir.ref, !fir.ref) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_19:.*]]) : i32 = (%[[VAL_13]]) to (%[[VAL_14]]) inclusive step (%[[VAL_15]]) { -! CHECK: %[[VAL_12:.*]]:2 = hlfir.declare %[[VAL_11]] {uniq_name = "_QFmultiple_int_reductions_same_typeEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_20:.*]]:2 = hlfir.declare %[[VAL_16]] {uniq_name = "_QFmultiple_int_reductions_same_typeEx"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_21:.*]]:2 = hlfir.declare %[[VAL_17]] {uniq_name = "_QFmultiple_int_reductions_same_typeEy"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_22:.*]]:2 = hlfir.declare %[[VAL_18]] {uniq_name = "_QFmultiple_int_reductions_same_typeEz"} : (!fir.ref) -> (!fir.ref, !fir.ref) @@ -287,12 +292,13 @@ subroutine multiple_int_reductions_same_type ! CHECK: %[[VAL_10:.*]] = arith.constant 0.000000e+00 : f32 ! CHECK: hlfir.assign %[[VAL_10]] to %[[VAL_7]]#0 : f32, !fir.ref ! CHECK: omp.parallel { +! CHECK: %[[VAL_11:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_12:.*]]:2 = hlfir.declare %[[VAL_11]] {uniq_name = "_QFmultiple_real_reductions_same_typeEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_13:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_14:.*]] = arith.constant 100 : i32 ! CHECK: %[[VAL_15:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_11:.*]] : !fir.ref) reduction(@add_reduction_f32 %[[VAL_3]]#0 -> %[[VAL_16:.*]], @add_reduction_f32 %[[VAL_5]]#0 -> %[[VAL_17:.*]], @add_reduction_f32 %[[VAL_7]]#0 -> %[[VAL_18:.*]] : !fir.ref, !fir.ref, !fir.ref) { +! CHECK: omp.wsloop reduction(@add_reduction_f32 %[[VAL_3]]#0 -> %[[VAL_16:.*]], @add_reduction_f32 %[[VAL_5]]#0 -> %[[VAL_17:.*]], @add_reduction_f32 %[[VAL_7]]#0 -> %[[VAL_18:.*]] : !fir.ref, !fir.ref, !fir.ref) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_19:.*]]) : i32 = (%[[VAL_13]]) to (%[[VAL_14]]) inclusive step (%[[VAL_15]]) { -! CHECK: %[[VAL_12:.*]]:2 = hlfir.declare %[[VAL_11]] {uniq_name = "_QFmultiple_real_reductions_same_typeEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_20:.*]]:2 = hlfir.declare %[[VAL_16]] {uniq_name = "_QFmultiple_real_reductions_same_typeEx"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_21:.*]]:2 = hlfir.declare %[[VAL_17]] {uniq_name = "_QFmultiple_real_reductions_same_typeEy"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_22:.*]]:2 = hlfir.declare %[[VAL_18]] {uniq_name = "_QFmultiple_real_reductions_same_typeEz"} : (!fir.ref) -> (!fir.ref, !fir.ref) @@ -356,12 +362,13 @@ subroutine multiple_real_reductions_same_type ! CHECK: %[[VAL_13:.*]] = arith.constant 0.000000e+00 : f64 ! CHECK: hlfir.assign %[[VAL_13]] to %[[VAL_3]]#0 : f64, !fir.ref ! CHECK: omp.parallel { +! CHECK: %[[VAL_14:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_15:.*]]:2 = hlfir.declare %[[VAL_14]] {uniq_name = "_QFmultiple_reductions_different_typeEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_16:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_17:.*]] = arith.constant 100 : i32 ! CHECK: %[[VAL_18:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_14:.*]] : !fir.ref) reduction(@add_reduction_i32 %[[VAL_5]]#0 -> %[[VAL_19:.*]], @add_reduction_i64 %[[VAL_7]]#0 -> %[[VAL_20:.*]], @add_reduction_f32 %[[VAL_9]]#0 -> %[[VAL_21:.*]], @add_reduction_f64 %[[VAL_3]]#0 -> %[[VAL_22:.*]] : !fir.ref, !fir.ref, !fir.ref, !fir.ref) { +! CHECK: omp.wsloop reduction(@add_reduction_i32 %[[VAL_5]]#0 -> %[[VAL_19:.*]], @add_reduction_i64 %[[VAL_7]]#0 -> %[[VAL_20:.*]], @add_reduction_f32 %[[VAL_9]]#0 -> %[[VAL_21:.*]], @add_reduction_f64 %[[VAL_3]]#0 -> %[[VAL_22:.*]] : !fir.ref, !fir.ref, !fir.ref, !fir.ref) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_23:.*]]) : i32 = (%[[VAL_16]]) to (%[[VAL_17]]) inclusive step (%[[VAL_18]]) { -! CHECK: %[[VAL_15:.*]]:2 = hlfir.declare %[[VAL_14]] {uniq_name = "_QFmultiple_reductions_different_typeEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_24:.*]]:2 = hlfir.declare %[[VAL_19]] {uniq_name = "_QFmultiple_reductions_different_typeEx"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_25:.*]]:2 = hlfir.declare %[[VAL_20]] {uniq_name = "_QFmultiple_reductions_different_typeEy"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_26:.*]]:2 = hlfir.declare %[[VAL_21]] {uniq_name = "_QFmultiple_reductions_different_typeEz"} : (!fir.ref) -> (!fir.ref, !fir.ref) diff --git a/flang/test/Lower/OpenMP/wsloop-reduction-allocatable-array-minmax.f90 b/flang/test/Lower/OpenMP/wsloop-reduction-allocatable-array-minmax.f90 index f09130152fb28..ce45d09d77a22 100644 --- a/flang/test/Lower/OpenMP/wsloop-reduction-allocatable-array-minmax.f90 +++ b/flang/test/Lower/OpenMP/wsloop-reduction-allocatable-array-minmax.f90 @@ -214,12 +214,13 @@ program reduce15 ! CHECK: } ! CHECK: fir.store %[[VAL_54:.*]]#1 to %[[VAL_3]]#1 : !fir.ref ! CHECK: omp.parallel { +! CHECK: %[[VAL_55:.*]] = fir.alloca i32 {bindc_name = "i", pinned, uniq_name = "_QFEi"} +! CHECK: %[[VAL_56:.*]]:2 = hlfir.declare %[[VAL_55]] {uniq_name = "_QFEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_57:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_58:.*]] = arith.constant 10 : i32 ! CHECK: %[[VAL_59:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_55:.*]] : !fir.ref) reduction(byref @max_byref_box_heap_Uxi32 %[[VAL_5]]#0 -> %[[VAL_60:.*]] : !fir.ref>>>) { +! CHECK: omp.wsloop reduction(byref @max_byref_box_heap_Uxi32 %[[VAL_5]]#0 -> %[[VAL_60:.*]] : !fir.ref>>>) { ! CHECK: omp.loop_nest (%[[VAL_61:.*]]) : i32 = (%[[VAL_57]]) to (%[[VAL_58]]) inclusive step (%[[VAL_59]]) { -! CHECK: %[[VAL_56:.*]]:2 = hlfir.declare %[[VAL_55]] {uniq_name = "_QFEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_62:.*]]:2 = hlfir.declare %[[VAL_60]] {fortran_attrs = {{.*}}, uniq_name = "_QFEmaxes"} : (!fir.ref>>>) -> (!fir.ref>>>, !fir.ref>>>) ! CHECK: fir.store %[[VAL_61]] to %[[VAL_56]]#1 : !fir.ref ! CHECK: %[[VAL_63:.*]] = fir.load %[[VAL_1]]#0 : !fir.ref>>> @@ -255,12 +256,13 @@ program reduce15 ! CHECK: omp.terminator ! CHECK: } ! CHECK: omp.parallel { +! CHECK: %[[VAL_87:.*]] = fir.alloca i32 {bindc_name = "i", pinned, uniq_name = "_QFEi"} +! CHECK: %[[VAL_88:.*]]:2 = hlfir.declare %[[VAL_87]] {uniq_name = "_QFEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_89:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_90:.*]] = arith.constant 10 : i32 ! CHECK: %[[VAL_91:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_87:.*]] : !fir.ref) reduction(byref @min_byref_box_heap_Uxi32 %[[VAL_7]]#0 -> %[[VAL_92:.*]] : !fir.ref>>>) { +! CHECK: omp.wsloop reduction(byref @min_byref_box_heap_Uxi32 %[[VAL_7]]#0 -> %[[VAL_92:.*]] : !fir.ref>>>) { ! CHECK: omp.loop_nest (%[[VAL_93:.*]]) : i32 = (%[[VAL_89]]) to (%[[VAL_90]]) inclusive step (%[[VAL_91]]) { -! CHECK: %[[VAL_88:.*]]:2 = hlfir.declare %[[VAL_87]] {uniq_name = "_QFEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_94:.*]]:2 = hlfir.declare %[[VAL_92]] {fortran_attrs = {{.*}}, uniq_name = "_QFEmins"} : (!fir.ref>>>) -> (!fir.ref>>>, !fir.ref>>>) ! CHECK: fir.store %[[VAL_93]] to %[[VAL_88]]#1 : !fir.ref ! CHECK: %[[VAL_95:.*]] = fir.load %[[VAL_1]]#0 : !fir.ref>>> diff --git a/flang/test/Lower/OpenMP/wsloop-reduction-allocatable.f90 b/flang/test/Lower/OpenMP/wsloop-reduction-allocatable.f90 index 7e6d7fddff5a1..ba7aea0d96c5b 100644 --- a/flang/test/Lower/OpenMP/wsloop-reduction-allocatable.f90 +++ b/flang/test/Lower/OpenMP/wsloop-reduction-allocatable.f90 @@ -77,12 +77,13 @@ program reduce ! CHECK: %[[VAL_8:.*]] = arith.constant 0 : i32 ! CHECK: hlfir.assign %[[VAL_8]] to %[[VAL_5]]#0 realloc : i32, !fir.ref>> ! CHECK: omp.parallel { +! CHECK: %[[VAL_9:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_10:.*]]:2 = hlfir.declare %[[VAL_9]] {uniq_name = "_QFEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_11:.*]] = arith.constant 0 : i32 ! CHECK: %[[VAL_12:.*]] = arith.constant 10 : i32 ! CHECK: %[[VAL_13:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_9:.*]] : !fir.ref) reduction(byref @add_reduction_byref_box_heap_i32 %[[VAL_5]]#0 -> %[[VAL_14:.*]] : !fir.ref>>) { +! CHECK: omp.wsloop reduction(byref @add_reduction_byref_box_heap_i32 %[[VAL_5]]#0 -> %[[VAL_14:.*]] : !fir.ref>>) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_15:.*]]) : i32 = (%[[VAL_11]]) to (%[[VAL_12]]) inclusive step (%[[VAL_13]]) { -! CHECK: %[[VAL_10:.*]]:2 = hlfir.declare %[[VAL_9]] {uniq_name = "_QFEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_16:.*]]:2 = hlfir.declare %[[VAL_14]] {fortran_attrs = {{.*}}, uniq_name = "_QFEr"} : (!fir.ref>>) -> (!fir.ref>>, !fir.ref>>) ! CHECK: fir.store %[[VAL_15]] to %[[VAL_10]]#1 : !fir.ref ! CHECK: %[[VAL_17:.*]] = fir.load %[[VAL_10]]#0 : !fir.ref diff --git a/flang/test/Lower/OpenMP/wsloop-reduction-array-assumed-shape.f90 b/flang/test/Lower/OpenMP/wsloop-reduction-array-assumed-shape.f90 index 0e2fc3a24ee1b..9785f77c0e091 100644 --- a/flang/test/Lower/OpenMP/wsloop-reduction-array-assumed-shape.f90 +++ b/flang/test/Lower/OpenMP/wsloop-reduction-array-assumed-shape.f90 @@ -81,12 +81,13 @@ subroutine reduce(r) ! CHECK: omp.parallel { ! CHECK: %[[VAL_4:.*]] = fir.alloca !fir.box> ! CHECK: fir.store %[[VAL_3]]#1 to %[[VAL_4]] : !fir.ref>> +! CHECK: %[[VAL_5:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_5]] {uniq_name = "_QFFreduceEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_7:.*]] = arith.constant 0 : i32 ! CHECK: %[[VAL_8:.*]] = arith.constant 10 : i32 ! CHECK: %[[VAL_9:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_5:.*]] : !fir.ref) reduction(byref @add_reduction_byref_box_Uxf64 %[[VAL_4]] -> %[[VAL_10:.*]] : !fir.ref>>) { +! CHECK: omp.wsloop reduction(byref @add_reduction_byref_box_Uxf64 %[[VAL_4]] -> %[[VAL_10:.*]] : !fir.ref>>) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_11:.*]]) : i32 = (%[[VAL_7]]) to (%[[VAL_8]]) inclusive step (%[[VAL_9]]) { -! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_5]] {uniq_name = "_QFFreduceEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_12:.*]]:2 = hlfir.declare %[[VAL_10]] {fortran_attrs = {{.*}}, uniq_name = "_QFFreduceEr"} : (!fir.ref>>) -> (!fir.ref>>, !fir.ref>>) ! CHECK: fir.store %[[VAL_11]] to %[[VAL_6]]#1 : !fir.ref ! CHECK: %[[VAL_13:.*]] = fir.load %[[VAL_6]]#0 : !fir.ref diff --git a/flang/test/Lower/OpenMP/wsloop-reduction-array.f90 b/flang/test/Lower/OpenMP/wsloop-reduction-array.f90 index 07debb9f6b9e0..ea5df5a836972 100644 --- a/flang/test/Lower/OpenMP/wsloop-reduction-array.f90 +++ b/flang/test/Lower/OpenMP/wsloop-reduction-array.f90 @@ -76,12 +76,13 @@ program reduce ! CHECK: %[[VAL_6:.*]] = fir.embox %[[VAL_5]]#0(%[[VAL_4]]) : (!fir.ref>, !fir.shape<1>) -> !fir.box> ! CHECK: %[[VAL_7:.*]] = fir.alloca !fir.box> ! CHECK: fir.store %[[VAL_6]] to %[[VAL_7]] : !fir.ref>> +! CHECK: %[[VAL_8:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_9:.*]]:2 = hlfir.declare %[[VAL_8]] {uniq_name = "_QFEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_10:.*]] = arith.constant 0 : i32 ! CHECK: %[[VAL_11:.*]] = arith.constant 10 : i32 ! CHECK: %[[VAL_12:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_8:.*]] : !fir.ref) reduction(byref @add_reduction_byref_box_2xi32 %[[VAL_7]] -> %[[VAL_13:.*]] : !fir.ref>>) { +! CHECK: omp.wsloop reduction(byref @add_reduction_byref_box_2xi32 %[[VAL_7]] -> %[[VAL_13:.*]] : !fir.ref>>) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_14:.*]]) : i32 = (%[[VAL_10]]) to (%[[VAL_11]]) inclusive step (%[[VAL_12]]) { -! CHECK: %[[VAL_9:.*]]:2 = hlfir.declare %[[VAL_8]] {uniq_name = "_QFEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_15:.*]]:2 = hlfir.declare %[[VAL_13]] {uniq_name = "_QFEr"} : (!fir.ref>>) -> (!fir.ref>>, !fir.ref>>) ! CHECK: fir.store %[[VAL_14]] to %[[VAL_9]]#1 : !fir.ref ! CHECK: %[[VAL_16:.*]] = fir.load %[[VAL_9]]#0 : !fir.ref diff --git a/flang/test/Lower/OpenMP/wsloop-reduction-array2.f90 b/flang/test/Lower/OpenMP/wsloop-reduction-array2.f90 index a25bedb359f4e..9815cfa9c3150 100644 --- a/flang/test/Lower/OpenMP/wsloop-reduction-array2.f90 +++ b/flang/test/Lower/OpenMP/wsloop-reduction-array2.f90 @@ -76,12 +76,13 @@ program reduce ! CHECK: %[[VAL_6:.*]] = fir.embox %[[VAL_5]]#0(%[[VAL_4]]) : (!fir.ref>, !fir.shape<1>) -> !fir.box> ! CHECK: %[[VAL_7:.*]] = fir.alloca !fir.box> ! CHECK: fir.store %[[VAL_6]] to %[[VAL_7]] : !fir.ref>> +! CHECK: %[[VAL_8:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_9:.*]]:2 = hlfir.declare %[[VAL_8]] {uniq_name = "_QFEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_10:.*]] = arith.constant 0 : i32 ! CHECK: %[[VAL_11:.*]] = arith.constant 10 : i32 ! CHECK: %[[VAL_12:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_8:.*]] : !fir.ref) reduction(byref @add_reduction_byref_box_2xi32 %[[VAL_7]] -> %[[VAL_13:.*]] : !fir.ref>>) { +! CHECK: omp.wsloop reduction(byref @add_reduction_byref_box_2xi32 %[[VAL_7]] -> %[[VAL_13:.*]] : !fir.ref>>) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_14:.*]]) : i32 = (%[[VAL_10]]) to (%[[VAL_11]]) inclusive step (%[[VAL_12]]) { -! CHECK: %[[VAL_9:.*]]:2 = hlfir.declare %[[VAL_8]] {uniq_name = "_QFEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_15:.*]]:2 = hlfir.declare %[[VAL_13]] {uniq_name = "_QFEr"} : (!fir.ref>>) -> (!fir.ref>>, !fir.ref>>) ! CHECK: fir.store %[[VAL_14]] to %[[VAL_9]]#1 : !fir.ref ! CHECK: %[[VAL_16:.*]] = fir.load %[[VAL_15]]#0 : !fir.ref>> diff --git a/flang/test/Lower/OpenMP/wsloop-reduction-iand-byref.f90 b/flang/test/Lower/OpenMP/wsloop-reduction-iand-byref.f90 index 18dcc3d722886..829229807698a 100644 --- a/flang/test/Lower/OpenMP/wsloop-reduction-iand-byref.f90 +++ b/flang/test/Lower/OpenMP/wsloop-reduction-iand-byref.f90 @@ -32,12 +32,13 @@ ! CHECK: %[[VAL_6:.*]] = arith.constant 0 : i32 ! CHECK: hlfir.assign %[[VAL_6]] to %[[VAL_4]]#0 : i32, !fir.ref ! CHECK: omp.parallel { +! CHECK: %[[VAL_7:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_8:.*]]:2 = hlfir.declare %[[VAL_7]] {uniq_name = "_QFreduction_iandEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_9:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_10:.*]] = arith.constant 100 : i32 ! CHECK: %[[VAL_11:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_7:.*]] : !fir.ref) reduction(byref @iand_byref_i32 %[[VAL_4]]#0 -> %[[VAL_12:.*]] : !fir.ref) { +! CHECK: omp.wsloop reduction(byref @iand_byref_i32 %[[VAL_4]]#0 -> %[[VAL_12:.*]] : !fir.ref) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_13:.*]]) : i32 = (%[[VAL_9]]) to (%[[VAL_10]]) inclusive step (%[[VAL_11]]) { -! CHECK: %[[VAL_8:.*]]:2 = hlfir.declare %[[VAL_7]] {uniq_name = "_QFreduction_iandEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_14:.*]]:2 = hlfir.declare %[[VAL_12]] {uniq_name = "_QFreduction_iandEx"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: fir.store %[[VAL_13]] to %[[VAL_8]]#1 : !fir.ref ! CHECK: %[[VAL_15:.*]] = fir.load %[[VAL_8]]#0 : !fir.ref diff --git a/flang/test/Lower/OpenMP/wsloop-reduction-iand.f90 b/flang/test/Lower/OpenMP/wsloop-reduction-iand.f90 index eaf07f93c7474..6c060f2e5292a 100644 --- a/flang/test/Lower/OpenMP/wsloop-reduction-iand.f90 +++ b/flang/test/Lower/OpenMP/wsloop-reduction-iand.f90 @@ -24,12 +24,13 @@ ! CHECK: %[[VAL_6:.*]] = arith.constant 0 : i32 ! CHECK: hlfir.assign %[[VAL_6]] to %[[VAL_4]]#0 : i32, !fir.ref ! CHECK: omp.parallel { +! CHECK: %[[VAL_7:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_8:.*]]:2 = hlfir.declare %[[VAL_7]] {uniq_name = "_QFreduction_iandEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_9:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_10:.*]] = arith.constant 100 : i32 ! CHECK: %[[VAL_11:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_7:.*]] : !fir.ref) reduction(@iand_i32 %[[VAL_4]]#0 -> %[[VAL_12:.*]] : !fir.ref) { +! CHECK: omp.wsloop reduction(@iand_i32 %[[VAL_4]]#0 -> %[[VAL_12:.*]] : !fir.ref) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_13:.*]]) : i32 = (%[[VAL_9]]) to (%[[VAL_10]]) inclusive step (%[[VAL_11]]) { -! CHECK: %[[VAL_8:.*]]:2 = hlfir.declare %[[VAL_7]] {uniq_name = "_QFreduction_iandEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_14:.*]]:2 = hlfir.declare %[[VAL_12]] {uniq_name = "_QFreduction_iandEx"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: fir.store %[[VAL_13]] to %[[VAL_8]]#1 : !fir.ref ! CHECK: %[[VAL_15:.*]] = fir.load %[[VAL_8]]#0 : !fir.ref diff --git a/flang/test/Lower/OpenMP/wsloop-reduction-ieor-byref.f90 b/flang/test/Lower/OpenMP/wsloop-reduction-ieor-byref.f90 index 6be6913f91a33..284ada404bd60 100644 --- a/flang/test/Lower/OpenMP/wsloop-reduction-ieor-byref.f90 +++ b/flang/test/Lower/OpenMP/wsloop-reduction-ieor-byref.f90 @@ -28,9 +28,10 @@ !CHECK: omp.parallel -!CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[I_REF:.*]] : !fir.ref) reduction(byref @ieor_byref_i32 %[[X_DECL]]#0 -> %[[PRV:.+]] : !fir.ref) -!CHECK-NEXT: omp.loop_nest +!CHECK: %[[I_REF:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} !CHECK: %[[I_DECL:.*]]:2 = hlfir.declare %[[I_REF]] {uniq_name = "_QFreduction_ieorEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK: omp.wsloop reduction(byref @ieor_byref_i32 %[[X_DECL]]#0 -> %[[PRV:.+]] : !fir.ref) +!CHECK-NEXT: omp.loop_nest !CHECK: %[[PRV_DECL:.+]]:2 = hlfir.declare %[[PRV]] {{.*}} : (!fir.ref) -> (!fir.ref, !fir.ref) !CHECK: fir.store %{{.*}} to %[[I_DECL]]#1 : !fir.ref !CHECK: %[[I_32:.*]] = fir.load %[[I_DECL]]#0 : !fir.ref diff --git a/flang/test/Lower/OpenMP/wsloop-reduction-ieor.f90 b/flang/test/Lower/OpenMP/wsloop-reduction-ieor.f90 index 632dbcf1348ec..e67253a413ce2 100644 --- a/flang/test/Lower/OpenMP/wsloop-reduction-ieor.f90 +++ b/flang/test/Lower/OpenMP/wsloop-reduction-ieor.f90 @@ -17,9 +17,10 @@ !CHECK: omp.parallel -!CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[I_REF:.*]] : !fir.ref) reduction(@[[IEOR_DECLARE_I]] %[[X_DECL]]#0 -> %[[PRV:.+]] : !fir.ref) -!CHECK-NEXT: omp.loop_nest +!CHECK: %[[I_REF:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} !CHECK: %[[I_DECL:.*]]:2 = hlfir.declare %[[I_REF]] {uniq_name = "_QFreduction_ieorEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK: omp.wsloop reduction(@[[IEOR_DECLARE_I]] %[[X_DECL]]#0 -> %[[PRV:.+]] : !fir.ref) +!CHECK-NEXT: omp.loop_nest !CHECK: %[[PRV_DECL:.+]]:2 = hlfir.declare %[[PRV]] {{.*}} : (!fir.ref) -> (!fir.ref, !fir.ref) !CHECK: fir.store %{{.*}} to %[[I_DECL]]#1 : !fir.ref !CHECK: %[[I_32:.*]] = fir.load %[[I_DECL]]#0 : !fir.ref diff --git a/flang/test/Lower/OpenMP/wsloop-reduction-ior-byref.f90 b/flang/test/Lower/OpenMP/wsloop-reduction-ior-byref.f90 index 90b9d2f61f930..315121cc7beb7 100644 --- a/flang/test/Lower/OpenMP/wsloop-reduction-ior-byref.f90 +++ b/flang/test/Lower/OpenMP/wsloop-reduction-ior-byref.f90 @@ -30,12 +30,13 @@ ! CHECK: %[[VAL_6:.*]] = arith.constant 0 : i32 ! CHECK: hlfir.assign %[[VAL_6]] to %[[VAL_4]]#0 : i32, !fir.ref ! CHECK: omp.parallel +! CHECK: %[[VAL_7:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_8:.*]]:2 = hlfir.declare %[[VAL_7]] {uniq_name = "_QFreduction_iorEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_9:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_10:.*]] = arith.constant 100 : i32 ! CHECK: %[[VAL_11:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_7:.*]] : !fir.ref) reduction(byref @ior_byref_i32 %[[VAL_4]]#0 -> %[[VAL_12:.*]] : !fir.ref) { +! CHECK: omp.wsloop reduction(byref @ior_byref_i32 %[[VAL_4]]#0 -> %[[VAL_12:.*]] : !fir.ref) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_13:.*]]) : i32 = (%[[VAL_9]]) to (%[[VAL_10]]) inclusive step (%[[VAL_11]]) { -! CHECK: %[[VAL_8:.*]]:2 = hlfir.declare %[[VAL_7]] {uniq_name = "_QFreduction_iorEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_14:.*]]:2 = hlfir.declare %[[VAL_12]] {uniq_name = "_QFreduction_iorEx"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: fir.store %[[VAL_13]] to %[[VAL_8]]#1 : !fir.ref ! CHECK: %[[VAL_15:.*]] = fir.load %[[VAL_8]]#0 : !fir.ref diff --git a/flang/test/Lower/OpenMP/wsloop-reduction-ior.f90 b/flang/test/Lower/OpenMP/wsloop-reduction-ior.f90 index 144bc17cf8b31..3da250da9703d 100644 --- a/flang/test/Lower/OpenMP/wsloop-reduction-ior.f90 +++ b/flang/test/Lower/OpenMP/wsloop-reduction-ior.f90 @@ -24,12 +24,13 @@ ! CHECK: %[[VAL_6:.*]] = arith.constant 0 : i32 ! CHECK: hlfir.assign %[[VAL_6]] to %[[VAL_4]]#0 : i32, !fir.ref ! CHECK: omp.parallel +! CHECK: %[[VAL_7:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_8:.*]]:2 = hlfir.declare %[[VAL_7]] {uniq_name = "_QFreduction_iorEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_9:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_10:.*]] = arith.constant 100 : i32 ! CHECK: %[[VAL_11:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_7:.*]] : !fir.ref) reduction(@ior_i32 %[[VAL_4]]#0 -> %[[VAL_12:.*]] : !fir.ref) { +! CHECK: omp.wsloop reduction(@ior_i32 %[[VAL_4]]#0 -> %[[VAL_12:.*]] : !fir.ref) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_13:.*]]) : i32 = (%[[VAL_9]]) to (%[[VAL_10]]) inclusive step (%[[VAL_11]]) { -! CHECK: %[[VAL_8:.*]]:2 = hlfir.declare %[[VAL_7]] {uniq_name = "_QFreduction_iorEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_14:.*]]:2 = hlfir.declare %[[VAL_12]] {uniq_name = "_QFreduction_iorEx"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: fir.store %[[VAL_13]] to %[[VAL_8]]#1 : !fir.ref ! CHECK: %[[VAL_15:.*]] = fir.load %[[VAL_8]]#0 : !fir.ref diff --git a/flang/test/Lower/OpenMP/wsloop-reduction-logical-and-byref.f90 b/flang/test/Lower/OpenMP/wsloop-reduction-logical-and-byref.f90 index e73540a93a71b..30908b6bdd4ce 100644 --- a/flang/test/Lower/OpenMP/wsloop-reduction-logical-and-byref.f90 +++ b/flang/test/Lower/OpenMP/wsloop-reduction-logical-and-byref.f90 @@ -39,12 +39,13 @@ ! CHECK: %[[VAL_9:.*]] = fir.convert %[[VAL_8]] : (i1) -> !fir.logical<4> ! CHECK: hlfir.assign %[[VAL_9]] to %[[VAL_4]]#0 : !fir.logical<4>, !fir.ref> ! CHECK: omp.parallel { +! CHECK: %[[VAL_10:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_11:.*]]:2 = hlfir.declare %[[VAL_10]] {uniq_name = "_QFsimple_reductionEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_12:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_13:.*]] = arith.constant 100 : i32 ! CHECK: %[[VAL_14:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_10:.*]] : !fir.ref) reduction(byref @and_reduction %[[VAL_4]]#0 -> %[[VAL_15:.*]] : !fir.ref>) { +! CHECK: omp.wsloop reduction(byref @and_reduction %[[VAL_4]]#0 -> %[[VAL_15:.*]] : !fir.ref>) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_16:.*]]) : i32 = (%[[VAL_12]]) to (%[[VAL_13]]) inclusive step (%[[VAL_14]]) { -! CHECK: %[[VAL_11:.*]]:2 = hlfir.declare %[[VAL_10]] {uniq_name = "_QFsimple_reductionEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_17:.*]]:2 = hlfir.declare %[[VAL_15]] {uniq_name = "_QFsimple_reductionEx"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) ! CHECK: fir.store %[[VAL_16]] to %[[VAL_11]]#1 : !fir.ref ! CHECK: %[[VAL_18:.*]] = fir.load %[[VAL_17]]#0 : !fir.ref> @@ -87,12 +88,13 @@ end subroutine simple_reduction ! CHECK: %[[VAL_9:.*]] = fir.convert %[[VAL_8]] : (i1) -> !fir.logical<4> ! CHECK: hlfir.assign %[[VAL_9]] to %[[VAL_4]]#0 : !fir.logical<4>, !fir.ref> ! CHECK: omp.parallel { +! CHECK: %[[VAL_10:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_11:.*]]:2 = hlfir.declare %[[VAL_10]] {uniq_name = "_QFsimple_reduction_switch_orderEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_12:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_13:.*]] = arith.constant 100 : i32 ! CHECK: %[[VAL_14:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_10:.*]] : !fir.ref) reduction(byref @and_reduction %[[VAL_4]]#0 -> %[[VAL_15:.*]] : !fir.ref>) { +! CHECK: omp.wsloop reduction(byref @and_reduction %[[VAL_4]]#0 -> %[[VAL_15:.*]] : !fir.ref>) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_16:.*]]) : i32 = (%[[VAL_12]]) to (%[[VAL_13]]) inclusive step (%[[VAL_14]]) { -! CHECK: %[[VAL_11:.*]]:2 = hlfir.declare %[[VAL_10]] {uniq_name = "_QFsimple_reduction_switch_orderEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_17:.*]]:2 = hlfir.declare %[[VAL_15]] {uniq_name = "_QFsimple_reduction_switch_orderEx"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) ! CHECK: fir.store %[[VAL_16]] to %[[VAL_11]]#1 : !fir.ref ! CHECK: %[[VAL_18:.*]] = fir.load %[[VAL_11]]#0 : !fir.ref @@ -144,12 +146,13 @@ subroutine simple_reduction_switch_order(y) ! CHECK: %[[VAL_17:.*]] = fir.convert %[[VAL_16]] : (i1) -> !fir.logical<4> ! CHECK: hlfir.assign %[[VAL_17]] to %[[VAL_11]]#0 : !fir.logical<4>, !fir.ref> ! CHECK: omp.parallel { +! CHECK: %[[VAL_18:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_19:.*]]:2 = hlfir.declare %[[VAL_18]] {uniq_name = "_QFmultiple_reductionsEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_20:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_21:.*]] = arith.constant 100 : i32 ! CHECK: %[[VAL_22:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_18:.*]] : !fir.ref) reduction(byref @and_reduction %[[VAL_7]]#0 -> %[[VAL_23:.*]], byref @and_reduction %[[VAL_9]]#0 -> %[[VAL_24:.*]], byref @and_reduction %[[VAL_11]]#0 -> %[[VAL_25:.*]] : !fir.ref>, !fir.ref>, !fir.ref>) { +! CHECK: omp.wsloop reduction(byref @and_reduction %[[VAL_7]]#0 -> %[[VAL_23:.*]], byref @and_reduction %[[VAL_9]]#0 -> %[[VAL_24:.*]], byref @and_reduction %[[VAL_11]]#0 -> %[[VAL_25:.*]] : !fir.ref>, !fir.ref>, !fir.ref>) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_26:.*]]) : i32 = (%[[VAL_20]]) to (%[[VAL_21]]) inclusive step (%[[VAL_22]]) { -! CHECK: %[[VAL_19:.*]]:2 = hlfir.declare %[[VAL_18]] {uniq_name = "_QFmultiple_reductionsEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_27:.*]]:2 = hlfir.declare %[[VAL_23]] {uniq_name = "_QFmultiple_reductionsEx"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) ! CHECK: %[[VAL_28:.*]]:2 = hlfir.declare %[[VAL_24]] {uniq_name = "_QFmultiple_reductionsEy"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) ! CHECK: %[[VAL_29:.*]]:2 = hlfir.declare %[[VAL_25]] {uniq_name = "_QFmultiple_reductionsEz"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) diff --git a/flang/test/Lower/OpenMP/wsloop-reduction-logical-and.f90 b/flang/test/Lower/OpenMP/wsloop-reduction-logical-and.f90 index c059dab5bff5a..367683de02080 100644 --- a/flang/test/Lower/OpenMP/wsloop-reduction-logical-and.f90 +++ b/flang/test/Lower/OpenMP/wsloop-reduction-logical-and.f90 @@ -31,12 +31,13 @@ ! CHECK: %[[VAL_9:.*]] = fir.convert %[[VAL_8]] : (i1) -> !fir.logical<4> ! CHECK: hlfir.assign %[[VAL_9]] to %[[VAL_4]]#0 : !fir.logical<4>, !fir.ref> ! CHECK: omp.parallel { +! CHECK: %[[VAL_10:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_11:.*]]:2 = hlfir.declare %[[VAL_10]] {uniq_name = "_QFsimple_reductionEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_12:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_13:.*]] = arith.constant 100 : i32 ! CHECK: %[[VAL_14:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_10:.*]] : !fir.ref) reduction(@and_reduction %[[VAL_4]]#0 -> %[[VAL_15:.*]] : !fir.ref>) { +! CHECK: omp.wsloop reduction(@and_reduction %[[VAL_4]]#0 -> %[[VAL_15:.*]] : !fir.ref>) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_16:.*]]) : i32 = (%[[VAL_12]]) to (%[[VAL_13]]) inclusive step (%[[VAL_14]]) { -! CHECK: %[[VAL_11:.*]]:2 = hlfir.declare %[[VAL_10]] {uniq_name = "_QFsimple_reductionEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_17:.*]]:2 = hlfir.declare %[[VAL_15]] {uniq_name = "_QFsimple_reductionEx"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) ! CHECK: fir.store %[[VAL_16]] to %[[VAL_11]]#1 : !fir.ref ! CHECK: %[[VAL_18:.*]] = fir.load %[[VAL_17]]#0 : !fir.ref> @@ -79,12 +80,13 @@ end subroutine simple_reduction ! CHECK: %[[VAL_9:.*]] = fir.convert %[[VAL_8]] : (i1) -> !fir.logical<4> ! CHECK: hlfir.assign %[[VAL_9]] to %[[VAL_4]]#0 : !fir.logical<4>, !fir.ref> ! CHECK: omp.parallel { +! CHECK: %[[VAL_10:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_11:.*]]:2 = hlfir.declare %[[VAL_10]] {uniq_name = "_QFsimple_reduction_switch_orderEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_12:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_13:.*]] = arith.constant 100 : i32 ! CHECK: %[[VAL_14:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_10:.*]] : !fir.ref) reduction(@and_reduction %[[VAL_4]]#0 -> %[[VAL_15:.*]] : !fir.ref>) { +! CHECK: omp.wsloop reduction(@and_reduction %[[VAL_4]]#0 -> %[[VAL_15:.*]] : !fir.ref>) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_16:.*]]) : i32 = (%[[VAL_12]]) to (%[[VAL_13]]) inclusive step (%[[VAL_14]]) { -! CHECK: %[[VAL_11:.*]]:2 = hlfir.declare %[[VAL_10]] {uniq_name = "_QFsimple_reduction_switch_orderEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_17:.*]]:2 = hlfir.declare %[[VAL_15]] {uniq_name = "_QFsimple_reduction_switch_orderEx"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) ! CHECK: fir.store %[[VAL_16]] to %[[VAL_11]]#1 : !fir.ref ! CHECK: %[[VAL_18:.*]] = fir.load %[[VAL_11]]#0 : !fir.ref @@ -136,12 +138,13 @@ subroutine simple_reduction_switch_order(y) ! CHECK: %[[VAL_17:.*]] = fir.convert %[[VAL_16]] : (i1) -> !fir.logical<4> ! CHECK: hlfir.assign %[[VAL_17]] to %[[VAL_11]]#0 : !fir.logical<4>, !fir.ref> ! CHECK: omp.parallel { +! CHECK: %[[VAL_18:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_19:.*]]:2 = hlfir.declare %[[VAL_18]] {uniq_name = "_QFmultiple_reductionsEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_20:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_21:.*]] = arith.constant 100 : i32 ! CHECK: %[[VAL_22:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_18:.*]] : !fir.ref) reduction(@and_reduction %[[VAL_7]]#0 -> %[[VAL_23:.*]], @and_reduction %[[VAL_9]]#0 -> %[[VAL_24:.*]], @and_reduction %[[VAL_11]]#0 -> %[[VAL_25:.*]] : !fir.ref>, !fir.ref>, !fir.ref>) { +! CHECK: omp.wsloop reduction(@and_reduction %[[VAL_7]]#0 -> %[[VAL_23:.*]], @and_reduction %[[VAL_9]]#0 -> %[[VAL_24:.*]], @and_reduction %[[VAL_11]]#0 -> %[[VAL_25:.*]] : !fir.ref>, !fir.ref>, !fir.ref>) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_26:.*]]) : i32 = (%[[VAL_20]]) to (%[[VAL_21]]) inclusive step (%[[VAL_22]]) { -! CHECK: %[[VAL_19:.*]]:2 = hlfir.declare %[[VAL_18]] {uniq_name = "_QFmultiple_reductionsEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_27:.*]]:2 = hlfir.declare %[[VAL_23]] {uniq_name = "_QFmultiple_reductionsEx"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) ! CHECK: %[[VAL_28:.*]]:2 = hlfir.declare %[[VAL_24]] {uniq_name = "_QFmultiple_reductionsEy"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) ! CHECK: %[[VAL_29:.*]]:2 = hlfir.declare %[[VAL_25]] {uniq_name = "_QFmultiple_reductionsEz"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) diff --git a/flang/test/Lower/OpenMP/wsloop-reduction-logical-eqv-byref.f90 b/flang/test/Lower/OpenMP/wsloop-reduction-logical-eqv-byref.f90 index 5e24ad6f7bb63..9137dd8ff4454 100644 --- a/flang/test/Lower/OpenMP/wsloop-reduction-logical-eqv-byref.f90 +++ b/flang/test/Lower/OpenMP/wsloop-reduction-logical-eqv-byref.f90 @@ -39,12 +39,13 @@ ! CHECK: %[[VAL_9:.*]] = fir.convert %[[VAL_8]] : (i1) -> !fir.logical<4> ! CHECK: hlfir.assign %[[VAL_9]] to %[[VAL_4]]#0 : !fir.logical<4>, !fir.ref> ! CHECK: omp.parallel { +! CHECK: %[[VAL_10:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_11:.*]]:2 = hlfir.declare %[[VAL_10]] {uniq_name = "_QFsimple_reductionEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_12:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_13:.*]] = arith.constant 100 : i32 ! CHECK: %[[VAL_14:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_10:.*]] : !fir.ref) reduction(byref @eqv_reduction %[[VAL_4]]#0 -> %[[VAL_15:.*]] : !fir.ref>) { +! CHECK: omp.wsloop reduction(byref @eqv_reduction %[[VAL_4]]#0 -> %[[VAL_15:.*]] : !fir.ref>) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_16:.*]]) : i32 = (%[[VAL_12]]) to (%[[VAL_13]]) inclusive step (%[[VAL_14]]) { -! CHECK: %[[VAL_11:.*]]:2 = hlfir.declare %[[VAL_10]] {uniq_name = "_QFsimple_reductionEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_17:.*]]:2 = hlfir.declare %[[VAL_15]] {uniq_name = "_QFsimple_reductionEx"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) ! CHECK: fir.store %[[VAL_16]] to %[[VAL_11]]#1 : !fir.ref ! CHECK: %[[VAL_18:.*]] = fir.load %[[VAL_17]]#0 : !fir.ref> @@ -86,12 +87,13 @@ subroutine simple_reduction(y) ! CHECK: %[[VAL_9:.*]] = fir.convert %[[VAL_8]] : (i1) -> !fir.logical<4> ! CHECK: hlfir.assign %[[VAL_9]] to %[[VAL_4]]#0 : !fir.logical<4>, !fir.ref> ! CHECK: omp.parallel { +! CHECK: %[[VAL_10:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_11:.*]]:2 = hlfir.declare %[[VAL_10]] {uniq_name = "_QFsimple_reduction_switch_orderEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_12:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_13:.*]] = arith.constant 100 : i32 ! CHECK: %[[VAL_14:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_10:.*]] : !fir.ref) reduction(byref @eqv_reduction %[[VAL_4]]#0 -> %[[VAL_15:.*]] : !fir.ref>) { +! CHECK: omp.wsloop reduction(byref @eqv_reduction %[[VAL_4]]#0 -> %[[VAL_15:.*]] : !fir.ref>) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_16:.*]]) : i32 = (%[[VAL_12]]) to (%[[VAL_13]]) inclusive step (%[[VAL_14]]) { -! CHECK: %[[VAL_11:.*]]:2 = hlfir.declare %[[VAL_10]] {uniq_name = "_QFsimple_reduction_switch_orderEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_17:.*]]:2 = hlfir.declare %[[VAL_15]] {uniq_name = "_QFsimple_reduction_switch_orderEx"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) ! CHECK: fir.store %[[VAL_16]] to %[[VAL_11]]#1 : !fir.ref ! CHECK: %[[VAL_18:.*]] = fir.load %[[VAL_11]]#0 : !fir.ref @@ -143,12 +145,13 @@ subroutine simple_reduction_switch_order(y) ! CHECK: %[[VAL_17:.*]] = fir.convert %[[VAL_16]] : (i1) -> !fir.logical<4> ! CHECK: hlfir.assign %[[VAL_17]] to %[[VAL_11]]#0 : !fir.logical<4>, !fir.ref> ! CHECK: omp.parallel { +! CHECK: %[[VAL_18:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_19:.*]]:2 = hlfir.declare %[[VAL_18]] {uniq_name = "_QFmultiple_reductionsEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_20:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_21:.*]] = arith.constant 100 : i32 ! CHECK: %[[VAL_22:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_18:.*]] : !fir.ref) reduction(byref @eqv_reduction %[[VAL_7]]#0 -> %[[VAL_23:.*]], byref @eqv_reduction %[[VAL_9]]#0 -> %[[VAL_24:.*]], byref @eqv_reduction %[[VAL_11]]#0 -> %[[VAL_25:.*]] : !fir.ref>, !fir.ref>, !fir.ref>) { +! CHECK: omp.wsloop reduction(byref @eqv_reduction %[[VAL_7]]#0 -> %[[VAL_23:.*]], byref @eqv_reduction %[[VAL_9]]#0 -> %[[VAL_24:.*]], byref @eqv_reduction %[[VAL_11]]#0 -> %[[VAL_25:.*]] : !fir.ref>, !fir.ref>, !fir.ref>) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_26:.*]]) : i32 = (%[[VAL_20]]) to (%[[VAL_21]]) inclusive step (%[[VAL_22]]) { -! CHECK: %[[VAL_19:.*]]:2 = hlfir.declare %[[VAL_18]] {uniq_name = "_QFmultiple_reductionsEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_27:.*]]:2 = hlfir.declare %[[VAL_23]] {uniq_name = "_QFmultiple_reductionsEx"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) ! CHECK: %[[VAL_28:.*]]:2 = hlfir.declare %[[VAL_24]] {uniq_name = "_QFmultiple_reductionsEy"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) ! CHECK: %[[VAL_29:.*]]:2 = hlfir.declare %[[VAL_25]] {uniq_name = "_QFmultiple_reductionsEz"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) diff --git a/flang/test/Lower/OpenMP/wsloop-reduction-logical-eqv.f90 b/flang/test/Lower/OpenMP/wsloop-reduction-logical-eqv.f90 index ad9e869984eac..d1ef676c37407 100644 --- a/flang/test/Lower/OpenMP/wsloop-reduction-logical-eqv.f90 +++ b/flang/test/Lower/OpenMP/wsloop-reduction-logical-eqv.f90 @@ -31,12 +31,13 @@ ! CHECK: %[[VAL_9:.*]] = fir.convert %[[VAL_8]] : (i1) -> !fir.logical<4> ! CHECK: hlfir.assign %[[VAL_9]] to %[[VAL_4]]#0 : !fir.logical<4>, !fir.ref> ! CHECK: omp.parallel { +! CHECK: %[[VAL_10:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_11:.*]]:2 = hlfir.declare %[[VAL_10]] {uniq_name = "_QFsimple_reductionEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_12:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_13:.*]] = arith.constant 100 : i32 ! CHECK: %[[VAL_14:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_10:.*]] : !fir.ref) reduction(@eqv_reduction %[[VAL_4]]#0 -> %[[VAL_15:.*]] : !fir.ref>) { +! CHECK: omp.wsloop reduction(@eqv_reduction %[[VAL_4]]#0 -> %[[VAL_15:.*]] : !fir.ref>) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_16:.*]]) : i32 = (%[[VAL_12]]) to (%[[VAL_13]]) inclusive step (%[[VAL_14]]) { -! CHECK: %[[VAL_11:.*]]:2 = hlfir.declare %[[VAL_10]] {uniq_name = "_QFsimple_reductionEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_17:.*]]:2 = hlfir.declare %[[VAL_15]] {uniq_name = "_QFsimple_reductionEx"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) ! CHECK: fir.store %[[VAL_16]] to %[[VAL_11]]#1 : !fir.ref ! CHECK: %[[VAL_18:.*]] = fir.load %[[VAL_17]]#0 : !fir.ref> @@ -78,12 +79,13 @@ subroutine simple_reduction(y) ! CHECK: %[[VAL_9:.*]] = fir.convert %[[VAL_8]] : (i1) -> !fir.logical<4> ! CHECK: hlfir.assign %[[VAL_9]] to %[[VAL_4]]#0 : !fir.logical<4>, !fir.ref> ! CHECK: omp.parallel { +! CHECK: %[[VAL_10:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_11:.*]]:2 = hlfir.declare %[[VAL_10]] {uniq_name = "_QFsimple_reduction_switch_orderEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_12:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_13:.*]] = arith.constant 100 : i32 ! CHECK: %[[VAL_14:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_10:.*]] : !fir.ref) reduction(@eqv_reduction %[[VAL_4]]#0 -> %[[VAL_15:.*]] : !fir.ref>) { +! CHECK: omp.wsloop reduction(@eqv_reduction %[[VAL_4]]#0 -> %[[VAL_15:.*]] : !fir.ref>) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_16:.*]]) : i32 = (%[[VAL_12]]) to (%[[VAL_13]]) inclusive step (%[[VAL_14]]) { -! CHECK: %[[VAL_11:.*]]:2 = hlfir.declare %[[VAL_10]] {uniq_name = "_QFsimple_reduction_switch_orderEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_17:.*]]:2 = hlfir.declare %[[VAL_15]] {uniq_name = "_QFsimple_reduction_switch_orderEx"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) ! CHECK: fir.store %[[VAL_16]] to %[[VAL_11]]#1 : !fir.ref ! CHECK: %[[VAL_18:.*]] = fir.load %[[VAL_11]]#0 : !fir.ref @@ -135,12 +137,13 @@ subroutine simple_reduction_switch_order(y) ! CHECK: %[[VAL_17:.*]] = fir.convert %[[VAL_16]] : (i1) -> !fir.logical<4> ! CHECK: hlfir.assign %[[VAL_17]] to %[[VAL_11]]#0 : !fir.logical<4>, !fir.ref> ! CHECK: omp.parallel { +! CHECK: %[[VAL_18:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_19:.*]]:2 = hlfir.declare %[[VAL_18]] {uniq_name = "_QFmultiple_reductionsEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_20:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_21:.*]] = arith.constant 100 : i32 ! CHECK: %[[VAL_22:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_18:.*]] : !fir.ref) reduction(@eqv_reduction %[[VAL_7]]#0 -> %[[VAL_23:.*]], @eqv_reduction %[[VAL_9]]#0 -> %[[VAL_24:.*]], @eqv_reduction %[[VAL_11]]#0 -> %[[VAL_25:.*]] : !fir.ref>, !fir.ref>, !fir.ref>) { +! CHECK: omp.wsloop reduction(@eqv_reduction %[[VAL_7]]#0 -> %[[VAL_23:.*]], @eqv_reduction %[[VAL_9]]#0 -> %[[VAL_24:.*]], @eqv_reduction %[[VAL_11]]#0 -> %[[VAL_25:.*]] : !fir.ref>, !fir.ref>, !fir.ref>) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_26:.*]]) : i32 = (%[[VAL_20]]) to (%[[VAL_21]]) inclusive step (%[[VAL_22]]) { -! CHECK: %[[VAL_19:.*]]:2 = hlfir.declare %[[VAL_18]] {uniq_name = "_QFmultiple_reductionsEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_27:.*]]:2 = hlfir.declare %[[VAL_23]] {uniq_name = "_QFmultiple_reductionsEx"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) ! CHECK: %[[VAL_28:.*]]:2 = hlfir.declare %[[VAL_24]] {uniq_name = "_QFmultiple_reductionsEy"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) ! CHECK: %[[VAL_29:.*]]:2 = hlfir.declare %[[VAL_25]] {uniq_name = "_QFmultiple_reductionsEz"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) diff --git a/flang/test/Lower/OpenMP/wsloop-reduction-logical-neqv-byref.f90 b/flang/test/Lower/OpenMP/wsloop-reduction-logical-neqv-byref.f90 index b5bf1d0d0b589..d1491a0f5561d 100644 --- a/flang/test/Lower/OpenMP/wsloop-reduction-logical-neqv-byref.f90 +++ b/flang/test/Lower/OpenMP/wsloop-reduction-logical-neqv-byref.f90 @@ -39,12 +39,13 @@ ! CHECK: %[[VAL_9:.*]] = fir.convert %[[VAL_8]] : (i1) -> !fir.logical<4> ! CHECK: hlfir.assign %[[VAL_9]] to %[[VAL_4]]#0 : !fir.logical<4>, !fir.ref> ! CHECK: omp.parallel { +! CHECK: %[[VAL_10:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_11:.*]]:2 = hlfir.declare %[[VAL_10]] {uniq_name = "_QFsimple_reductionEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_12:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_13:.*]] = arith.constant 100 : i32 ! CHECK: %[[VAL_14:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_10:.*]] : !fir.ref) reduction(byref @neqv_reduction %[[VAL_4]]#0 -> %[[VAL_15:.*]] : !fir.ref>) { +! CHECK: omp.wsloop reduction(byref @neqv_reduction %[[VAL_4]]#0 -> %[[VAL_15:.*]] : !fir.ref>) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_16:.*]]) : i32 = (%[[VAL_12]]) to (%[[VAL_13]]) inclusive step (%[[VAL_14]]) { -! CHECK: %[[VAL_11:.*]]:2 = hlfir.declare %[[VAL_10]] {uniq_name = "_QFsimple_reductionEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_17:.*]]:2 = hlfir.declare %[[VAL_15]] {uniq_name = "_QFsimple_reductionEx"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) ! CHECK: fir.store %[[VAL_16]] to %[[VAL_11]]#1 : !fir.ref ! CHECK: %[[VAL_18:.*]] = fir.load %[[VAL_17]]#0 : !fir.ref> @@ -87,12 +88,13 @@ subroutine simple_reduction(y) ! CHECK: %[[VAL_9:.*]] = fir.convert %[[VAL_8]] : (i1) -> !fir.logical<4> ! CHECK: hlfir.assign %[[VAL_9]] to %[[VAL_4]]#0 : !fir.logical<4>, !fir.ref> ! CHECK: omp.parallel { +! CHECK: %[[VAL_10:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_11:.*]]:2 = hlfir.declare %[[VAL_10]] {uniq_name = "_QFsimple_reduction_switch_orderEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_12:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_13:.*]] = arith.constant 100 : i32 ! CHECK: %[[VAL_14:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_10:.*]] : !fir.ref) reduction(byref @neqv_reduction %[[VAL_4]]#0 -> %[[VAL_15:.*]] : !fir.ref>) { +! CHECK: omp.wsloop reduction(byref @neqv_reduction %[[VAL_4]]#0 -> %[[VAL_15:.*]] : !fir.ref>) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_16:.*]]) : i32 = (%[[VAL_12]]) to (%[[VAL_13]]) inclusive step (%[[VAL_14]]) { -! CHECK: %[[VAL_11:.*]]:2 = hlfir.declare %[[VAL_10]] {uniq_name = "_QFsimple_reduction_switch_orderEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_17:.*]]:2 = hlfir.declare %[[VAL_15]] {uniq_name = "_QFsimple_reduction_switch_orderEx"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) ! CHECK: fir.store %[[VAL_16]] to %[[VAL_11]]#1 : !fir.ref ! CHECK: %[[VAL_18:.*]] = fir.load %[[VAL_11]]#0 : !fir.ref @@ -146,12 +148,13 @@ subroutine simple_reduction_switch_order(y) ! CHECK: %[[VAL_17:.*]] = fir.convert %[[VAL_16]] : (i1) -> !fir.logical<4> ! CHECK: hlfir.assign %[[VAL_17]] to %[[VAL_11]]#0 : !fir.logical<4>, !fir.ref> ! CHECK: omp.parallel { +! CHECK: %[[VAL_18:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_19:.*]]:2 = hlfir.declare %[[VAL_18]] {uniq_name = "_QFmultiple_reductionsEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_20:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_21:.*]] = arith.constant 100 : i32 ! CHECK: %[[VAL_22:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_18:.*]] : !fir.ref) reduction(byref @neqv_reduction %[[VAL_7]]#0 -> %[[VAL_23:.*]], byref @neqv_reduction %[[VAL_9]]#0 -> %[[VAL_24:.*]], byref @neqv_reduction %[[VAL_11]]#0 -> %[[VAL_25:.*]] : !fir.ref>, !fir.ref>, !fir.ref>) { +! CHECK: omp.wsloop reduction(byref @neqv_reduction %[[VAL_7]]#0 -> %[[VAL_23:.*]], byref @neqv_reduction %[[VAL_9]]#0 -> %[[VAL_24:.*]], byref @neqv_reduction %[[VAL_11]]#0 -> %[[VAL_25:.*]] : !fir.ref>, !fir.ref>, !fir.ref>) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_26:.*]]) : i32 = (%[[VAL_20]]) to (%[[VAL_21]]) inclusive step (%[[VAL_22]]) { -! CHECK: %[[VAL_19:.*]]:2 = hlfir.declare %[[VAL_18]] {uniq_name = "_QFmultiple_reductionsEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_27:.*]]:2 = hlfir.declare %[[VAL_23]] {uniq_name = "_QFmultiple_reductionsEx"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) ! CHECK: %[[VAL_28:.*]]:2 = hlfir.declare %[[VAL_24]] {uniq_name = "_QFmultiple_reductionsEy"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) ! CHECK: %[[VAL_29:.*]]:2 = hlfir.declare %[[VAL_25]] {uniq_name = "_QFmultiple_reductionsEz"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) diff --git a/flang/test/Lower/OpenMP/wsloop-reduction-logical-neqv.f90 b/flang/test/Lower/OpenMP/wsloop-reduction-logical-neqv.f90 index ac9fc7f051d88..b4df699c49ffa 100644 --- a/flang/test/Lower/OpenMP/wsloop-reduction-logical-neqv.f90 +++ b/flang/test/Lower/OpenMP/wsloop-reduction-logical-neqv.f90 @@ -31,12 +31,13 @@ ! CHECK: %[[VAL_9:.*]] = fir.convert %[[VAL_8]] : (i1) -> !fir.logical<4> ! CHECK: hlfir.assign %[[VAL_9]] to %[[VAL_4]]#0 : !fir.logical<4>, !fir.ref> ! CHECK: omp.parallel { +! CHECK: %[[VAL_10:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_11:.*]]:2 = hlfir.declare %[[VAL_10]] {uniq_name = "_QFsimple_reductionEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_12:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_13:.*]] = arith.constant 100 : i32 ! CHECK: %[[VAL_14:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_10:.*]] : !fir.ref) reduction(@neqv_reduction %[[VAL_4]]#0 -> %[[VAL_15:.*]] : !fir.ref>) { +! CHECK: omp.wsloop reduction(@neqv_reduction %[[VAL_4]]#0 -> %[[VAL_15:.*]] : !fir.ref>) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_16:.*]]) : i32 = (%[[VAL_12]]) to (%[[VAL_13]]) inclusive step (%[[VAL_14]]) { -! CHECK: %[[VAL_11:.*]]:2 = hlfir.declare %[[VAL_10]] {uniq_name = "_QFsimple_reductionEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_17:.*]]:2 = hlfir.declare %[[VAL_15]] {uniq_name = "_QFsimple_reductionEx"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) ! CHECK: fir.store %[[VAL_16]] to %[[VAL_11]]#1 : !fir.ref ! CHECK: %[[VAL_18:.*]] = fir.load %[[VAL_17]]#0 : !fir.ref> @@ -79,12 +80,13 @@ subroutine simple_reduction(y) ! CHECK: %[[VAL_9:.*]] = fir.convert %[[VAL_8]] : (i1) -> !fir.logical<4> ! CHECK: hlfir.assign %[[VAL_9]] to %[[VAL_4]]#0 : !fir.logical<4>, !fir.ref> ! CHECK: omp.parallel { +! CHECK: %[[VAL_10:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_11:.*]]:2 = hlfir.declare %[[VAL_10]] {uniq_name = "_QFsimple_reduction_switch_orderEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_12:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_13:.*]] = arith.constant 100 : i32 ! CHECK: %[[VAL_14:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_10:.*]] : !fir.ref) reduction(@neqv_reduction %[[VAL_4]]#0 -> %[[VAL_15:.*]] : !fir.ref>) { +! CHECK: omp.wsloop reduction(@neqv_reduction %[[VAL_4]]#0 -> %[[VAL_15:.*]] : !fir.ref>) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_16:.*]]) : i32 = (%[[VAL_12]]) to (%[[VAL_13]]) inclusive step (%[[VAL_14]]) { -! CHECK: %[[VAL_11:.*]]:2 = hlfir.declare %[[VAL_10]] {uniq_name = "_QFsimple_reduction_switch_orderEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_17:.*]]:2 = hlfir.declare %[[VAL_15]] {uniq_name = "_QFsimple_reduction_switch_orderEx"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) ! CHECK: fir.store %[[VAL_16]] to %[[VAL_11]]#1 : !fir.ref ! CHECK: %[[VAL_18:.*]] = fir.load %[[VAL_11]]#0 : !fir.ref @@ -138,12 +140,13 @@ subroutine simple_reduction_switch_order(y) ! CHECK: %[[VAL_17:.*]] = fir.convert %[[VAL_16]] : (i1) -> !fir.logical<4> ! CHECK: hlfir.assign %[[VAL_17]] to %[[VAL_11]]#0 : !fir.logical<4>, !fir.ref> ! CHECK: omp.parallel { +! CHECK: %[[VAL_18:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_19:.*]]:2 = hlfir.declare %[[VAL_18]] {uniq_name = "_QFmultiple_reductionsEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_20:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_21:.*]] = arith.constant 100 : i32 ! CHECK: %[[VAL_22:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_18:.*]] : !fir.ref) reduction(@neqv_reduction %[[VAL_7]]#0 -> %[[VAL_23:.*]], @neqv_reduction %[[VAL_9]]#0 -> %[[VAL_24:.*]], @neqv_reduction %[[VAL_11]]#0 -> %[[VAL_25:.*]] : !fir.ref>, !fir.ref>, !fir.ref>) { +! CHECK: omp.wsloop reduction(@neqv_reduction %[[VAL_7]]#0 -> %[[VAL_23:.*]], @neqv_reduction %[[VAL_9]]#0 -> %[[VAL_24:.*]], @neqv_reduction %[[VAL_11]]#0 -> %[[VAL_25:.*]] : !fir.ref>, !fir.ref>, !fir.ref>) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_26:.*]]) : i32 = (%[[VAL_20]]) to (%[[VAL_21]]) inclusive step (%[[VAL_22]]) { -! CHECK: %[[VAL_19:.*]]:2 = hlfir.declare %[[VAL_18]] {uniq_name = "_QFmultiple_reductionsEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_27:.*]]:2 = hlfir.declare %[[VAL_23]] {uniq_name = "_QFmultiple_reductionsEx"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) ! CHECK: %[[VAL_28:.*]]:2 = hlfir.declare %[[VAL_24]] {uniq_name = "_QFmultiple_reductionsEy"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) ! CHECK: %[[VAL_29:.*]]:2 = hlfir.declare %[[VAL_25]] {uniq_name = "_QFmultiple_reductionsEz"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) diff --git a/flang/test/Lower/OpenMP/wsloop-reduction-logical-or-byref.f90 b/flang/test/Lower/OpenMP/wsloop-reduction-logical-or-byref.f90 index 883064884b637..8f4a6c22c1d74 100644 --- a/flang/test/Lower/OpenMP/wsloop-reduction-logical-or-byref.f90 +++ b/flang/test/Lower/OpenMP/wsloop-reduction-logical-or-byref.f90 @@ -38,12 +38,13 @@ ! CHECK: %[[VAL_9:.*]] = fir.convert %[[VAL_8]] : (i1) -> !fir.logical<4> ! CHECK: hlfir.assign %[[VAL_9]] to %[[VAL_4]]#0 : !fir.logical<4>, !fir.ref> ! CHECK: omp.parallel { +! CHECK: %[[VAL_10:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_11:.*]]:2 = hlfir.declare %[[VAL_10]] {uniq_name = "_QFsimple_reductionEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_12:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_13:.*]] = arith.constant 100 : i32 ! CHECK: %[[VAL_14:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_10:.*]] : !fir.ref) reduction(byref @or_reduction %[[VAL_4]]#0 -> %[[VAL_15:.*]] : !fir.ref>) { +! CHECK: omp.wsloop reduction(byref @or_reduction %[[VAL_4]]#0 -> %[[VAL_15:.*]] : !fir.ref>) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_16:.*]]) : i32 = (%[[VAL_12]]) to (%[[VAL_13]]) inclusive step (%[[VAL_14]]) { -! CHECK: %[[VAL_11:.*]]:2 = hlfir.declare %[[VAL_10]] {uniq_name = "_QFsimple_reductionEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_17:.*]]:2 = hlfir.declare %[[VAL_15]] {uniq_name = "_QFsimple_reductionEx"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) ! CHECK: fir.store %[[VAL_16]] to %[[VAL_11]]#1 : !fir.ref ! CHECK: %[[VAL_18:.*]] = fir.load %[[VAL_17]]#0 : !fir.ref> @@ -85,12 +86,13 @@ subroutine simple_reduction(y) ! CHECK: %[[VAL_9:.*]] = fir.convert %[[VAL_8]] : (i1) -> !fir.logical<4> ! CHECK: hlfir.assign %[[VAL_9]] to %[[VAL_4]]#0 : !fir.logical<4>, !fir.ref> ! CHECK: omp.parallel { +! CHECK: %[[VAL_10:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_11:.*]]:2 = hlfir.declare %[[VAL_10]] {uniq_name = "_QFsimple_reduction_switch_orderEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_12:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_13:.*]] = arith.constant 100 : i32 ! CHECK: %[[VAL_14:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_10:.*]] : !fir.ref) reduction(byref @or_reduction %[[VAL_4]]#0 -> %[[VAL_15:.*]] : !fir.ref>) { +! CHECK: omp.wsloop reduction(byref @or_reduction %[[VAL_4]]#0 -> %[[VAL_15:.*]] : !fir.ref>) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_16:.*]]) : i32 = (%[[VAL_12]]) to (%[[VAL_13]]) inclusive step (%[[VAL_14]]) { -! CHECK: %[[VAL_11:.*]]:2 = hlfir.declare %[[VAL_10]] {uniq_name = "_QFsimple_reduction_switch_orderEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_17:.*]]:2 = hlfir.declare %[[VAL_15]] {uniq_name = "_QFsimple_reduction_switch_orderEx"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) ! CHECK: fir.store %[[VAL_16]] to %[[VAL_11]]#1 : !fir.ref ! CHECK: %[[VAL_18:.*]] = fir.load %[[VAL_11]]#0 : !fir.ref @@ -142,12 +144,13 @@ subroutine simple_reduction_switch_order(y) ! CHECK: %[[VAL_17:.*]] = fir.convert %[[VAL_16]] : (i1) -> !fir.logical<4> ! CHECK: hlfir.assign %[[VAL_17]] to %[[VAL_11]]#0 : !fir.logical<4>, !fir.ref> ! CHECK: omp.parallel { +! CHECK: %[[VAL_18:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_19:.*]]:2 = hlfir.declare %[[VAL_18]] {uniq_name = "_QFmultiple_reductionsEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_20:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_21:.*]] = arith.constant 100 : i32 ! CHECK: %[[VAL_22:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_18:.*]] : !fir.ref) reduction(byref @or_reduction %[[VAL_7]]#0 -> %[[VAL_23:.*]], byref @or_reduction %[[VAL_9]]#0 -> %[[VAL_24:.*]], byref @or_reduction %[[VAL_11]]#0 -> %[[VAL_25:.*]] : !fir.ref>, !fir.ref>, !fir.ref>) { +! CHECK: omp.wsloop reduction(byref @or_reduction %[[VAL_7]]#0 -> %[[VAL_23:.*]], byref @or_reduction %[[VAL_9]]#0 -> %[[VAL_24:.*]], byref @or_reduction %[[VAL_11]]#0 -> %[[VAL_25:.*]] : !fir.ref>, !fir.ref>, !fir.ref>) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_26:.*]]) : i32 = (%[[VAL_20]]) to (%[[VAL_21]]) inclusive step (%[[VAL_22]]) { -! CHECK: %[[VAL_19:.*]]:2 = hlfir.declare %[[VAL_18]] {uniq_name = "_QFmultiple_reductionsEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_27:.*]]:2 = hlfir.declare %[[VAL_23]] {uniq_name = "_QFmultiple_reductionsEx"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) ! CHECK: %[[VAL_28:.*]]:2 = hlfir.declare %[[VAL_24]] {uniq_name = "_QFmultiple_reductionsEy"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) ! CHECK: %[[VAL_29:.*]]:2 = hlfir.declare %[[VAL_25]] {uniq_name = "_QFmultiple_reductionsEz"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) diff --git a/flang/test/Lower/OpenMP/wsloop-reduction-logical-or.f90 b/flang/test/Lower/OpenMP/wsloop-reduction-logical-or.f90 index 312c08d17a14d..9d367797ec216 100644 --- a/flang/test/Lower/OpenMP/wsloop-reduction-logical-or.f90 +++ b/flang/test/Lower/OpenMP/wsloop-reduction-logical-or.f90 @@ -31,12 +31,13 @@ ! CHECK: %[[VAL_9:.*]] = fir.convert %[[VAL_8]] : (i1) -> !fir.logical<4> ! CHECK: hlfir.assign %[[VAL_9]] to %[[VAL_4]]#0 : !fir.logical<4>, !fir.ref> ! CHECK: omp.parallel { +! CHECK: %[[VAL_10:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_11:.*]]:2 = hlfir.declare %[[VAL_10]] {uniq_name = "_QFsimple_reductionEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_12:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_13:.*]] = arith.constant 100 : i32 ! CHECK: %[[VAL_14:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_10:.*]] : !fir.ref) reduction(@or_reduction %[[VAL_4]]#0 -> %[[VAL_15:.*]] : !fir.ref>) { +! CHECK: omp.wsloop reduction(@or_reduction %[[VAL_4]]#0 -> %[[VAL_15:.*]] : !fir.ref>) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_16:.*]]) : i32 = (%[[VAL_12]]) to (%[[VAL_13]]) inclusive step (%[[VAL_14]]) { -! CHECK: %[[VAL_11:.*]]:2 = hlfir.declare %[[VAL_10]] {uniq_name = "_QFsimple_reductionEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_17:.*]]:2 = hlfir.declare %[[VAL_15]] {uniq_name = "_QFsimple_reductionEx"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) ! CHECK: fir.store %[[VAL_16]] to %[[VAL_11]]#1 : !fir.ref ! CHECK: %[[VAL_18:.*]] = fir.load %[[VAL_17]]#0 : !fir.ref> @@ -78,12 +79,13 @@ subroutine simple_reduction(y) ! CHECK: %[[VAL_9:.*]] = fir.convert %[[VAL_8]] : (i1) -> !fir.logical<4> ! CHECK: hlfir.assign %[[VAL_9]] to %[[VAL_4]]#0 : !fir.logical<4>, !fir.ref> ! CHECK: omp.parallel { +! CHECK: %[[VAL_10:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_11:.*]]:2 = hlfir.declare %[[VAL_10]] {uniq_name = "_QFsimple_reduction_switch_orderEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_12:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_13:.*]] = arith.constant 100 : i32 ! CHECK: %[[VAL_14:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_10:.*]] : !fir.ref) reduction(@or_reduction %[[VAL_4]]#0 -> %[[VAL_15:.*]] : !fir.ref>) { +! CHECK: omp.wsloop reduction(@or_reduction %[[VAL_4]]#0 -> %[[VAL_15:.*]] : !fir.ref>) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_16:.*]]) : i32 = (%[[VAL_12]]) to (%[[VAL_13]]) inclusive step (%[[VAL_14]]) { -! CHECK: %[[VAL_11:.*]]:2 = hlfir.declare %[[VAL_10]] {uniq_name = "_QFsimple_reduction_switch_orderEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_17:.*]]:2 = hlfir.declare %[[VAL_15]] {uniq_name = "_QFsimple_reduction_switch_orderEx"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) ! CHECK: fir.store %[[VAL_16]] to %[[VAL_11]]#1 : !fir.ref ! CHECK: %[[VAL_18:.*]] = fir.load %[[VAL_11]]#0 : !fir.ref @@ -135,12 +137,13 @@ subroutine simple_reduction_switch_order(y) ! CHECK: %[[VAL_17:.*]] = fir.convert %[[VAL_16]] : (i1) -> !fir.logical<4> ! CHECK: hlfir.assign %[[VAL_17]] to %[[VAL_11]]#0 : !fir.logical<4>, !fir.ref> ! CHECK: omp.parallel { +! CHECK: %[[VAL_18:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_19:.*]]:2 = hlfir.declare %[[VAL_18]] {uniq_name = "_QFmultiple_reductionsEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_20:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_21:.*]] = arith.constant 100 : i32 ! CHECK: %[[VAL_22:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_18:.*]] : !fir.ref) reduction(@or_reduction %[[VAL_7]]#0 -> %[[VAL_23:.*]], @or_reduction %[[VAL_9]]#0 -> %[[VAL_24:.*]], @or_reduction %[[VAL_11]]#0 -> %[[VAL_25:.*]] : !fir.ref>, !fir.ref>, !fir.ref>) { +! CHECK: omp.wsloop reduction(@or_reduction %[[VAL_7]]#0 -> %[[VAL_23:.*]], @or_reduction %[[VAL_9]]#0 -> %[[VAL_24:.*]], @or_reduction %[[VAL_11]]#0 -> %[[VAL_25:.*]] : !fir.ref>, !fir.ref>, !fir.ref>) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_26:.*]]) : i32 = (%[[VAL_20]]) to (%[[VAL_21]]) inclusive step (%[[VAL_22]]) { -! CHECK: %[[VAL_19:.*]]:2 = hlfir.declare %[[VAL_18]] {uniq_name = "_QFmultiple_reductionsEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_27:.*]]:2 = hlfir.declare %[[VAL_23]] {uniq_name = "_QFmultiple_reductionsEx"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) ! CHECK: %[[VAL_28:.*]]:2 = hlfir.declare %[[VAL_24]] {uniq_name = "_QFmultiple_reductionsEy"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) ! CHECK: %[[VAL_29:.*]]:2 = hlfir.declare %[[VAL_25]] {uniq_name = "_QFmultiple_reductionsEz"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) diff --git a/flang/test/Lower/OpenMP/wsloop-reduction-max-2-byref.f90 b/flang/test/Lower/OpenMP/wsloop-reduction-max-2-byref.f90 index 0438e19f34391..28c70899e6ccc 100644 --- a/flang/test/Lower/OpenMP/wsloop-reduction-max-2-byref.f90 +++ b/flang/test/Lower/OpenMP/wsloop-reduction-max-2-byref.f90 @@ -1,7 +1,7 @@ ! RUN: bbc -emit-hlfir -fopenmp --force-byref-reduction -o - %s 2>&1 | FileCheck %s ! RUN: %flang_fc1 -emit-hlfir -fopenmp -mmlir --force-byref-reduction -o - %s 2>&1 | FileCheck %s -! CHECK: omp.wsloop private({{.*}}) reduction(byref @max_byref_i32 +! CHECK: omp.wsloop reduction(byref @max_byref_i32 ! CHECK: arith.cmpi sgt ! CHECK: arith.select diff --git a/flang/test/Lower/OpenMP/wsloop-reduction-max-2.f90 b/flang/test/Lower/OpenMP/wsloop-reduction-max-2.f90 index 66c75bbe38f10..abd7ca1ae555d 100644 --- a/flang/test/Lower/OpenMP/wsloop-reduction-max-2.f90 +++ b/flang/test/Lower/OpenMP/wsloop-reduction-max-2.f90 @@ -1,7 +1,7 @@ ! RUN: bbc -emit-hlfir -fopenmp -o - %s 2>&1 | FileCheck %s ! RUN: %flang_fc1 -emit-hlfir -fopenmp -o - %s 2>&1 | FileCheck %s -! CHECK: omp.wsloop private({{.*}}) reduction(@max_i32 +! CHECK: omp.wsloop reduction(@max_i32 ! CHECK: arith.cmpi sgt ! CHECK: arith.select diff --git a/flang/test/Lower/OpenMP/wsloop-reduction-max-byref.f90 b/flang/test/Lower/OpenMP/wsloop-reduction-max-byref.f90 index 07c18f90480bf..9abff8ccfa3b6 100644 --- a/flang/test/Lower/OpenMP/wsloop-reduction-max-byref.f90 +++ b/flang/test/Lower/OpenMP/wsloop-reduction-max-byref.f90 @@ -45,12 +45,13 @@ ! CHECK: %[[VAL_6:.*]] = arith.constant 0 : i32 ! CHECK: hlfir.assign %[[VAL_6]] to %[[VAL_4]]#0 : i32, !fir.ref ! CHECK: omp.parallel { +! CHECK: %[[VAL_7:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_8:.*]]:2 = hlfir.declare %[[VAL_7]] {uniq_name = "_QFreduction_max_intEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_9:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_10:.*]] = arith.constant 100 : i32 ! CHECK: %[[VAL_11:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_7:.*]] : !fir.ref) reduction(byref @max_byref_i32 %[[VAL_4]]#0 -> %[[VAL_12:.*]] : !fir.ref) { +! CHECK: omp.wsloop reduction(byref @max_byref_i32 %[[VAL_4]]#0 -> %[[VAL_12:.*]] : !fir.ref) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_13:.*]]) : i32 = (%[[VAL_9]]) to (%[[VAL_10]]) inclusive step (%[[VAL_11]]) { -! CHECK: %[[VAL_8:.*]]:2 = hlfir.declare %[[VAL_7]] {uniq_name = "_QFreduction_max_intEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_14:.*]]:2 = hlfir.declare %[[VAL_12]] {uniq_name = "_QFreduction_max_intEx"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: fir.store %[[VAL_13]] to %[[VAL_8]]#1 : !fir.ref ! CHECK: %[[VAL_15:.*]] = fir.load %[[VAL_8]]#0 : !fir.ref @@ -74,12 +75,13 @@ ! CHECK: %[[VAL_6:.*]] = arith.constant 0.000000e+00 : f32 ! CHECK: hlfir.assign %[[VAL_6]] to %[[VAL_4]]#0 : f32, !fir.ref ! CHECK: omp.parallel { +! CHECK: %[[VAL_7:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_8:.*]]:2 = hlfir.declare %[[VAL_7]] {uniq_name = "_QFreduction_max_realEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_9:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_10:.*]] = arith.constant 100 : i32 ! CHECK: %[[VAL_11:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_7:.*]] : !fir.ref) reduction(byref @max_byref_f32 %[[VAL_4]]#0 -> %[[VAL_12:.*]] : !fir.ref) { +! CHECK: omp.wsloop reduction(byref @max_byref_f32 %[[VAL_4]]#0 -> %[[VAL_12:.*]] : !fir.ref) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_13:.*]]) : i32 = (%[[VAL_9]]) to (%[[VAL_10]]) inclusive step (%[[VAL_11]]) { -! CHECK: %[[VAL_8:.*]]:2 = hlfir.declare %[[VAL_7]] {uniq_name = "_QFreduction_max_realEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_14:.*]]:2 = hlfir.declare %[[VAL_12]] {uniq_name = "_QFreduction_max_realEx"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: fir.store %[[VAL_13]] to %[[VAL_8]]#1 : !fir.ref ! CHECK: %[[VAL_15:.*]] = fir.load %[[VAL_8]]#0 : !fir.ref @@ -93,12 +95,13 @@ ! CHECK: omp.yield ! CHECK: omp.terminator ! CHECK: omp.parallel { +! CHECK: %[[VAL_30:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_31:.*]]:2 = hlfir.declare %[[VAL_30]] {uniq_name = "_QFreduction_max_realEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_32:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_33:.*]] = arith.constant 100 : i32 ! CHECK: %[[VAL_34:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_30:.*]] : !fir.ref) reduction(byref @max_byref_f32 %[[VAL_4]]#0 -> %[[VAL_35:.*]] : !fir.ref) { +! CHECK: omp.wsloop reduction(byref @max_byref_f32 %[[VAL_4]]#0 -> %[[VAL_35:.*]] : !fir.ref) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_36:.*]]) : i32 = (%[[VAL_32]]) to (%[[VAL_33]]) inclusive step (%[[VAL_34]]) { -! CHECK: %[[VAL_31:.*]]:2 = hlfir.declare %[[VAL_30]] {uniq_name = "_QFreduction_max_realEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_37:.*]]:2 = hlfir.declare %[[VAL_35]] {uniq_name = "_QFreduction_max_realEx"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: fir.store %[[VAL_36]] to %[[VAL_31]]#1 : !fir.ref ! CHECK: %[[VAL_38:.*]] = fir.load %[[VAL_31]]#0 : !fir.ref diff --git a/flang/test/Lower/OpenMP/wsloop-reduction-max.f90 b/flang/test/Lower/OpenMP/wsloop-reduction-max.f90 index 7bdfa0948c747..7237d3f903b74 100644 --- a/flang/test/Lower/OpenMP/wsloop-reduction-max.f90 +++ b/flang/test/Lower/OpenMP/wsloop-reduction-max.f90 @@ -35,12 +35,13 @@ ! CHECK: %[[VAL_6:.*]] = arith.constant 0 : i32 ! CHECK: hlfir.assign %[[VAL_6]] to %[[VAL_4]]#0 : i32, !fir.ref ! CHECK: omp.parallel { +! CHECK: %[[VAL_7:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_8:.*]]:2 = hlfir.declare %[[VAL_7]] {uniq_name = "_QFreduction_max_intEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_9:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_10:.*]] = arith.constant 100 : i32 ! CHECK: %[[VAL_11:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_7:.*]] : !fir.ref) reduction(@max_i32 %[[VAL_4]]#0 -> %[[VAL_12:.*]] : !fir.ref) { +! CHECK: omp.wsloop reduction(@max_i32 %[[VAL_4]]#0 -> %[[VAL_12:.*]] : !fir.ref) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_13:.*]]) : i32 = (%[[VAL_9]]) to (%[[VAL_10]]) inclusive step (%[[VAL_11]]) { -! CHECK: %[[VAL_8:.*]]:2 = hlfir.declare %[[VAL_7]] {uniq_name = "_QFreduction_max_intEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_14:.*]]:2 = hlfir.declare %[[VAL_12]] {uniq_name = "_QFreduction_max_intEx"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: fir.store %[[VAL_13]] to %[[VAL_8]]#1 : !fir.ref ! CHECK: %[[VAL_15:.*]] = fir.load %[[VAL_8]]#0 : !fir.ref @@ -64,12 +65,13 @@ ! CHECK: %[[VAL_6:.*]] = arith.constant 0.000000e+00 : f32 ! CHECK: hlfir.assign %[[VAL_6]] to %[[VAL_4]]#0 : f32, !fir.ref ! CHECK: omp.parallel { +! CHECK: %[[VAL_7:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_8:.*]]:2 = hlfir.declare %[[VAL_7]] {uniq_name = "_QFreduction_max_realEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_9:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_10:.*]] = arith.constant 100 : i32 ! CHECK: %[[VAL_11:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_7:.*]] : !fir.ref) reduction(@max_f32 %[[VAL_4]]#0 -> %[[VAL_12:.*]] : !fir.ref) { +! CHECK: omp.wsloop reduction(@max_f32 %[[VAL_4]]#0 -> %[[VAL_12:.*]] : !fir.ref) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_13:.*]]) : i32 = (%[[VAL_9]]) to (%[[VAL_10]]) inclusive step (%[[VAL_11]]) { -! CHECK: %[[VAL_8:.*]]:2 = hlfir.declare %[[VAL_7]] {uniq_name = "_QFreduction_max_realEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_14:.*]]:2 = hlfir.declare %[[VAL_12]] {uniq_name = "_QFreduction_max_realEx"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: fir.store %[[VAL_13]] to %[[VAL_8]]#1 : !fir.ref ! CHECK: %[[VAL_15:.*]] = fir.load %[[VAL_8]]#0 : !fir.ref @@ -83,12 +85,13 @@ ! CHECK: omp.yield ! CHECK: omp.terminator ! CHECK: omp.parallel { +! CHECK: %[[VAL_30:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_31:.*]]:2 = hlfir.declare %[[VAL_30]] {uniq_name = "_QFreduction_max_realEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_32:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_33:.*]] = arith.constant 100 : i32 ! CHECK: %[[VAL_34:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_30:.*]] : !fir.ref) reduction(@max_f32 %[[VAL_4]]#0 -> %[[VAL_35:.*]] : !fir.ref) { +! CHECK: omp.wsloop reduction(@max_f32 %[[VAL_4]]#0 -> %[[VAL_35:.*]] : !fir.ref) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_36:.*]]) : i32 = (%[[VAL_32]]) to (%[[VAL_33]]) inclusive step (%[[VAL_34]]) { -! CHECK: %[[VAL_31:.*]]:2 = hlfir.declare %[[VAL_30]] {uniq_name = "_QFreduction_max_realEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_37:.*]]:2 = hlfir.declare %[[VAL_35]] {uniq_name = "_QFreduction_max_realEx"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: fir.store %[[VAL_36]] to %[[VAL_31]]#1 : !fir.ref ! CHECK: %[[VAL_38:.*]] = fir.load %[[VAL_31]]#0 : !fir.ref diff --git a/flang/test/Lower/OpenMP/wsloop-reduction-min-byref.f90 b/flang/test/Lower/OpenMP/wsloop-reduction-min-byref.f90 index 88a455f4b45ac..a4bfbaa09d2fa 100644 --- a/flang/test/Lower/OpenMP/wsloop-reduction-min-byref.f90 +++ b/flang/test/Lower/OpenMP/wsloop-reduction-min-byref.f90 @@ -45,12 +45,13 @@ ! CHECK: %[[VAL_6:.*]] = arith.constant 0 : i32 ! CHECK: hlfir.assign %[[VAL_6]] to %[[VAL_4]]#0 : i32, !fir.ref ! CHECK: omp.parallel { +! CHECK: %[[VAL_7:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_8:.*]]:2 = hlfir.declare %[[VAL_7]] {uniq_name = "_QFreduction_min_intEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_9:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_10:.*]] = arith.constant 100 : i32 ! CHECK: %[[VAL_11:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_7:.*]] : !fir.ref) reduction(byref @min_byref_i32 %[[VAL_4]]#0 -> %[[VAL_12:.*]] : !fir.ref) { +! CHECK: omp.wsloop reduction(byref @min_byref_i32 %[[VAL_4]]#0 -> %[[VAL_12:.*]] : !fir.ref) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_13:.*]]) : i32 = (%[[VAL_9]]) to (%[[VAL_10]]) inclusive step (%[[VAL_11]]) { -! CHECK: %[[VAL_8:.*]]:2 = hlfir.declare %[[VAL_7]] {uniq_name = "_QFreduction_min_intEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_14:.*]]:2 = hlfir.declare %[[VAL_12]] {uniq_name = "_QFreduction_min_intEx"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: fir.store %[[VAL_13]] to %[[VAL_8]]#1 : !fir.ref ! CHECK: %[[VAL_15:.*]] = fir.load %[[VAL_8]]#0 : !fir.ref @@ -74,12 +75,13 @@ ! CHECK: %[[VAL_6:.*]] = arith.constant 0.000000e+00 : f32 ! CHECK: hlfir.assign %[[VAL_6]] to %[[VAL_4]]#0 : f32, !fir.ref ! CHECK: omp.parallel { +! CHECK: %[[VAL_7:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_8:.*]]:2 = hlfir.declare %[[VAL_7]] {uniq_name = "_QFreduction_min_realEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_9:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_10:.*]] = arith.constant 100 : i32 ! CHECK: %[[VAL_11:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_7:.*]] : !fir.ref) reduction(byref @min_byref_f32 %[[VAL_4]]#0 -> %[[VAL_12:.*]] : !fir.ref) { +! CHECK: omp.wsloop reduction(byref @min_byref_f32 %[[VAL_4]]#0 -> %[[VAL_12:.*]] : !fir.ref) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_13:.*]]) : i32 = (%[[VAL_9]]) to (%[[VAL_10]]) inclusive step (%[[VAL_11]]) { -! CHECK: %[[VAL_8:.*]]:2 = hlfir.declare %[[VAL_7]] {uniq_name = "_QFreduction_min_realEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_14:.*]]:2 = hlfir.declare %[[VAL_12]] {uniq_name = "_QFreduction_min_realEx"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: fir.store %[[VAL_13]] to %[[VAL_8]]#1 : !fir.ref ! CHECK: %[[VAL_15:.*]] = fir.load %[[VAL_8]]#0 : !fir.ref @@ -95,12 +97,13 @@ ! CHECK: omp.terminator ! CHECK: } ! CHECK: omp.parallel { +! CHECK: %[[VAL_30:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_31:.*]]:2 = hlfir.declare %[[VAL_30]] {uniq_name = "_QFreduction_min_realEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_32:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_33:.*]] = arith.constant 100 : i32 ! CHECK: %[[VAL_34:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_30:.*]] : !fir.ref) reduction(byref @min_byref_f32 %[[VAL_4]]#0 -> %[[VAL_35:.*]] : !fir.ref) { +! CHECK: omp.wsloop reduction(byref @min_byref_f32 %[[VAL_4]]#0 -> %[[VAL_35:.*]] : !fir.ref) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_36:.*]]) : i32 = (%[[VAL_32]]) to (%[[VAL_33]]) inclusive step (%[[VAL_34]]) { -! CHECK: %[[VAL_31:.*]]:2 = hlfir.declare %[[VAL_30]] {uniq_name = "_QFreduction_min_realEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_37:.*]]:2 = hlfir.declare %[[VAL_35]] {uniq_name = "_QFreduction_min_realEx"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: fir.store %[[VAL_36]] to %[[VAL_31]]#1 : !fir.ref ! CHECK: %[[VAL_38:.*]] = fir.load %[[VAL_31]]#0 : !fir.ref diff --git a/flang/test/Lower/OpenMP/wsloop-reduction-min.f90 b/flang/test/Lower/OpenMP/wsloop-reduction-min.f90 index 6d4dcf1ab68eb..ce9e53a17523c 100644 --- a/flang/test/Lower/OpenMP/wsloop-reduction-min.f90 +++ b/flang/test/Lower/OpenMP/wsloop-reduction-min.f90 @@ -35,12 +35,13 @@ ! CHECK: %[[VAL_6:.*]] = arith.constant 0 : i32 ! CHECK: hlfir.assign %[[VAL_6]] to %[[VAL_4]]#0 : i32, !fir.ref ! CHECK: omp.parallel { +! CHECK: %[[VAL_7:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_8:.*]]:2 = hlfir.declare %[[VAL_7]] {uniq_name = "_QFreduction_min_intEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_9:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_10:.*]] = arith.constant 100 : i32 ! CHECK: %[[VAL_11:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_7:.*]] : !fir.ref) reduction(@min_i32 %[[VAL_4]]#0 -> %[[VAL_12:.*]] : !fir.ref) { +! CHECK: omp.wsloop reduction(@min_i32 %[[VAL_4]]#0 -> %[[VAL_12:.*]] : !fir.ref) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_13:.*]]) : i32 = (%[[VAL_9]]) to (%[[VAL_10]]) inclusive step (%[[VAL_11]]) { -! CHECK: %[[VAL_8:.*]]:2 = hlfir.declare %[[VAL_7]] {uniq_name = "_QFreduction_min_intEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_14:.*]]:2 = hlfir.declare %[[VAL_12]] {uniq_name = "_QFreduction_min_intEx"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: fir.store %[[VAL_13]] to %[[VAL_8]]#1 : !fir.ref ! CHECK: %[[VAL_15:.*]] = fir.load %[[VAL_8]]#0 : !fir.ref @@ -64,12 +65,13 @@ ! CHECK: %[[VAL_6:.*]] = arith.constant 0.000000e+00 : f32 ! CHECK: hlfir.assign %[[VAL_6]] to %[[VAL_4]]#0 : f32, !fir.ref ! CHECK: omp.parallel { +! CHECK: %[[VAL_7:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_8:.*]]:2 = hlfir.declare %[[VAL_7]] {uniq_name = "_QFreduction_min_realEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_9:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_10:.*]] = arith.constant 100 : i32 ! CHECK: %[[VAL_11:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_7:.*]] : !fir.ref) reduction(@min_f32 %[[VAL_4]]#0 -> %[[VAL_12:.*]] : !fir.ref) { +! CHECK: omp.wsloop reduction(@min_f32 %[[VAL_4]]#0 -> %[[VAL_12:.*]] : !fir.ref) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_13:.*]]) : i32 = (%[[VAL_9]]) to (%[[VAL_10]]) inclusive step (%[[VAL_11]]) { -! CHECK: %[[VAL_8:.*]]:2 = hlfir.declare %[[VAL_7]] {uniq_name = "_QFreduction_min_realEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_14:.*]]:2 = hlfir.declare %[[VAL_12]] {uniq_name = "_QFreduction_min_realEx"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: fir.store %[[VAL_13]] to %[[VAL_8]]#1 : !fir.ref ! CHECK: %[[VAL_15:.*]] = fir.load %[[VAL_8]]#0 : !fir.ref @@ -85,12 +87,13 @@ ! CHECK: omp.terminator ! CHECK: } ! CHECK: omp.parallel { +! CHECK: %[[VAL_30:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_31:.*]]:2 = hlfir.declare %[[VAL_30]] {uniq_name = "_QFreduction_min_realEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_32:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_33:.*]] = arith.constant 100 : i32 ! CHECK: %[[VAL_34:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_30:.*]] : !fir.ref) reduction(@min_f32 %[[VAL_4]]#0 -> %[[VAL_35:.*]] : !fir.ref) { +! CHECK: omp.wsloop reduction(@min_f32 %[[VAL_4]]#0 -> %[[VAL_35:.*]] : !fir.ref) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_36:.*]]) : i32 = (%[[VAL_32]]) to (%[[VAL_33]]) inclusive step (%[[VAL_34]]) { -! CHECK: %[[VAL_31:.*]]:2 = hlfir.declare %[[VAL_30]] {uniq_name = "_QFreduction_min_realEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_37:.*]]:2 = hlfir.declare %[[VAL_35]] {uniq_name = "_QFreduction_min_realEx"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: fir.store %[[VAL_36]] to %[[VAL_31]]#1 : !fir.ref ! CHECK: %[[VAL_38:.*]] = fir.load %[[VAL_31]]#0 : !fir.ref diff --git a/flang/test/Lower/OpenMP/wsloop-reduction-min2.f90 b/flang/test/Lower/OpenMP/wsloop-reduction-min2.f90 index db8e59cb09dfa..d83ebb77af3eb 100644 --- a/flang/test/Lower/OpenMP/wsloop-reduction-min2.f90 +++ b/flang/test/Lower/OpenMP/wsloop-reduction-min2.f90 @@ -34,12 +34,13 @@ program reduce ! CHECK: %[[VAL_2:.*]] = fir.address_of(@_QFEr) : !fir.ref ! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_2]] {uniq_name = "_QFEr"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: omp.parallel { +! CHECK: %[[VAL_4:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_5:.*]]:2 = hlfir.declare %[[VAL_4]] {uniq_name = "_QFEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_6:.*]] = arith.constant 0 : i32 ! CHECK: %[[VAL_7:.*]] = arith.constant 10 : i32 ! CHECK: %[[VAL_8:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_4:.*]] : !fir.ref) reduction(@min_i32 %[[VAL_3]]#0 -> %[[VAL_9:.*]] : !fir.ref) { +! CHECK: omp.wsloop reduction(@min_i32 %[[VAL_3]]#0 -> %[[VAL_9:.*]] : !fir.ref) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_10:.*]]) : i32 = (%[[VAL_6]]) to (%[[VAL_7]]) inclusive step (%[[VAL_8]]) { -! CHECK: %[[VAL_5:.*]]:2 = hlfir.declare %[[VAL_4]] {uniq_name = "_QFEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_11:.*]]:2 = hlfir.declare %[[VAL_9]] {uniq_name = "_QFEr"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: fir.store %[[VAL_10]] to %[[VAL_5]]#1 : !fir.ref ! CHECK: %[[VAL_12:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref diff --git a/flang/test/Lower/OpenMP/wsloop-reduction-mul-byref.f90 b/flang/test/Lower/OpenMP/wsloop-reduction-mul-byref.f90 index 85df29e83f75d..18554fbb72aee 100644 --- a/flang/test/Lower/OpenMP/wsloop-reduction-mul-byref.f90 +++ b/flang/test/Lower/OpenMP/wsloop-reduction-mul-byref.f90 @@ -88,12 +88,13 @@ ! CHECK: %[[VAL_4:.*]] = arith.constant 1 : i32 ! CHECK: hlfir.assign %[[VAL_4]] to %[[VAL_3]]#0 : i32, !fir.ref ! CHECK: omp.parallel { +! CHECK: %[[VAL_5:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_5]] {uniq_name = "_QFsimple_int_reductionEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_7:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_8:.*]] = arith.constant 10 : i32 ! CHECK: %[[VAL_9:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_5:.*]] : !fir.ref) reduction(byref @multiply_reduction_byref_i32 %[[VAL_3]]#0 -> %[[VAL_10:.*]] : !fir.ref) { +! CHECK: omp.wsloop reduction(byref @multiply_reduction_byref_i32 %[[VAL_3]]#0 -> %[[VAL_10:.*]] : !fir.ref) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_11:.*]]) : i32 = (%[[VAL_7]]) to (%[[VAL_8]]) inclusive step (%[[VAL_9]]) { -! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_5]] {uniq_name = "_QFsimple_int_reductionEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_12:.*]]:2 = hlfir.declare %[[VAL_10]] {uniq_name = "_QFsimple_int_reductionEx"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: fir.store %[[VAL_11]] to %[[VAL_6]]#1 : !fir.ref ! CHECK: %[[VAL_13:.*]] = fir.load %[[VAL_12]]#0 : !fir.ref @@ -124,12 +125,13 @@ subroutine simple_int_reduction ! CHECK: %[[VAL_4:.*]] = arith.constant 1.000000e+00 : f32 ! CHECK: hlfir.assign %[[VAL_4]] to %[[VAL_3]]#0 : f32, !fir.ref ! CHECK: omp.parallel { +! CHECK: %[[VAL_5:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_5]] {uniq_name = "_QFsimple_real_reductionEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_7:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_8:.*]] = arith.constant 10 : i32 ! CHECK: %[[VAL_9:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_5:.*]] : !fir.ref) reduction(byref @multiply_reduction_byref_f32 %[[VAL_3]]#0 -> %[[VAL_10:.*]] : !fir.ref) { +! CHECK: omp.wsloop reduction(byref @multiply_reduction_byref_f32 %[[VAL_3]]#0 -> %[[VAL_10:.*]] : !fir.ref) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_11:.*]]) : i32 = (%[[VAL_7]]) to (%[[VAL_8]]) inclusive step (%[[VAL_9]]) { -! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_5]] {uniq_name = "_QFsimple_real_reductionEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_12:.*]]:2 = hlfir.declare %[[VAL_10]] {uniq_name = "_QFsimple_real_reductionEx"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: fir.store %[[VAL_11]] to %[[VAL_6]]#1 : !fir.ref ! CHECK: %[[VAL_13:.*]] = fir.load %[[VAL_12]]#0 : !fir.ref @@ -161,12 +163,13 @@ subroutine simple_real_reduction ! CHECK: %[[VAL_4:.*]] = arith.constant 1 : i32 ! CHECK: hlfir.assign %[[VAL_4]] to %[[VAL_3]]#0 : i32, !fir.ref ! CHECK: omp.parallel { +! CHECK: %[[VAL_5:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_5]] {uniq_name = "_QFsimple_int_reduction_switch_orderEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_7:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_8:.*]] = arith.constant 10 : i32 ! CHECK: %[[VAL_9:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_5:.*]] : !fir.ref) reduction(byref @multiply_reduction_byref_i32 %[[VAL_3]]#0 -> %[[VAL_10:.*]] : !fir.ref) { +! CHECK: omp.wsloop reduction(byref @multiply_reduction_byref_i32 %[[VAL_3]]#0 -> %[[VAL_10:.*]] : !fir.ref) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_11:.*]]) : i32 = (%[[VAL_7]]) to (%[[VAL_8]]) inclusive step (%[[VAL_9]]) { -! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_5]] {uniq_name = "_QFsimple_int_reduction_switch_orderEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_12:.*]]:2 = hlfir.declare %[[VAL_10]] {uniq_name = "_QFsimple_int_reduction_switch_orderEx"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: fir.store %[[VAL_11]] to %[[VAL_6]]#1 : !fir.ref ! CHECK: %[[VAL_13:.*]] = fir.load %[[VAL_6]]#0 : !fir.ref @@ -197,12 +200,13 @@ subroutine simple_int_reduction_switch_order ! CHECK: %[[VAL_4:.*]] = arith.constant 1.000000e+00 : f32 ! CHECK: hlfir.assign %[[VAL_4]] to %[[VAL_3]]#0 : f32, !fir.ref ! CHECK: omp.parallel { +! CHECK: %[[VAL_5:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_5]] {uniq_name = "_QFsimple_real_reduction_switch_orderEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_7:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_8:.*]] = arith.constant 10 : i32 ! CHECK: %[[VAL_9:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_5:.*]] : !fir.ref) reduction(byref @multiply_reduction_byref_f32 %[[VAL_3]]#0 -> %[[VAL_10:.*]] : !fir.ref) { +! CHECK: omp.wsloop reduction(byref @multiply_reduction_byref_f32 %[[VAL_3]]#0 -> %[[VAL_10:.*]] : !fir.ref) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_11:.*]]) : i32 = (%[[VAL_7]]) to (%[[VAL_8]]) inclusive step (%[[VAL_9]]) { -! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_5]] {uniq_name = "_QFsimple_real_reduction_switch_orderEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_12:.*]]:2 = hlfir.declare %[[VAL_10]] {uniq_name = "_QFsimple_real_reduction_switch_orderEx"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: fir.store %[[VAL_11]] to %[[VAL_6]]#1 : !fir.ref ! CHECK: %[[VAL_13:.*]] = fir.load %[[VAL_6]]#0 : !fir.ref @@ -242,12 +246,13 @@ subroutine simple_real_reduction_switch_order ! CHECK: %[[VAL_10:.*]] = arith.constant 1 : i32 ! CHECK: hlfir.assign %[[VAL_10]] to %[[VAL_7]]#0 : i32, !fir.ref ! CHECK: omp.parallel { +! CHECK: %[[VAL_11:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_12:.*]]:2 = hlfir.declare %[[VAL_11]] {uniq_name = "_QFmultiple_int_reductions_same_typeEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_13:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_14:.*]] = arith.constant 10 : i32 ! CHECK: %[[VAL_15:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_11:.*]] : !fir.ref) reduction(byref @multiply_reduction_byref_i32 %[[VAL_3]]#0 -> %[[VAL_16:.*]], byref @multiply_reduction_byref_i32 %[[VAL_5]]#0 -> %[[VAL_17:.*]], byref @multiply_reduction_byref_i32 %[[VAL_7]]#0 -> %[[VAL_18:.*]] : !fir.ref, !fir.ref, !fir.ref) { +! CHECK: omp.wsloop reduction(byref @multiply_reduction_byref_i32 %[[VAL_3]]#0 -> %[[VAL_16:.*]], byref @multiply_reduction_byref_i32 %[[VAL_5]]#0 -> %[[VAL_17:.*]], byref @multiply_reduction_byref_i32 %[[VAL_7]]#0 -> %[[VAL_18:.*]] : !fir.ref, !fir.ref, !fir.ref) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_19:.*]]) : i32 = (%[[VAL_13]]) to (%[[VAL_14]]) inclusive step (%[[VAL_15]]) { -! CHECK: %[[VAL_12:.*]]:2 = hlfir.declare %[[VAL_11]] {uniq_name = "_QFmultiple_int_reductions_same_typeEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_20:.*]]:2 = hlfir.declare %[[VAL_16]] {uniq_name = "_QFmultiple_int_reductions_same_typeEx"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_21:.*]]:2 = hlfir.declare %[[VAL_17]] {uniq_name = "_QFmultiple_int_reductions_same_typeEy"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_22:.*]]:2 = hlfir.declare %[[VAL_18]] {uniq_name = "_QFmultiple_int_reductions_same_typeEz"} : (!fir.ref) -> (!fir.ref, !fir.ref) @@ -300,12 +305,13 @@ subroutine multiple_int_reductions_same_type ! CHECK: %[[VAL_10:.*]] = arith.constant 1.000000e+00 : f32 ! CHECK: hlfir.assign %[[VAL_10]] to %[[VAL_7]]#0 : f32, !fir.ref ! CHECK: omp.parallel { +! CHECK: %[[VAL_11:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_12:.*]]:2 = hlfir.declare %[[VAL_11]] {uniq_name = "_QFmultiple_real_reductions_same_typeEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_13:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_14:.*]] = arith.constant 10 : i32 ! CHECK: %[[VAL_15:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_11:.*]] : !fir.ref) reduction(byref @multiply_reduction_byref_f32 %[[VAL_3]]#0 -> %[[VAL_16:.*]], byref @multiply_reduction_byref_f32 %[[VAL_5]]#0 -> %[[VAL_17:.*]], byref @multiply_reduction_byref_f32 %[[VAL_7]]#0 -> %[[VAL_18:.*]] : !fir.ref, !fir.ref, !fir.ref) { +! CHECK: omp.wsloop reduction(byref @multiply_reduction_byref_f32 %[[VAL_3]]#0 -> %[[VAL_16:.*]], byref @multiply_reduction_byref_f32 %[[VAL_5]]#0 -> %[[VAL_17:.*]], byref @multiply_reduction_byref_f32 %[[VAL_7]]#0 -> %[[VAL_18:.*]] : !fir.ref, !fir.ref, !fir.ref) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_19:.*]]) : i32 = (%[[VAL_13]]) to (%[[VAL_14]]) inclusive step (%[[VAL_15]]) { -! CHECK: %[[VAL_12:.*]]:2 = hlfir.declare %[[VAL_11]] {uniq_name = "_QFmultiple_real_reductions_same_typeEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_20:.*]]:2 = hlfir.declare %[[VAL_16]] {uniq_name = "_QFmultiple_real_reductions_same_typeEx"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_21:.*]]:2 = hlfir.declare %[[VAL_17]] {uniq_name = "_QFmultiple_real_reductions_same_typeEy"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_22:.*]]:2 = hlfir.declare %[[VAL_18]] {uniq_name = "_QFmultiple_real_reductions_same_typeEz"} : (!fir.ref) -> (!fir.ref, !fir.ref) @@ -365,12 +371,13 @@ subroutine multiple_real_reductions_same_type ! CHECK: %[[VAL_13:.*]] = arith.constant 1.000000e+00 : f64 ! CHECK: hlfir.assign %[[VAL_13]] to %[[VAL_3]]#0 : f64, !fir.ref ! CHECK: omp.parallel { +! CHECK: %[[VAL_14:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_15:.*]]:2 = hlfir.declare %[[VAL_14]] {uniq_name = "_QFmultiple_reductions_different_typeEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_16:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_17:.*]] = arith.constant 10 : i32 ! CHECK: %[[VAL_18:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_14:.*]] : !fir.ref) reduction(byref @multiply_reduction_byref_i32 %[[VAL_5]]#0 -> %[[VAL_19:.*]], byref @multiply_reduction_byref_i64 %[[VAL_7]]#0 -> %[[VAL_20:.*]], byref @multiply_reduction_byref_f32 %[[VAL_9]]#0 -> %[[VAL_21:.*]], byref @multiply_reduction_byref_f64 %[[VAL_3]]#0 -> %[[VAL_22:.*]] : !fir.ref, !fir.ref, !fir.ref, !fir.ref) { +! CHECK: omp.wsloop reduction(byref @multiply_reduction_byref_i32 %[[VAL_5]]#0 -> %[[VAL_19:.*]], byref @multiply_reduction_byref_i64 %[[VAL_7]]#0 -> %[[VAL_20:.*]], byref @multiply_reduction_byref_f32 %[[VAL_9]]#0 -> %[[VAL_21:.*]], byref @multiply_reduction_byref_f64 %[[VAL_3]]#0 -> %[[VAL_22:.*]] : !fir.ref, !fir.ref, !fir.ref, !fir.ref) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_23:.*]]) : i32 = (%[[VAL_16]]) to (%[[VAL_17]]) inclusive step (%[[VAL_18]]) { -! CHECK: %[[VAL_15:.*]]:2 = hlfir.declare %[[VAL_14]] {uniq_name = "_QFmultiple_reductions_different_typeEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_24:.*]]:2 = hlfir.declare %[[VAL_19]] {uniq_name = "_QFmultiple_reductions_different_typeEx"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_25:.*]]:2 = hlfir.declare %[[VAL_20]] {uniq_name = "_QFmultiple_reductions_different_typeEy"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_26:.*]]:2 = hlfir.declare %[[VAL_21]] {uniq_name = "_QFmultiple_reductions_different_typeEz"} : (!fir.ref) -> (!fir.ref, !fir.ref) diff --git a/flang/test/Lower/OpenMP/wsloop-reduction-mul.f90 b/flang/test/Lower/OpenMP/wsloop-reduction-mul.f90 index 09c44f187f4a2..f5c12ccf61f76 100644 --- a/flang/test/Lower/OpenMP/wsloop-reduction-mul.f90 +++ b/flang/test/Lower/OpenMP/wsloop-reduction-mul.f90 @@ -55,12 +55,13 @@ ! CHECK: %[[VAL_4:.*]] = arith.constant 1 : i32 ! CHECK: hlfir.assign %[[VAL_4]] to %[[VAL_3]]#0 : i32, !fir.ref ! CHECK: omp.parallel { +! CHECK: %[[VAL_5:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_5]] {uniq_name = "_QFsimple_int_reductionEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_7:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_8:.*]] = arith.constant 10 : i32 ! CHECK: %[[VAL_9:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_5:.*]] : !fir.ref) reduction(@multiply_reduction_i32 %[[VAL_3]]#0 -> %[[VAL_10:.*]] : !fir.ref) { +! CHECK: omp.wsloop reduction(@multiply_reduction_i32 %[[VAL_3]]#0 -> %[[VAL_10:.*]] : !fir.ref) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_11:.*]]) : i32 = (%[[VAL_7]]) to (%[[VAL_8]]) inclusive step (%[[VAL_9]]) { -! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_5]] {uniq_name = "_QFsimple_int_reductionEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_12:.*]]:2 = hlfir.declare %[[VAL_10]] {uniq_name = "_QFsimple_int_reductionEx"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: fir.store %[[VAL_11]] to %[[VAL_6]]#1 : !fir.ref ! CHECK: %[[VAL_13:.*]] = fir.load %[[VAL_12]]#0 : !fir.ref @@ -91,12 +92,13 @@ subroutine simple_int_reduction ! CHECK: %[[VAL_4:.*]] = arith.constant 1.000000e+00 : f32 ! CHECK: hlfir.assign %[[VAL_4]] to %[[VAL_3]]#0 : f32, !fir.ref ! CHECK: omp.parallel { +! CHECK: %[[VAL_5:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_5]] {uniq_name = "_QFsimple_real_reductionEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_7:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_8:.*]] = arith.constant 10 : i32 ! CHECK: %[[VAL_9:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_5:.*]] : !fir.ref) reduction(@multiply_reduction_f32 %[[VAL_3]]#0 -> %[[VAL_10:.*]] : !fir.ref) { +! CHECK: omp.wsloop reduction(@multiply_reduction_f32 %[[VAL_3]]#0 -> %[[VAL_10:.*]] : !fir.ref) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_11:.*]]) : i32 = (%[[VAL_7]]) to (%[[VAL_8]]) inclusive step (%[[VAL_9]]) { -! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_5]] {uniq_name = "_QFsimple_real_reductionEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_12:.*]]:2 = hlfir.declare %[[VAL_10]] {uniq_name = "_QFsimple_real_reductionEx"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: fir.store %[[VAL_11]] to %[[VAL_6]]#1 : !fir.ref ! CHECK: %[[VAL_13:.*]] = fir.load %[[VAL_12]]#0 : !fir.ref @@ -128,12 +130,13 @@ subroutine simple_real_reduction ! CHECK: %[[VAL_4:.*]] = arith.constant 1 : i32 ! CHECK: hlfir.assign %[[VAL_4]] to %[[VAL_3]]#0 : i32, !fir.ref ! CHECK: omp.parallel { +! CHECK: %[[VAL_5:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_5]] {uniq_name = "_QFsimple_int_reduction_switch_orderEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_7:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_8:.*]] = arith.constant 10 : i32 ! CHECK: %[[VAL_9:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_5:.*]] : !fir.ref) reduction(@multiply_reduction_i32 %[[VAL_3]]#0 -> %[[VAL_10:.*]] : !fir.ref) { +! CHECK: omp.wsloop reduction(@multiply_reduction_i32 %[[VAL_3]]#0 -> %[[VAL_10:.*]] : !fir.ref) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_11:.*]]) : i32 = (%[[VAL_7]]) to (%[[VAL_8]]) inclusive step (%[[VAL_9]]) { -! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_5]] {uniq_name = "_QFsimple_int_reduction_switch_orderEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_12:.*]]:2 = hlfir.declare %[[VAL_10]] {uniq_name = "_QFsimple_int_reduction_switch_orderEx"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: fir.store %[[VAL_11]] to %[[VAL_6]]#1 : !fir.ref ! CHECK: %[[VAL_13:.*]] = fir.load %[[VAL_6]]#0 : !fir.ref @@ -164,12 +167,13 @@ subroutine simple_int_reduction_switch_order ! CHECK: %[[VAL_4:.*]] = arith.constant 1.000000e+00 : f32 ! CHECK: hlfir.assign %[[VAL_4]] to %[[VAL_3]]#0 : f32, !fir.ref ! CHECK: omp.parallel { +! CHECK: %[[VAL_5:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_5]] {uniq_name = "_QFsimple_real_reduction_switch_orderEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_7:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_8:.*]] = arith.constant 10 : i32 ! CHECK: %[[VAL_9:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_5:.*]] : !fir.ref) reduction(@multiply_reduction_f32 %[[VAL_3]]#0 -> %[[VAL_10:.*]] : !fir.ref) { +! CHECK: omp.wsloop reduction(@multiply_reduction_f32 %[[VAL_3]]#0 -> %[[VAL_10:.*]] : !fir.ref) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_11:.*]]) : i32 = (%[[VAL_7]]) to (%[[VAL_8]]) inclusive step (%[[VAL_9]]) { -! CHECK: %[[VAL_6:.*]]:2 = hlfir.declare %[[VAL_5]] {uniq_name = "_QFsimple_real_reduction_switch_orderEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_12:.*]]:2 = hlfir.declare %[[VAL_10]] {uniq_name = "_QFsimple_real_reduction_switch_orderEx"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: fir.store %[[VAL_11]] to %[[VAL_6]]#1 : !fir.ref ! CHECK: %[[VAL_13:.*]] = fir.load %[[VAL_6]]#0 : !fir.ref @@ -209,12 +213,13 @@ subroutine simple_real_reduction_switch_order ! CHECK: %[[VAL_10:.*]] = arith.constant 1 : i32 ! CHECK: hlfir.assign %[[VAL_10]] to %[[VAL_7]]#0 : i32, !fir.ref ! CHECK: omp.parallel { +! CHECK: %[[VAL_11:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_12:.*]]:2 = hlfir.declare %[[VAL_11]] {uniq_name = "_QFmultiple_int_reductions_same_typeEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_13:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_14:.*]] = arith.constant 10 : i32 ! CHECK: %[[VAL_15:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_11:.*]] : !fir.ref) reduction(@multiply_reduction_i32 %[[VAL_3]]#0 -> %[[VAL_16:.*]], @multiply_reduction_i32 %[[VAL_5]]#0 -> %[[VAL_17:.*]], @multiply_reduction_i32 %[[VAL_7]]#0 -> %[[VAL_18:.*]] : !fir.ref, !fir.ref, !fir.ref) { +! CHECK: omp.wsloop reduction(@multiply_reduction_i32 %[[VAL_3]]#0 -> %[[VAL_16:.*]], @multiply_reduction_i32 %[[VAL_5]]#0 -> %[[VAL_17:.*]], @multiply_reduction_i32 %[[VAL_7]]#0 -> %[[VAL_18:.*]] : !fir.ref, !fir.ref, !fir.ref) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_19:.*]]) : i32 = (%[[VAL_13]]) to (%[[VAL_14]]) inclusive step (%[[VAL_15]]) { -! CHECK: %[[VAL_12:.*]]:2 = hlfir.declare %[[VAL_11]] {uniq_name = "_QFmultiple_int_reductions_same_typeEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_20:.*]]:2 = hlfir.declare %[[VAL_16]] {uniq_name = "_QFmultiple_int_reductions_same_typeEx"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_21:.*]]:2 = hlfir.declare %[[VAL_17]] {uniq_name = "_QFmultiple_int_reductions_same_typeEy"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_22:.*]]:2 = hlfir.declare %[[VAL_18]] {uniq_name = "_QFmultiple_int_reductions_same_typeEz"} : (!fir.ref) -> (!fir.ref, !fir.ref) @@ -267,12 +272,13 @@ subroutine multiple_int_reductions_same_type ! CHECK: %[[VAL_10:.*]] = arith.constant 1.000000e+00 : f32 ! CHECK: hlfir.assign %[[VAL_10]] to %[[VAL_7]]#0 : f32, !fir.ref ! CHECK: omp.parallel { +! CHECK: %[[VAL_11:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_12:.*]]:2 = hlfir.declare %[[VAL_11]] {uniq_name = "_QFmultiple_real_reductions_same_typeEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_13:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_14:.*]] = arith.constant 10 : i32 ! CHECK: %[[VAL_15:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_11:.*]] : !fir.ref) reduction(@multiply_reduction_f32 %[[VAL_3]]#0 -> %[[VAL_16:.*]], @multiply_reduction_f32 %[[VAL_5]]#0 -> %[[VAL_17:.*]], @multiply_reduction_f32 %[[VAL_7]]#0 -> %[[VAL_18:.*]] : !fir.ref, !fir.ref, !fir.ref) { +! CHECK: omp.wsloop reduction(@multiply_reduction_f32 %[[VAL_3]]#0 -> %[[VAL_16:.*]], @multiply_reduction_f32 %[[VAL_5]]#0 -> %[[VAL_17:.*]], @multiply_reduction_f32 %[[VAL_7]]#0 -> %[[VAL_18:.*]] : !fir.ref, !fir.ref, !fir.ref) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_19:.*]]) : i32 = (%[[VAL_13]]) to (%[[VAL_14]]) inclusive step (%[[VAL_15]]) { -! CHECK: %[[VAL_12:.*]]:2 = hlfir.declare %[[VAL_11]] {uniq_name = "_QFmultiple_real_reductions_same_typeEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_20:.*]]:2 = hlfir.declare %[[VAL_16]] {uniq_name = "_QFmultiple_real_reductions_same_typeEx"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_21:.*]]:2 = hlfir.declare %[[VAL_17]] {uniq_name = "_QFmultiple_real_reductions_same_typeEy"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_22:.*]]:2 = hlfir.declare %[[VAL_18]] {uniq_name = "_QFmultiple_real_reductions_same_typeEz"} : (!fir.ref) -> (!fir.ref, !fir.ref) @@ -332,12 +338,13 @@ subroutine multiple_real_reductions_same_type ! CHECK: %[[VAL_13:.*]] = arith.constant 1.000000e+00 : f64 ! CHECK: hlfir.assign %[[VAL_13]] to %[[VAL_3]]#0 : f64, !fir.ref ! CHECK: omp.parallel { +! CHECK: %[[VAL_14:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_15:.*]]:2 = hlfir.declare %[[VAL_14]] {uniq_name = "_QFmultiple_reductions_different_typeEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_16:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_17:.*]] = arith.constant 10 : i32 ! CHECK: %[[VAL_18:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_14:.*]] : !fir.ref) reduction(@multiply_reduction_i32 %[[VAL_5]]#0 -> %[[VAL_19:.*]], @multiply_reduction_i64 %[[VAL_7]]#0 -> %[[VAL_20:.*]], @multiply_reduction_f32 %[[VAL_9]]#0 -> %[[VAL_21:.*]], @multiply_reduction_f64 %[[VAL_3]]#0 -> %[[VAL_22:.*]] : !fir.ref, !fir.ref, !fir.ref, !fir.ref) { +! CHECK: omp.wsloop reduction(@multiply_reduction_i32 %[[VAL_5]]#0 -> %[[VAL_19:.*]], @multiply_reduction_i64 %[[VAL_7]]#0 -> %[[VAL_20:.*]], @multiply_reduction_f32 %[[VAL_9]]#0 -> %[[VAL_21:.*]], @multiply_reduction_f64 %[[VAL_3]]#0 -> %[[VAL_22:.*]] : !fir.ref, !fir.ref, !fir.ref, !fir.ref) { ! CHECK-NEXT: omp.loop_nest (%[[VAL_23:.*]]) : i32 = (%[[VAL_16]]) to (%[[VAL_17]]) inclusive step (%[[VAL_18]]) { -! CHECK: %[[VAL_15:.*]]:2 = hlfir.declare %[[VAL_14]] {uniq_name = "_QFmultiple_reductions_different_typeEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_24:.*]]:2 = hlfir.declare %[[VAL_19]] {uniq_name = "_QFmultiple_reductions_different_typeEx"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_25:.*]]:2 = hlfir.declare %[[VAL_20]] {uniq_name = "_QFmultiple_reductions_different_typeEy"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_26:.*]]:2 = hlfir.declare %[[VAL_21]] {uniq_name = "_QFmultiple_reductions_different_typeEz"} : (!fir.ref) -> (!fir.ref, !fir.ref) diff --git a/flang/test/Lower/OpenMP/wsloop-reduction-multi.f90 b/flang/test/Lower/OpenMP/wsloop-reduction-multi.f90 index 66229259adf82..659ba06005670 100644 --- a/flang/test/Lower/OpenMP/wsloop-reduction-multi.f90 +++ b/flang/test/Lower/OpenMP/wsloop-reduction-multi.f90 @@ -41,7 +41,7 @@ !CHECK: %[[Y_DECL:.*]]:2 = hlfir.declare %[[Y_REF]] {uniq_name = "_QFmultiple_reductionEy"} : (!fir.ref) -> (!fir.ref, !fir.ref) !CHECK: %[[Z_REF:.*]] = fir.alloca i32 {bindc_name = "z", uniq_name = "_QFmultiple_reductionEz"} !CHECK: %[[Z_DECL:.*]]:2 = hlfir.declare %[[Z_REF]] {uniq_name = "_QFmultiple_reductionEz"} : (!fir.ref) -> (!fir.ref, !fir.ref) -!CHECK: omp.wsloop private({{.*}}) reduction( +!CHECK: omp.wsloop reduction( !CHECK-SAME: @[[ADD_RED_I32_NAME]] %[[X_DECL]]#0 -> %[[PRV_X:[^,]+]], !CHECK-SAME: @[[ADD_RED_F32_NAME]] %[[Y_DECL]]#0 -> %[[PRV_Y:[^,]+]], !CHECK-SAME: @[[MIN_RED_I32_NAME]] %[[Z_DECL]]#0 -> %[[PRV_Z:.+]] : diff --git a/flang/test/Lower/OpenMP/wsloop-reduction-multiple-clauses.f90 b/flang/test/Lower/OpenMP/wsloop-reduction-multiple-clauses.f90 index 75773416e4840..5b6ab095b45b6 100644 --- a/flang/test/Lower/OpenMP/wsloop-reduction-multiple-clauses.f90 +++ b/flang/test/Lower/OpenMP/wsloop-reduction-multiple-clauses.f90 @@ -112,12 +112,13 @@ program main ! CHECK: %[[VAL_11:.*]] = fir.embox %[[VAL_4]]#0(%[[VAL_3]]) : (!fir.ref>, !fir.shape<2>) -> !fir.box> ! CHECK: %[[VAL_12:.*]] = fir.alloca !fir.box> ! CHECK: fir.store %[[VAL_11]] to %[[VAL_12]] : !fir.ref>> +! CHECK: %[[VAL_13:.*]] = fir.alloca i32 {bindc_name = "i", pinned, {{.*}}} +! CHECK: %[[VAL_14:.*]]:2 = hlfir.declare %[[VAL_13]] {uniq_name = "_QFEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_15:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_16:.*]] = arith.constant 10 : i32 ! CHECK: %[[VAL_17:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_13:.*]] : !fir.ref) reduction(@add_reduction_f64 %[[VAL_8]]#0 -> %[[VAL_18:.*]], byref @add_reduction_byref_box_3x3xf64 %[[VAL_12]] -> %[[VAL_19:.*]] : !fir.ref, !fir.ref>>) { +! CHECK: omp.wsloop reduction(@add_reduction_f64 %[[VAL_8]]#0 -> %[[VAL_18:.*]], byref @add_reduction_byref_box_3x3xf64 %[[VAL_12]] -> %[[VAL_19:.*]] : !fir.ref, !fir.ref>>) { ! CHECK: omp.loop_nest (%[[VAL_20:.*]]) : i32 = (%[[VAL_15]]) to (%[[VAL_16]]) inclusive step (%[[VAL_17]]) { -! CHECK: %[[VAL_14:.*]]:2 = hlfir.declare %[[VAL_13]] {uniq_name = "_QFEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_21:.*]]:2 = hlfir.declare %[[VAL_18]] {uniq_name = "_QFEscalar"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_22:.*]]:2 = hlfir.declare %[[VAL_19]] {uniq_name = "_QFEarray"} : (!fir.ref>>) -> (!fir.ref>>, !fir.ref>>) ! CHECK: fir.store %[[VAL_20]] to %[[VAL_14]]#1 : !fir.ref diff --git a/flang/test/Lower/OpenMP/wsloop-reduction-pointer.f90 b/flang/test/Lower/OpenMP/wsloop-reduction-pointer.f90 index f706e48b8fda8..2c126bb8962c2 100644 --- a/flang/test/Lower/OpenMP/wsloop-reduction-pointer.f90 +++ b/flang/test/Lower/OpenMP/wsloop-reduction-pointer.f90 @@ -87,12 +87,13 @@ program reduce_pointer ! CHECK: %[[VAL_17:.*]] = fir.box_addr %[[VAL_16]] : (!fir.box>) -> !fir.ptr ! CHECK: hlfir.assign %[[VAL_15]] to %[[VAL_17]] : i32, !fir.ptr ! CHECK: omp.parallel { +! CHECK: %[[VAL_18:.*]] = fir.alloca i32 {bindc_name = "i", pinned, uniq_name = "_QFEi"} +! CHECK: %[[VAL_19:.*]]:2 = hlfir.declare %[[VAL_18]] {uniq_name = "_QFEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_20:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_21:.*]] = arith.constant 5 : i32 ! CHECK: %[[VAL_22:.*]] = arith.constant 1 : i32 -! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_18:.*]] : !fir.ref) reduction(byref @add_reduction_byref_box_ptr_i32 %[[VAL_5]]#0 -> %[[VAL_23:.*]] : !fir.ref>>) { +! CHECK: omp.wsloop reduction(byref @add_reduction_byref_box_ptr_i32 %[[VAL_5]]#0 -> %[[VAL_23:.*]] : !fir.ref>>) { ! CHECK: omp.loop_nest (%[[VAL_24:.*]]) : i32 = (%[[VAL_20]]) to (%[[VAL_21]]) inclusive step (%[[VAL_22]]) { -! CHECK: %[[VAL_19:.*]]:2 = hlfir.declare %[[VAL_18]] {uniq_name = "_QFEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[VAL_25:.*]]:2 = hlfir.declare %[[VAL_23]] {fortran_attrs = {{.*}}, uniq_name = "_QFEv"} : (!fir.ref>>) -> (!fir.ref>>, !fir.ref>>) ! CHECK: fir.store %[[VAL_24]] to %[[VAL_19]]#1 : !fir.ref ! CHECK: %[[VAL_26:.*]] = fir.load %[[VAL_25]]#0 : !fir.ref>> diff --git a/flang/test/Lower/OpenMP/wsloop-schedule.f90 b/flang/test/Lower/OpenMP/wsloop-schedule.f90 index 0ff4ce7c3ede3..ae854a2de0c9d 100644 --- a/flang/test/Lower/OpenMP/wsloop-schedule.f90 +++ b/flang/test/Lower/OpenMP/wsloop-schedule.f90 @@ -14,7 +14,7 @@ program wsloop_dynamic !CHECK: %[[WS_LB:.*]] = arith.constant 1 : i32 !CHECK: %[[WS_UB:.*]] = arith.constant 9 : i32 !CHECK: %[[WS_STEP:.*]] = arith.constant 1 : i32 -!CHECK: omp.wsloop nowait schedule(runtime, simd) private({{.*}}) { +!CHECK: omp.wsloop nowait schedule(runtime, simd) { !CHECK-NEXT: omp.loop_nest (%[[I:.*]]) : i32 = (%[[WS_LB]]) to (%[[WS_UB]]) inclusive step (%[[WS_STEP]]) { !CHECK: fir.store %[[I]] to %[[STORE:.*]]#1 : !fir.ref diff --git a/flang/test/Lower/OpenMP/wsloop-unstructured.f90 b/flang/test/Lower/OpenMP/wsloop-unstructured.f90 index 6174718c08758..8c89f863ab877 100644 --- a/flang/test/Lower/OpenMP/wsloop-unstructured.f90 +++ b/flang/test/Lower/OpenMP/wsloop-unstructured.f90 @@ -29,7 +29,7 @@ end subroutine sub ! CHECK-SAME: %[[VAL_2:.*]]: !fir.ref> {fir.bindc_name = "x"}, ! CHECK-SAME: %[[VAL_3:.*]]: !fir.ref> {fir.bindc_name = "y"}) { ! [...] -! CHECK: omp.wsloop private({{.*}}) { +! CHECK: omp.wsloop { ! CHECK-NEXT: omp.loop_nest (%[[VAL_53:.*]], %[[VAL_54:.*]]) : i32 = ({{.*}}) to ({{.*}}) inclusive step ({{.*}}) { ! [...] ! CHECK: cf.br ^bb1 diff --git a/flang/test/Lower/OpenMP/wsloop-variable.f90 b/flang/test/Lower/OpenMP/wsloop-variable.f90 index 50b2b3a21ff1e..cc77ce754d97e 100644 --- a/flang/test/Lower/OpenMP/wsloop-variable.f90 +++ b/flang/test/Lower/OpenMP/wsloop-variable.f90 @@ -22,7 +22,7 @@ program wsloop_variable !CHECK: %[[TMP5:.*]] = fir.convert %{{.*}} : (i128) -> i64 !CHECK: %[[TMP6:.*]] = fir.convert %[[TMP1]] : (i32) -> i64 !CHECK: %[[TMP7:.*]] = fir.convert %{{.*}} : (i32) -> i64 -!CHECK: omp.wsloop private({{.*}}) { +!CHECK: omp.wsloop { !CHECK-NEXT: omp.loop_nest (%[[ARG0:.*]], %[[ARG1:.*]]) : i64 = (%[[TMP2]], %[[TMP5]]) to (%[[TMP3]], %[[TMP6]]) inclusive step (%[[TMP4]], %[[TMP7]]) { !CHECK: %[[ARG0_I16:.*]] = fir.convert %[[ARG0]] : (i64) -> i16 !CHECK: fir.store %[[ARG0_I16]] to %[[STORE_IV0:.*]]#1 : !fir.ref @@ -48,7 +48,7 @@ program wsloop_variable !CHECK: %[[TMP12:.*]] = arith.constant 1 : i32 !CHECK: %[[TMP13:.*]] = fir.convert %{{.*}} : (i8) -> i32 !CHECK: %[[TMP14:.*]] = fir.convert %{{.*}} : (i64) -> i32 -!CHECK: omp.wsloop private({{.*}}) { +!CHECK: omp.wsloop { !CHECK-NEXT: omp.loop_nest (%[[ARG0:.*]]) : i32 = (%[[TMP12]]) to (%[[TMP13]]) inclusive step (%[[TMP14]]) { !CHECK: %[[ARG0_I16:.*]] = fir.convert %[[ARG0]] : (i32) -> i16 !CHECK: fir.store %[[ARG0_I16]] to %[[STORE3:.*]]#1 : !fir.ref @@ -68,7 +68,7 @@ program wsloop_variable !CHECK: %[[TMP17:.*]] = fir.convert %{{.*}} : (i8) -> i64 !CHECK: %[[TMP18:.*]] = fir.convert %{{.*}} : (i16) -> i64 !CHECK: %[[TMP19:.*]] = fir.convert %{{.*}} : (i32) -> i64 -!CHECK: omp.wsloop private({{.*}}) { +!CHECK: omp.wsloop { !CHECK-NEXT: omp.loop_nest (%[[ARG1:.*]]) : i64 = (%[[TMP17]]) to (%[[TMP18]]) inclusive step (%[[TMP19]]) { !CHECK: %[[ARG1_I128:.*]] = fir.convert %[[ARG1]] : (i64) -> i128 !CHECK: fir.store %[[ARG1_I128]] to %[[STORE4:.*]]#1 : !fir.ref @@ -123,14 +123,16 @@ subroutine wsloop_variable_sub integer(kind=16) :: i16_lb real :: x +!CHECK: %[[VAL_2:.*]] = fir.alloca i16 {bindc_name = "i2", pinned, {{.*}}} +!CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_2]] {uniq_name = "_QFwsloop_variable_subEi2"} : (!fir.ref) -> (!fir.ref, !fir.ref) + !CHECK: %[[VAL_22:.*]] = arith.constant 1 : i32 !CHECK: %[[VAL_23:.*]] = fir.load %[[VAL_9]]#0 : !fir.ref !CHECK: %[[VAL_24:.*]] = fir.load %[[VAL_13]]#0 : !fir.ref !CHECK: %[[VAL_25:.*]] = fir.convert %[[VAL_23]] : (i8) -> i32 !CHECK: %[[VAL_26:.*]] = fir.convert %[[VAL_24]] : (i16) -> i32 -!CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_2:.*]] : !fir.ref) { +!CHECK: omp.wsloop { !CHECK-NEXT: omp.loop_nest (%[[VAL_27:.*]]) : i32 = (%[[VAL_22]]) to (%[[VAL_25]]) inclusive step (%[[VAL_26]]) { -!CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_2]] {uniq_name = "_QFwsloop_variable_subEi2"} : (!fir.ref) -> (!fir.ref, !fir.ref) !CHECK: %[[VAL_28:.*]] = fir.convert %[[VAL_27]] : (i32) -> i16 !CHECK: fir.store %[[VAL_28]] to %[[VAL_3]]#1 : !fir.ref !CHECK: %[[VAL_29:.*]] = fir.load %[[VAL_7]]#0 : !fir.ref @@ -170,13 +172,14 @@ subroutine wsloop_variable_sub !CHECK: %[[VAL_49:.*]] = arith.constant 5 : i8 !CHECK: hlfir.assign %[[VAL_49]] to %[[VAL_19]]#0 : i8, !fir.ref +!CHECK: %[[VAL_0:.*]] = fir.alloca i8 {bindc_name = "i1", pinned, {{.*}}} +!CHECK: %[[VAL_1:.*]]:2 = hlfir.declare %[[VAL_0]] {uniq_name = "_QFwsloop_variable_subEi1"} : (!fir.ref) -> (!fir.ref, !fir.ref) !CHECK: %[[VAL_50:.*]] = arith.constant 1 : i32 !CHECK: %[[VAL_51:.*]] = arith.constant 10 : i32 !CHECK: %[[VAL_52:.*]] = arith.constant 1 : i32 -!CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[VAL_0:.*]] : !fir.ref) { +!CHECK: omp.wsloop { !CHECK-NEXT: omp.loop_nest (%[[VAL_53:.*]]) : i32 = (%[[VAL_50]]) to (%[[VAL_51]]) inclusive step (%[[VAL_52]]) { -!CHECK: %[[VAL_1:.*]]:2 = hlfir.declare %[[VAL_0]] {uniq_name = "_QFwsloop_variable_subEi1"} : (!fir.ref) -> (!fir.ref, !fir.ref) !CHECK: %[[VAL_54:.*]] = fir.convert %[[VAL_53]] : (i32) -> i8 !CHECK: fir.store %[[VAL_54]] to %[[VAL_1]]#1 : !fir.ref !CHECK: %[[VAL_55:.*]] = fir.load %[[VAL_1]]#0 : !fir.ref diff --git a/flang/test/Lower/OpenMP/wsloop.f90 b/flang/test/Lower/OpenMP/wsloop.f90 index 44b2f585b3a67..4378233a622ed 100644 --- a/flang/test/Lower/OpenMP/wsloop.f90 +++ b/flang/test/Lower/OpenMP/wsloop.f90 @@ -7,14 +7,15 @@ subroutine simple_loop integer :: i ! CHECK: omp.parallel !$OMP PARALLEL + ! CHECK: %[[ALLOCA_IV:.*]] = fir.alloca i32 {{{.*}}, pinned, {{.*}}} + ! CHECK: %[[IV_DECL:.*]]:2 = hlfir.declare %[[ALLOCA_IV]] {uniq_name = "_QFsimple_loopEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[WS_LB:.*]] = arith.constant 1 : i32 ! CHECK: %[[WS_UB:.*]] = arith.constant 9 : i32 ! CHECK: %[[WS_STEP:.*]] = arith.constant 1 : i32 - ! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[ALLOCA_IV:.*]] : !fir.ref) { + ! CHECK: omp.wsloop { ! CHECK-NEXT: omp.loop_nest (%[[I:.*]]) : i32 = (%[[WS_LB]]) to (%[[WS_UB]]) inclusive step (%[[WS_STEP]]) { !$OMP DO do i=1, 9 - ! CHECK: %[[IV_DECL:.*]]:2 = hlfir.declare %[[ALLOCA_IV]] {uniq_name = "_QFsimple_loopEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: fir.store %[[I]] to %[[IV_DECL:.*]]#1 : !fir.ref ! CHECK: %[[LOAD_IV:.*]] = fir.load %[[IV_DECL]]#0 : !fir.ref ! CHECK: fir.call @_FortranAioOutputInteger32({{.*}}, %[[LOAD_IV]]) {{.*}}: (!fir.ref, i32) -> i1 @@ -31,12 +32,13 @@ subroutine simple_loop_with_step integer :: i ! CHECK: omp.parallel !$OMP PARALLEL + ! CHECK: %[[ALLOCA_IV:.*]] = fir.alloca i32 {{{.*}}, pinned, {{.*}}} + ! CHECK: %[[IV_DECL:.*]]:2 = hlfir.declare %[[ALLOCA_IV]] {uniq_name = "_QFsimple_loop_with_stepEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[WS_LB:.*]] = arith.constant 1 : i32 ! CHECK: %[[WS_UB:.*]] = arith.constant 9 : i32 ! CHECK: %[[WS_STEP:.*]] = arith.constant 2 : i32 - ! CHECK: omp.wsloop private(@{{.*}} %{{.*}}#0 -> %[[ALLOCA_IV:.*]] : !fir.ref) { + ! CHECK: omp.wsloop { ! CHECK-NEXT: omp.loop_nest (%[[I:.*]]) : i32 = (%[[WS_LB]]) to (%[[WS_UB]]) inclusive step (%[[WS_STEP]]) { - ! CHECK: %[[IV_DECL:.*]]:2 = hlfir.declare %[[ALLOCA_IV]] {uniq_name = "_QFsimple_loop_with_stepEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: fir.store %[[I]] to %[[IV_DECL]]#1 : !fir.ref ! CHECK: %[[LOAD_IV:.*]] = fir.load %[[IV_DECL]]#0 : !fir.ref !$OMP DO @@ -55,14 +57,15 @@ subroutine loop_with_schedule_nowait integer :: i ! CHECK: omp.parallel !$OMP PARALLEL + ! CHECK: %[[ALLOCA_IV:.*]] = fir.alloca i32 {{{.*}}, pinned, {{.*}}} + ! CHECK: %[[IV_DECL:.*]]:2 = hlfir.declare %[[ALLOCA_IV]] {uniq_name = "_QFloop_with_schedule_nowaitEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[WS_LB:.*]] = arith.constant 1 : i32 ! CHECK: %[[WS_UB:.*]] = arith.constant 9 : i32 ! CHECK: %[[WS_STEP:.*]] = arith.constant 1 : i32 - ! CHECK: omp.wsloop nowait schedule(runtime) private(@{{.*}} %{{.*}}#0 -> %[[ALLOCA_IV:.*]] : !fir.ref) { + ! CHECK: omp.wsloop nowait schedule(runtime) { ! CHECK-NEXT: omp.loop_nest (%[[I:.*]]) : i32 = (%[[WS_LB]]) to (%[[WS_UB]]) inclusive step (%[[WS_STEP]]) { !$OMP DO SCHEDULE(runtime) do i=1, 9 - ! CHECK: %[[IV_DECL:.*]]:2 = hlfir.declare %[[ALLOCA_IV]] {uniq_name = "_QFloop_with_schedule_nowaitEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: fir.store %[[I]] to %[[IV_DECL]]#1 : !fir.ref ! CHECK: %[[LOAD_IV:.*]] = fir.load %[[IV_DECL]]#0 : !fir.ref ! CHECK: fir.call @_FortranAioOutputInteger32({{.*}}, %[[LOAD_IV]]) {{.*}}: (!fir.ref, i32) -> i1 diff --git a/flang/test/Semantics/OpenMP/declare-target08.f90 b/flang/test/Semantics/OpenMP/declare-target08.f90 new file mode 100644 index 0000000000000..1438d79d37348 --- /dev/null +++ b/flang/test/Semantics/OpenMP/declare-target08.f90 @@ -0,0 +1,41 @@ +! RUN: %flang_fc1 -fopenmp -fdebug-dump-symbols %s | FileCheck %s + +subroutine bar(i, a) + !$omp declare target + real :: a + integer :: i + a = a - i +end subroutine + +function baz(a) + !$omp declare target + real, intent(in) :: a + baz = a +end function baz + +program main +real a +!CHECK: bar (Subroutine, OmpDeclareTarget): HostAssoc +!CHECK: baz (Function, OmpDeclareTarget): HostAssoc +!$omp declare target(bar) +!$omp declare target(baz) + +a = baz(a) +call bar(2,a) +call foo(a) +return +end + +subroutine foo(a) +real a +integer i +!CHECK: bar (Subroutine, OmpDeclareTarget): HostAssoc +!CHECK: baz (Function, OmpDeclareTarget): HostAssoc +!$omp declare target(bar) +!$omp declare target(baz) +!$omp target + a = baz(a) + call bar(i,a) +!$omp end target +return +end diff --git a/flang/test/Transforms/generic-loop-rewriting-todo.mlir b/flang/test/Transforms/generic-loop-rewriting-todo.mlir index 9ea6bf001b668..becd6b8dcb5cb 100644 --- a/flang/test/Transforms/generic-loop-rewriting-todo.mlir +++ b/flang/test/Transforms/generic-loop-rewriting-todo.mlir @@ -1,18 +1,5 @@ // RUN: fir-opt --omp-generic-loop-conversion -verify-diagnostics %s -func.func @_QPtarget_loop() { - %c0 = arith.constant 0 : i32 - %c10 = arith.constant 10 : i32 - %c1 = arith.constant 1 : i32 - // expected-error@below {{not yet implemented: Standalone `omp loop` directive}} - omp.loop { - omp.loop_nest (%arg3) : i32 = (%c0) to (%c10) inclusive step (%c1) { - omp.yield - } - } - return -} - func.func @_QPtarget_parallel_loop() { omp.target { omp.parallel { diff --git a/libc/cmake/modules/LLVMLibCTestRules.cmake b/libc/cmake/modules/LLVMLibCTestRules.cmake index 4dbe5e046cc68..96fa6c3a707e4 100644 --- a/libc/cmake/modules/LLVMLibCTestRules.cmake +++ b/libc/cmake/modules/LLVMLibCTestRules.cmake @@ -35,7 +35,7 @@ function(_get_common_test_compile_options output_var c_test flags) # list(APPEND compile_options "-Wno-sign-conversion") # list(APPEND compile_options "-Wimplicit-fallthrough") # list(APPEND compile_options "-Wwrite-strings") - # list(APPEND compile_options "-Wextra-semi") + list(APPEND compile_options "-Wextra-semi") # Silence this warning because _Complex is a part of C99. if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") if(NOT c_test) diff --git a/libc/test/src/math/smoke/nan_test.cpp b/libc/test/src/math/smoke/nan_test.cpp index 46b9e9aa9563a..da6beb94c7f05 100644 --- a/libc/test/src/math/smoke/nan_test.cpp +++ b/libc/test/src/math/smoke/nan_test.cpp @@ -23,7 +23,7 @@ class LlvmLibcNanTest : public LIBC_NAMESPACE::testing::FEnvSafeTest { auto actual_fp = LIBC_NAMESPACE::fputil::FPBits(result); auto expected_fp = LIBC_NAMESPACE::fputil::FPBits(bits); EXPECT_EQ(actual_fp.uintval(), expected_fp.uintval()); - }; + } }; TEST_F(LlvmLibcNanTest, NCharSeq) { diff --git a/libc/test/src/math/smoke/nanf128_test.cpp b/libc/test/src/math/smoke/nanf128_test.cpp index 25dd2ef1d5b1c..dd1986f17b978 100644 --- a/libc/test/src/math/smoke/nanf128_test.cpp +++ b/libc/test/src/math/smoke/nanf128_test.cpp @@ -28,7 +28,7 @@ class LlvmLibcNanf128Test : public LIBC_NAMESPACE::testing::FEnvSafeTest { auto actual_fp = FPBits128(result); auto expected_fp = FPBits128(bits); EXPECT_EQ(actual_fp.uintval(), expected_fp.uintval()); - }; + } }; TEST_F(LlvmLibcNanf128Test, NCharSeq) { diff --git a/libc/test/src/math/smoke/nanf16_test.cpp b/libc/test/src/math/smoke/nanf16_test.cpp index ec640a3b9eef9..5fafb1a36e4cd 100644 --- a/libc/test/src/math/smoke/nanf16_test.cpp +++ b/libc/test/src/math/smoke/nanf16_test.cpp @@ -23,7 +23,7 @@ class LlvmLibcNanf16Test : public LIBC_NAMESPACE::testing::FEnvSafeTest { auto actual_fp = LIBC_NAMESPACE::fputil::FPBits(result); auto expected_fp = LIBC_NAMESPACE::fputil::FPBits(bits); EXPECT_EQ(actual_fp.uintval(), expected_fp.uintval()); - }; + } }; TEST_F(LlvmLibcNanf16Test, NCharSeq) { diff --git a/libc/test/src/math/smoke/nanf_test.cpp b/libc/test/src/math/smoke/nanf_test.cpp index dd3124ee9c511..19d94b40b5ffb 100644 --- a/libc/test/src/math/smoke/nanf_test.cpp +++ b/libc/test/src/math/smoke/nanf_test.cpp @@ -23,7 +23,7 @@ class LlvmLibcNanfTest : public LIBC_NAMESPACE::testing::FEnvSafeTest { auto actual_fp = LIBC_NAMESPACE::fputil::FPBits(result); auto expected_fp = LIBC_NAMESPACE::fputil::FPBits(bits); EXPECT_EQ(actual_fp.uintval(), expected_fp.uintval()); - }; + } }; TEST_F(LlvmLibcNanfTest, NCharSeq) { diff --git a/libc/test/src/math/smoke/nanl_test.cpp b/libc/test/src/math/smoke/nanl_test.cpp index ef3f9c15dafd9..c7217928e943b 100644 --- a/libc/test/src/math/smoke/nanl_test.cpp +++ b/libc/test/src/math/smoke/nanl_test.cpp @@ -33,7 +33,7 @@ class LlvmLibcNanlTest : public LIBC_NAMESPACE::testing::FEnvSafeTest { auto actual_fp = LIBC_NAMESPACE::fputil::FPBits(result); auto expected_fp = LIBC_NAMESPACE::fputil::FPBits(bits); EXPECT_EQ(actual_fp.uintval(), expected_fp.uintval()); - }; + } }; TEST_F(LlvmLibcNanlTest, NCharSeq) { diff --git a/libclc/clc/include/clc/clcmacro.h b/libclc/clc/include/clc/clcmacro.h index 44928b2e428bf..676560e9efcb4 100644 --- a/libclc/clc/include/clc/clcmacro.h +++ b/libclc/clc/include/clc/clcmacro.h @@ -227,6 +227,8 @@ } \ _CLC_BINARY_VECTORIZE(_CLC_OVERLOAD _CLC_DEF, half, FUNCTION, half, half) +#pragma OPENCL EXTENSION cl_khr_fp16 : disable + #else #define _CLC_DEFINE_UNARY_BUILTIN_FP16(FUNCTION) diff --git a/libclc/clc/include/clc/relational/clc_select.h b/libclc/clc/include/clc/relational/clc_select.h index ddea7c528ec74..a92f2051b577d 100644 --- a/libclc/clc/include/clc/relational/clc_select.h +++ b/libclc/clc/include/clc/relational/clc_select.h @@ -1,23 +1,19 @@ #ifndef __CLC_RELATIONAL_CLC_SELECT_H__ #define __CLC_RELATIONAL_CLC_SELECT_H__ -#if defined(CLC_CLSPV) || defined(CLC_SPIRV) -// clspv and spir-v targets provide their own OpenCL-compatible select -#define __clc_select select -#else - /* Duplciate these so we don't have to distribute utils.h */ #define __CLC_CONCAT(x, y) x##y #define __CLC_XCONCAT(x, y) __CLC_CONCAT(x, y) -#define __CLC_BODY +#define __CLC_SELECT_FN __clc_select + +#define __CLC_BODY #include -#define __CLC_BODY +#define __CLC_BODY #include +#undef __CLC_SELECT_FN #undef __CLC_CONCAT #undef __CLC_XCONCAT -#endif - #endif // __CLC_RELATIONAL_CLC_SELECT_H__ diff --git a/libclc/clc/include/clc/relational/clc_select.inc b/libclc/clc/include/clc/relational/clc_select_decl.inc similarity index 58% rename from libclc/clc/include/clc/relational/clc_select.inc rename to libclc/clc/include/clc/relational/clc_select_decl.inc index abf0e0fa43600..3a4f2dcb75170 100644 --- a/libclc/clc/include/clc/relational/clc_select.inc +++ b/libclc/clc/include/clc/relational/clc_select_decl.inc @@ -13,12 +13,12 @@ #define __CLC_U_GENTYPE __CLC_XCONCAT(ushort, __CLC_VECSIZE) #endif -_CLC_OVERLOAD _CLC_DECL __CLC_GENTYPE __clc_select(__CLC_GENTYPE x, - __CLC_GENTYPE y, - __CLC_S_GENTYPE z); -_CLC_OVERLOAD _CLC_DECL __CLC_GENTYPE __clc_select(__CLC_GENTYPE x, - __CLC_GENTYPE y, - __CLC_U_GENTYPE z); +_CLC_OVERLOAD _CLC_DECL __CLC_GENTYPE __CLC_SELECT_FN(__CLC_GENTYPE x, + __CLC_GENTYPE y, + __CLC_S_GENTYPE z); +_CLC_OVERLOAD _CLC_DECL __CLC_GENTYPE __CLC_SELECT_FN(__CLC_GENTYPE x, + __CLC_GENTYPE y, + __CLC_U_GENTYPE z); #ifdef __CLC_FPSIZE #undef __CLC_S_GENTYPE diff --git a/libclc/clc/lib/generic/relational/clc_select.inc b/libclc/clc/include/clc/relational/clc_select_impl.inc similarity index 55% rename from libclc/clc/lib/generic/relational/clc_select.inc rename to libclc/clc/include/clc/relational/clc_select_impl.inc index 47db80672a02c..ad53e822179fb 100644 --- a/libclc/clc/lib/generic/relational/clc_select.inc +++ b/libclc/clc/include/clc/relational/clc_select_impl.inc @@ -13,16 +13,16 @@ #define __CLC_U_GENTYPE __CLC_XCONCAT(ushort, __CLC_VECSIZE) #endif -_CLC_OVERLOAD _CLC_DEF __CLC_GENTYPE __clc_select(__CLC_GENTYPE x, - __CLC_GENTYPE y, - __CLC_S_GENTYPE z) { - return z ? y : x; +_CLC_OVERLOAD _CLC_DEF __CLC_GENTYPE __CLC_SELECT_FN(__CLC_GENTYPE x, + __CLC_GENTYPE y, + __CLC_S_GENTYPE z) { + __CLC_SELECT_DEF(x, y, z); } -_CLC_OVERLOAD _CLC_DEF __CLC_GENTYPE __clc_select(__CLC_GENTYPE x, - __CLC_GENTYPE y, - __CLC_U_GENTYPE z) { - return z ? y : x; +_CLC_OVERLOAD _CLC_DEF __CLC_GENTYPE __CLC_SELECT_FN(__CLC_GENTYPE x, + __CLC_GENTYPE y, + __CLC_U_GENTYPE z) { + __CLC_SELECT_DEF(x, y, z); } #ifdef __CLC_FPSIZE diff --git a/libclc/clc/lib/clspv/SOURCES b/libclc/clc/lib/clspv/SOURCES index 209dc0ca61e2b..c3fc03c0b3dd5 100644 --- a/libclc/clc/lib/clspv/SOURCES +++ b/libclc/clc/lib/clspv/SOURCES @@ -4,4 +4,5 @@ ../generic/math/clc_mad.cl ../generic/math/clc_rint.cl ../generic/math/clc_trunc.cl +../generic/relational/clc_select.cl ../generic/shared/clc_clamp.cl diff --git a/libclc/clc/lib/generic/relational/clc_bitselect.cl b/libclc/clc/lib/generic/relational/clc_bitselect.cl index 66b28af71b38d..6281eeea1abb2 100644 --- a/libclc/clc/lib/generic/relational/clc_bitselect.cl +++ b/libclc/clc/lib/generic/relational/clc_bitselect.cl @@ -53,3 +53,15 @@ FLOAT_BITSELECT(double, ulong, 8) FLOAT_BITSELECT(double, ulong, 16) #endif + +#ifdef cl_khr_fp16 +#pragma OPENCL EXTENSION cl_khr_fp16 : enable + +FLOAT_BITSELECT(half, ushort, ) +FLOAT_BITSELECT(half, ushort, 2) +FLOAT_BITSELECT(half, ushort, 3) +FLOAT_BITSELECT(half, ushort, 4) +FLOAT_BITSELECT(half, ushort, 8) +FLOAT_BITSELECT(half, ushort, 16) + +#endif diff --git a/libclc/clc/lib/generic/relational/clc_select.cl b/libclc/clc/lib/generic/relational/clc_select.cl index bb016ed2993e7..210db7867eefb 100644 --- a/libclc/clc/lib/generic/relational/clc_select.cl +++ b/libclc/clc/lib/generic/relational/clc_select.cl @@ -1,7 +1,10 @@ #include #include -#define __CLC_BODY +#define __CLC_SELECT_FN __clc_select +#define __CLC_SELECT_DEF(x, y, z) return z ? y : x + +#define __CLC_BODY #include -#define __CLC_BODY +#define __CLC_BODY #include diff --git a/libclc/clc/lib/spirv/SOURCES b/libclc/clc/lib/spirv/SOURCES index 905afa03d8a56..55d109478faac 100644 --- a/libclc/clc/lib/spirv/SOURCES +++ b/libclc/clc/lib/spirv/SOURCES @@ -8,4 +8,5 @@ ../generic/math/clc_mad.cl ../generic/math/clc_rint.cl ../generic/math/clc_trunc.cl +../generic/relational/clc_select.cl ../generic/shared/clc_clamp.cl diff --git a/libclc/clc/lib/spirv64/SOURCES b/libclc/clc/lib/spirv64/SOURCES index 905afa03d8a56..55d109478faac 100644 --- a/libclc/clc/lib/spirv64/SOURCES +++ b/libclc/clc/lib/spirv64/SOURCES @@ -8,4 +8,5 @@ ../generic/math/clc_mad.cl ../generic/math/clc_rint.cl ../generic/math/clc_trunc.cl +../generic/relational/clc_select.cl ../generic/shared/clc_clamp.cl diff --git a/libclc/generic/include/clc/relational/select.h b/libclc/generic/include/clc/relational/select.h index d20deae0d2cf9..847884a07b7f2 100644 --- a/libclc/generic/include/clc/relational/select.h +++ b/libclc/generic/include/clc/relational/select.h @@ -2,10 +2,13 @@ #define __CLC_CONCAT(x, y) x ## y #define __CLC_XCONCAT(x, y) __CLC_CONCAT(x, y) -#define __CLC_BODY +#define __CLC_SELECT_FN select + +#define __CLC_BODY #include -#define __CLC_BODY +#define __CLC_BODY #include +#undef __CLC_SELECT_FN #undef __CLC_CONCAT #undef __CLC_XCONCAT diff --git a/libclc/generic/include/clc/relational/select.inc b/libclc/generic/include/clc/relational/select.inc deleted file mode 100644 index 11a957a56e4b7..0000000000000 --- a/libclc/generic/include/clc/relational/select.inc +++ /dev/null @@ -1,25 +0,0 @@ -#ifdef __CLC_SCALAR -#define __CLC_VECSIZE -#endif - -#if __CLC_FPSIZE == 64 -#define __CLC_S_GENTYPE __CLC_XCONCAT(long, __CLC_VECSIZE) -#define __CLC_U_GENTYPE __CLC_XCONCAT(ulong, __CLC_VECSIZE) -#elif __CLC_FPSIZE == 32 -#define __CLC_S_GENTYPE __CLC_XCONCAT(int, __CLC_VECSIZE) -#define __CLC_U_GENTYPE __CLC_XCONCAT(uint, __CLC_VECSIZE) -#elif __CLC_FPSIZE == 16 -#define __CLC_S_GENTYPE __CLC_XCONCAT(short, __CLC_VECSIZE) -#define __CLC_U_GENTYPE __CLC_XCONCAT(ushort, __CLC_VECSIZE) -#endif - -_CLC_OVERLOAD _CLC_DECL __CLC_GENTYPE select(__CLC_GENTYPE x, __CLC_GENTYPE y, __CLC_S_GENTYPE z); -_CLC_OVERLOAD _CLC_DECL __CLC_GENTYPE select(__CLC_GENTYPE x, __CLC_GENTYPE y, __CLC_U_GENTYPE z); - -#ifdef __CLC_FPSIZE -#undef __CLC_S_GENTYPE -#undef __CLC_U_GENTYPE -#endif -#ifdef __CLC_SCALAR -#undef __CLC_VECSIZE -#endif diff --git a/libclc/generic/lib/math/acos.cl b/libclc/generic/lib/math/acos.cl index aeb72872da342..d71d10024b180 100644 --- a/libclc/generic/lib/math/acos.cl +++ b/libclc/generic/lib/math/acos.cl @@ -172,4 +172,10 @@ _CLC_UNARY_VECTORIZE(_CLC_OVERLOAD _CLC_DEF, double, acos, double); #endif // cl_khr_fp64 +#ifdef cl_khr_fp16 + +#pragma OPENCL EXTENSION cl_khr_fp16 : enable + _CLC_DEFINE_UNARY_BUILTIN_FP16(acos) + +#endif diff --git a/libclc/generic/lib/math/acosh.cl b/libclc/generic/lib/math/acosh.cl index 4656f14457d42..977c2e929b34c 100644 --- a/libclc/generic/lib/math/acosh.cl +++ b/libclc/generic/lib/math/acosh.cl @@ -126,4 +126,10 @@ _CLC_UNARY_VECTORIZE(_CLC_OVERLOAD _CLC_DEF, double, acosh, double) #endif +#ifdef cl_khr_fp16 + +#pragma OPENCL EXTENSION cl_khr_fp16 : enable + _CLC_DEFINE_UNARY_BUILTIN_FP16(acosh) + +#endif diff --git a/libclc/generic/lib/math/acospi.cl b/libclc/generic/lib/math/acospi.cl index 83a47eb27e836..5aa8a083df4e9 100644 --- a/libclc/generic/lib/math/acospi.cl +++ b/libclc/generic/lib/math/acospi.cl @@ -171,4 +171,10 @@ _CLC_UNARY_VECTORIZE(_CLC_OVERLOAD _CLC_DEF, double, acospi, double) #endif +#ifdef cl_khr_fp16 + +#pragma OPENCL EXTENSION cl_khr_fp16 : enable + _CLC_DEFINE_UNARY_BUILTIN_FP16(acospi) + +#endif diff --git a/libclc/generic/lib/math/asinh.cl b/libclc/generic/lib/math/asinh.cl index f7637ade227ee..686d9f7a95e5d 100644 --- a/libclc/generic/lib/math/asinh.cl +++ b/libclc/generic/lib/math/asinh.cl @@ -292,4 +292,10 @@ _CLC_UNARY_VECTORIZE(_CLC_OVERLOAD _CLC_DEF, double, asinh, double) #endif +#ifdef cl_khr_fp16 + +#pragma OPENCL EXTENSION cl_khr_fp16 : enable + _CLC_DEFINE_UNARY_BUILTIN_FP16(asinh) + +#endif diff --git a/libclc/generic/lib/math/atan.cl b/libclc/generic/lib/math/atan.cl index 28eaaf7b2ae72..b6b067f2bf4ff 100644 --- a/libclc/generic/lib/math/atan.cl +++ b/libclc/generic/lib/math/atan.cl @@ -182,5 +182,10 @@ _CLC_UNARY_VECTORIZE(_CLC_OVERLOAD _CLC_DEF, double, atan, double); #endif // cl_khr_fp64 +#ifdef cl_khr_fp16 + +#pragma OPENCL EXTENSION cl_khr_fp16 : enable _CLC_DEFINE_UNARY_BUILTIN_FP16(atan) + +#endif diff --git a/libclc/generic/lib/math/atan2.cl b/libclc/generic/lib/math/atan2.cl index 98b457a69a0e2..32419937a856b 100644 --- a/libclc/generic/lib/math/atan2.cl +++ b/libclc/generic/lib/math/atan2.cl @@ -236,4 +236,10 @@ _CLC_BINARY_VECTORIZE(_CLC_OVERLOAD _CLC_DEF, double, atan2, double, double); #endif +#ifdef cl_khr_fp16 + +#pragma OPENCL EXTENSION cl_khr_fp16 : enable + _CLC_DEFINE_BINARY_BUILTIN_FP16(atan2) + +#endif diff --git a/libclc/generic/lib/math/atan2pi.cl b/libclc/generic/lib/math/atan2pi.cl index ad41b11bd3741..e631918f7539e 100644 --- a/libclc/generic/lib/math/atan2pi.cl +++ b/libclc/generic/lib/math/atan2pi.cl @@ -220,4 +220,10 @@ _CLC_BINARY_VECTORIZE(_CLC_OVERLOAD _CLC_DEF, double, atan2pi, double, double) #endif +#ifdef cl_khr_fp16 + +#pragma OPENCL EXTENSION cl_khr_fp16 : enable + _CLC_DEFINE_BINARY_BUILTIN_FP16(atan2pi) + +#endif diff --git a/libclc/generic/lib/math/atanh.cl b/libclc/generic/lib/math/atanh.cl index f2298a2624e84..10bad190cc0dc 100644 --- a/libclc/generic/lib/math/atanh.cl +++ b/libclc/generic/lib/math/atanh.cl @@ -112,4 +112,10 @@ _CLC_UNARY_VECTORIZE(_CLC_OVERLOAD _CLC_DEF, double, atanh, double) #endif +#ifdef cl_khr_fp16 + +#pragma OPENCL EXTENSION cl_khr_fp16 : enable + _CLC_DEFINE_UNARY_BUILTIN_FP16(atanh) + +#endif diff --git a/libclc/generic/lib/math/atanpi.cl b/libclc/generic/lib/math/atanpi.cl index 9e6b3ece7f325..8522acf349933 100644 --- a/libclc/generic/lib/math/atanpi.cl +++ b/libclc/generic/lib/math/atanpi.cl @@ -181,4 +181,10 @@ _CLC_UNARY_VECTORIZE(_CLC_OVERLOAD _CLC_DEF, double, atanpi, double) #endif +#ifdef cl_khr_fp16 + +#pragma OPENCL EXTENSION cl_khr_fp16 : enable + _CLC_DEFINE_UNARY_BUILTIN_FP16(atanpi) + +#endif diff --git a/libclc/generic/lib/math/cbrt.cl b/libclc/generic/lib/math/cbrt.cl index 8462f5f6e14bb..49f2ba8a411cb 100644 --- a/libclc/generic/lib/math/cbrt.cl +++ b/libclc/generic/lib/math/cbrt.cl @@ -150,4 +150,10 @@ _CLC_UNARY_VECTORIZE(_CLC_OVERLOAD _CLC_DEF, double, cbrt, double) #endif +#ifdef cl_khr_fp16 + +#pragma OPENCL EXTENSION cl_khr_fp16 : enable + _CLC_DEFINE_UNARY_BUILTIN_FP16(cbrt) + +#endif diff --git a/libclc/generic/lib/math/cos.cl b/libclc/generic/lib/math/cos.cl index 42192895151a3..2945c90d6fe0f 100644 --- a/libclc/generic/lib/math/cos.cl +++ b/libclc/generic/lib/math/cos.cl @@ -76,4 +76,10 @@ _CLC_UNARY_VECTORIZE(_CLC_OVERLOAD _CLC_DEF, double, cos, double); #endif +#ifdef cl_khr_fp16 + +#pragma OPENCL EXTENSION cl_khr_fp16 : enable + _CLC_DEFINE_UNARY_BUILTIN_FP16(cos) + +#endif diff --git a/libclc/generic/lib/math/cosh.cl b/libclc/generic/lib/math/cosh.cl index 1f58d7acd2b55..02b03a761aa19 100644 --- a/libclc/generic/lib/math/cosh.cl +++ b/libclc/generic/lib/math/cosh.cl @@ -191,4 +191,10 @@ _CLC_UNARY_VECTORIZE(_CLC_OVERLOAD _CLC_DEF, double, cosh, double) #endif +#ifdef cl_khr_fp16 + +#pragma OPENCL EXTENSION cl_khr_fp16 : enable + _CLC_DEFINE_UNARY_BUILTIN_FP16(cosh) + +#endif diff --git a/libclc/generic/lib/math/cospi.cl b/libclc/generic/lib/math/cospi.cl index 0e69f7885faa1..98e989267c917 100644 --- a/libclc/generic/lib/math/cospi.cl +++ b/libclc/generic/lib/math/cospi.cl @@ -135,4 +135,10 @@ _CLC_OVERLOAD _CLC_DEF double cospi(double x) { _CLC_UNARY_VECTORIZE(_CLC_OVERLOAD _CLC_DEF, double, cospi, double); #endif +#ifdef cl_khr_fp16 + +#pragma OPENCL EXTENSION cl_khr_fp16 : enable + _CLC_DEFINE_UNARY_BUILTIN_FP16(cospi) + +#endif diff --git a/libclc/generic/lib/math/exp.cl b/libclc/generic/lib/math/exp.cl index 1e37d76f3ac8e..95dc0db44df76 100644 --- a/libclc/generic/lib/math/exp.cl +++ b/libclc/generic/lib/math/exp.cl @@ -89,4 +89,10 @@ _CLC_UNARY_VECTORIZE(_CLC_OVERLOAD _CLC_DEF, double, exp, double) #endif +#ifdef cl_khr_fp16 + +#pragma OPENCL EXTENSION cl_khr_fp16 : enable + _CLC_DEFINE_UNARY_BUILTIN_FP16(exp) + +#endif diff --git a/libclc/generic/lib/math/expm1.cl b/libclc/generic/lib/math/expm1.cl index fbb9f0d087c89..d50a88e0aaae8 100644 --- a/libclc/generic/lib/math/expm1.cl +++ b/libclc/generic/lib/math/expm1.cl @@ -141,4 +141,10 @@ _CLC_UNARY_VECTORIZE(_CLC_OVERLOAD _CLC_DEF, double, expm1, double) #endif +#ifdef cl_khr_fp16 + +#pragma OPENCL EXTENSION cl_khr_fp16 : enable + _CLC_DEFINE_UNARY_BUILTIN_FP16(expm1) + +#endif diff --git a/libclc/generic/lib/math/lgamma.cl b/libclc/generic/lib/math/lgamma.cl index ca7b9610a31b3..f0476230e63fe 100644 --- a/libclc/generic/lib/math/lgamma.cl +++ b/libclc/generic/lib/math/lgamma.cl @@ -43,4 +43,10 @@ _CLC_UNARY_VECTORIZE(_CLC_OVERLOAD _CLC_DEF, double, lgamma, double) #endif +#ifdef cl_khr_fp16 + +#pragma OPENCL EXTENSION cl_khr_fp16 : enable + _CLC_DEFINE_UNARY_BUILTIN_FP16(lgamma) + +#endif diff --git a/libclc/generic/lib/math/log1p.cl b/libclc/generic/lib/math/log1p.cl index a371995a08492..7fef79ca7b8f3 100644 --- a/libclc/generic/lib/math/log1p.cl +++ b/libclc/generic/lib/math/log1p.cl @@ -176,4 +176,10 @@ _CLC_UNARY_VECTORIZE(_CLC_OVERLOAD _CLC_DEF, double, log1p, double); #endif // cl_khr_fp64 +#ifdef cl_khr_fp16 + +#pragma OPENCL EXTENSION cl_khr_fp16 : enable + _CLC_DEFINE_UNARY_BUILTIN_FP16(log1p) + +#endif diff --git a/libclc/generic/lib/math/logb.cl b/libclc/generic/lib/math/logb.cl index 7a7111d5bc84d..d91972f780ba9 100644 --- a/libclc/generic/lib/math/logb.cl +++ b/libclc/generic/lib/math/logb.cl @@ -30,4 +30,10 @@ _CLC_OVERLOAD _CLC_DEF double logb(double x) { _CLC_UNARY_VECTORIZE(_CLC_OVERLOAD _CLC_DEF, double, logb, double) #endif +#ifdef cl_khr_fp16 + +#pragma OPENCL EXTENSION cl_khr_fp16 : enable + _CLC_DEFINE_UNARY_BUILTIN_FP16(logb) + +#endif diff --git a/libclc/generic/lib/math/sin.cl b/libclc/generic/lib/math/sin.cl index 30638a57f59b5..c271e67828066 100644 --- a/libclc/generic/lib/math/sin.cl +++ b/libclc/generic/lib/math/sin.cl @@ -78,4 +78,10 @@ _CLC_UNARY_VECTORIZE(_CLC_OVERLOAD _CLC_DEF, double, sin, double); #endif +#ifdef cl_khr_fp16 + +#pragma OPENCL EXTENSION cl_khr_fp16 : enable + _CLC_DEFINE_UNARY_BUILTIN_FP16(sin) + +#endif diff --git a/libclc/generic/lib/math/sinh.cl b/libclc/generic/lib/math/sinh.cl index 3de0792361c2f..23500c1f49b7a 100644 --- a/libclc/generic/lib/math/sinh.cl +++ b/libclc/generic/lib/math/sinh.cl @@ -190,4 +190,10 @@ _CLC_UNARY_VECTORIZE(_CLC_OVERLOAD _CLC_DEF, double, sinh, double) #endif +#ifdef cl_khr_fp16 + +#pragma OPENCL EXTENSION cl_khr_fp16 : enable + _CLC_DEFINE_UNARY_BUILTIN_FP16(sinh) + +#endif diff --git a/libclc/generic/lib/math/sinpi.cl b/libclc/generic/lib/math/sinpi.cl index 520bba5415c7c..01b340b855c44 100644 --- a/libclc/generic/lib/math/sinpi.cl +++ b/libclc/generic/lib/math/sinpi.cl @@ -130,4 +130,10 @@ _CLC_UNARY_VECTORIZE(_CLC_OVERLOAD _CLC_DEF, double, sinpi, double) #endif +#ifdef cl_khr_fp16 + +#pragma OPENCL EXTENSION cl_khr_fp16 : enable + _CLC_DEFINE_UNARY_BUILTIN_FP16(sinpi) + +#endif diff --git a/libclc/generic/lib/math/tanh.cl b/libclc/generic/lib/math/tanh.cl index e558bb93a5596..d9509c57b0507 100644 --- a/libclc/generic/lib/math/tanh.cl +++ b/libclc/generic/lib/math/tanh.cl @@ -145,4 +145,10 @@ _CLC_UNARY_VECTORIZE(_CLC_OVERLOAD _CLC_DEF, double, tanh, double); #endif // cl_khr_fp64 +#ifdef cl_khr_fp16 + +#pragma OPENCL EXTENSION cl_khr_fp16 : enable + _CLC_DEFINE_UNARY_BUILTIN_FP16(tanh) + +#endif diff --git a/libclc/generic/lib/relational/bitselect.cl b/libclc/generic/lib/relational/bitselect.cl index a470447f1fb91..04aae105b7f2c 100644 --- a/libclc/generic/lib/relational/bitselect.cl +++ b/libclc/generic/lib/relational/bitselect.cl @@ -21,34 +21,10 @@ */ #include -#include #include #define __CLC_BODY #include -#undef __CLC_BODY -#define FLOAT_BITSELECT(f_type, i_type, width) \ - _CLC_OVERLOAD _CLC_DEF f_type##width bitselect( \ - f_type##width x, f_type##width y, f_type##width z) { \ - return __clc_bitselect(x, y, z); \ - } - -FLOAT_BITSELECT(float, uint, ) -FLOAT_BITSELECT(float, uint, 2) -FLOAT_BITSELECT(float, uint, 3) -FLOAT_BITSELECT(float, uint, 4) -FLOAT_BITSELECT(float, uint, 8) -FLOAT_BITSELECT(float, uint, 16) - -#ifdef cl_khr_fp64 -#pragma OPENCL EXTENSION cl_khr_fp64 : enable - -FLOAT_BITSELECT(double, ulong, ) -FLOAT_BITSELECT(double, ulong, 2) -FLOAT_BITSELECT(double, ulong, 3) -FLOAT_BITSELECT(double, ulong, 4) -FLOAT_BITSELECT(double, ulong, 8) -FLOAT_BITSELECT(double, ulong, 16) - -#endif +#define __CLC_BODY +#include diff --git a/libclc/generic/lib/relational/bitselect.inc b/libclc/generic/lib/relational/bitselect.inc index 3a78a8c7b7487..b0d64bddffdfd 100644 --- a/libclc/generic/lib/relational/bitselect.inc +++ b/libclc/generic/lib/relational/bitselect.inc @@ -20,6 +20,7 @@ * THE SOFTWARE. */ -_CLC_OVERLOAD _CLC_DEF __CLC_GENTYPE bitselect(__CLC_GENTYPE x, __CLC_GENTYPE y, __CLC_GENTYPE z) { - return ((x) ^ ((z) & ((y) ^ (x)))); +_CLC_OVERLOAD _CLC_DEF __CLC_GENTYPE bitselect(__CLC_GENTYPE x, __CLC_GENTYPE y, + __CLC_GENTYPE z) { + return __clc_bitselect(x, y, z); } diff --git a/libclc/generic/lib/relational/select.cl b/libclc/generic/lib/relational/select.cl index 094f4f9f29fa9..663f9d7ccf990 100644 --- a/libclc/generic/lib/relational/select.cl +++ b/libclc/generic/lib/relational/select.cl @@ -1,7 +1,11 @@ #include +#include #include -#define __CLC_BODY +#define __CLC_SELECT_FN select +#define __CLC_SELECT_DEF(x, y, z) return __clc_select(x, y, z) + +#define __CLC_BODY #include -#define __CLC_BODY +#define __CLC_BODY #include diff --git a/libclc/generic/lib/relational/select.inc b/libclc/generic/lib/relational/select.inc deleted file mode 100644 index 7691af2669186..0000000000000 --- a/libclc/generic/lib/relational/select.inc +++ /dev/null @@ -1,33 +0,0 @@ -#ifdef __CLC_SCALAR -#define __CLC_VECSIZE -#endif - -#if __CLC_FPSIZE == 64 -#define __CLC_S_GENTYPE __CLC_XCONCAT(long, __CLC_VECSIZE) -#define __CLC_U_GENTYPE __CLC_XCONCAT(ulong, __CLC_VECSIZE) -#elif __CLC_FPSIZE == 32 -#define __CLC_S_GENTYPE __CLC_XCONCAT(int, __CLC_VECSIZE) -#define __CLC_U_GENTYPE __CLC_XCONCAT(uint, __CLC_VECSIZE) -#elif __CLC_FPSIZE == 16 -#define __CLC_S_GENTYPE __CLC_XCONCAT(short, __CLC_VECSIZE) -#define __CLC_U_GENTYPE __CLC_XCONCAT(ushort, __CLC_VECSIZE) -#endif - -_CLC_OVERLOAD _CLC_DEF __CLC_GENTYPE select(__CLC_GENTYPE x, __CLC_GENTYPE y, __CLC_S_GENTYPE z) -{ - return z ? y : x; -} - -_CLC_OVERLOAD _CLC_DEF __CLC_GENTYPE select(__CLC_GENTYPE x, __CLC_GENTYPE y, __CLC_U_GENTYPE z) -{ - return z ? y : x; -} - -#ifdef __CLC_FPSIZE -#undef __CLC_S_GENTYPE -#undef __CLC_U_GENTYPE -#endif - -#ifdef __CLC_SCALAR -#undef __CLC_VECSIZE -#endif diff --git a/libcxx/docs/CodingGuidelines.rst b/libcxx/docs/CodingGuidelines.rst index 1bb62072e886d..9bf23a4cfe08b 100644 --- a/libcxx/docs/CodingGuidelines.rst +++ b/libcxx/docs/CodingGuidelines.rst @@ -184,3 +184,13 @@ headers (which is sometimes required for ``constexpr`` support). When defining a function at the ABI boundary, it can also be useful to consider which attributes (like ``[[gnu::pure]]`` and ``[[clang::noescape]]``) can be added to the function to improve the compiler's ability to optimize. + +Library-internal type aliases should be annotated with ``_LIBCPP_NODEBUG`` +========================================================================== + +Libc++ has lots of internal type aliases. Accumulated, these can result in significant amounts of debug information that +users generally don't care about, since users don't try to debug standard library facilities in most cases. For that +reason, all library-internal type aliases that aren't function-local should be annotated with ``_LIBCPP_NODEBUG`` to +prevent compilers from generating said debug information. + +This is enforced by the clang-tidy check ``libcpp-nodebug-on-aliases``. diff --git a/libcxx/include/__memory/uninitialized_algorithms.h b/libcxx/include/__memory/uninitialized_algorithms.h index 9587f01f64d58..a02a88399a7a7 100644 --- a/libcxx/include/__memory/uninitialized_algorithms.h +++ b/libcxx/include/__memory/uninitialized_algorithms.h @@ -585,9 +585,9 @@ __uninitialized_allocator_copy_impl(_Alloc&, _In* __first1, _In* __last1, _Out* template _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Iter2 __uninitialized_allocator_copy(_Alloc& __alloc, _Iter1 __first1, _Sent1 __last1, _Iter2 __first2) { - auto __unwrapped_range = std::__unwrap_range(__first1, __last1); + auto __unwrapped_range = std::__unwrap_range(std::move(__first1), std::move(__last1)); auto __result = std::__uninitialized_allocator_copy_impl( - __alloc, __unwrapped_range.first, __unwrapped_range.second, std::__unwrap_iter(__first2)); + __alloc, std::move(__unwrapped_range.first), std::move(__unwrapped_range.second), std::__unwrap_iter(__first2)); return std::__rewrap_iter(__first2, __result); } diff --git a/libcxx/include/__vector/vector.h b/libcxx/include/__vector/vector.h index d94aca6788c87..66cb622e20963 100644 --- a/libcxx/include/__vector/vector.h +++ b/libcxx/include/__vector/vector.h @@ -10,11 +10,13 @@ #define _LIBCPP___VECTOR_VECTOR_H #include <__algorithm/copy.h> +#include <__algorithm/copy_n.h> #include <__algorithm/fill_n.h> #include <__algorithm/max.h> #include <__algorithm/min.h> #include <__algorithm/move.h> #include <__algorithm/move_backward.h> +#include <__algorithm/ranges_copy_n.h> #include <__algorithm/rotate.h> #include <__assert> #include <__config> @@ -23,6 +25,7 @@ #include <__fwd/vector.h> #include <__iterator/advance.h> #include <__iterator/bounded_iter.h> +#include <__iterator/concepts.h> #include <__iterator/distance.h> #include <__iterator/iterator_traits.h> #include <__iterator/move_iterator.h> @@ -575,7 +578,7 @@ class _LIBCPP_TEMPLATE_VIS vector { if (__n > 0) { __vallocate(__n); - __construct_at_end(__first, __last, __n); + __construct_at_end(std::move(__first), std::move(__last), __n); } __guard.__complete(); @@ -595,9 +598,12 @@ class _LIBCPP_TEMPLATE_VIS vector { template _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __assign_with_sentinel(_Iterator __first, _Sentinel __last); - template + // The `_Iterator` in `*_with_size` functions can be input-only only if called from `*_range` (since C++23). + // Otherwise, `_Iterator` is a forward iterator. + + template _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void - __assign_with_size(_ForwardIterator __first, _Sentinel __last, difference_type __n); + __assign_with_size(_Iterator __first, _Sentinel __last, difference_type __n); template _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator @@ -918,7 +924,7 @@ template _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::__construct_at_end(_InputIterator __first, _Sentinel __last, size_type __n) { _ConstructTransaction __tx(*this, __n); - __tx.__pos_ = std::__uninitialized_allocator_copy(this->__alloc_, __first, __last, __tx.__pos_); + __tx.__pos_ = std::__uninitialized_allocator_copy(this->__alloc_, std::move(__first), std::move(__last), __tx.__pos_); } // Default constructs __n objects starting at __end_ @@ -1027,23 +1033,28 @@ vector<_Tp, _Allocator>::__assign_with_sentinel(_Iterator __first, _Sentinel __l } template -template +template _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void -vector<_Tp, _Allocator>::__assign_with_size(_ForwardIterator __first, _Sentinel __last, difference_type __n) { +vector<_Tp, _Allocator>::__assign_with_size(_Iterator __first, _Sentinel __last, difference_type __n) { size_type __new_size = static_cast(__n); if (__new_size <= capacity()) { if (__new_size > size()) { - _ForwardIterator __mid = std::next(__first, size()); +#if _LIBCPP_STD_VER >= 23 + auto __mid = ranges::copy_n(std::move(__first), size(), this->__begin_).in; + __construct_at_end(std::move(__mid), std::move(__last), __new_size - size()); +#else + _Iterator __mid = std::next(__first, size()); std::copy(__first, __mid, this->__begin_); __construct_at_end(__mid, __last, __new_size - size()); +#endif } else { - pointer __m = std::__copy(__first, __last, this->__begin_).second; + pointer __m = std::__copy(std::move(__first), __last, this->__begin_).second; this->__destruct_at_end(__m); } } else { __vdeallocate(); __vallocate(__recommend(__new_size)); - __construct_at_end(__first, __last, __new_size); + __construct_at_end(std::move(__first), std::move(__last), __new_size); } } @@ -1293,28 +1304,40 @@ template _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI typename vector<_Tp, _Allocator>::iterator vector<_Tp, _Allocator>::__insert_with_size( const_iterator __position, _Iterator __first, _Sentinel __last, difference_type __n) { - auto __insertion_size = __n; - pointer __p = this->__begin_ + (__position - begin()); + pointer __p = this->__begin_ + (__position - begin()); if (__n > 0) { if (__n <= this->__cap_ - this->__end_) { - size_type __old_n = __n; pointer __old_last = this->__end_; - _Iterator __m = std::next(__first, __n); difference_type __dx = this->__end_ - __p; if (__n > __dx) { - __m = __first; - difference_type __diff = this->__end_ - __p; - std::advance(__m, __diff); - __construct_at_end(__m, __last, __n - __diff); - __n = __dx; - } - if (__n > 0) { - __move_range(__p, __old_last, __p + __old_n); - std::copy(__first, __m, __p); +#if _LIBCPP_STD_VER >= 23 + if constexpr (!forward_iterator<_Iterator>) { + __construct_at_end(std::move(__first), std::move(__last), __n); + std::rotate(__p, __old_last, this->__end_); + } else +#endif + { + _Iterator __m = std::next(__first, __dx); + __construct_at_end(__m, __last, __n - __dx); + if (__dx > 0) { + __move_range(__p, __old_last, __p + __n); + std::copy(__first, __m, __p); + } + } + } else { + __move_range(__p, __old_last, __p + __n); +#if _LIBCPP_STD_VER >= 23 + if constexpr (!forward_iterator<_Iterator>) { + ranges::copy_n(std::move(__first), __n, __p); + } else +#endif + { + std::copy_n(__first, __n, __p); + } } } else { __split_buffer __v(__recommend(size() + __n), __p - this->__begin_, this->__alloc_); - __v.__construct_at_end_with_size(__first, __insertion_size); + __v.__construct_at_end_with_size(std::move(__first), __n); __p = __swap_out_circular_buffer(__v, __p); } } diff --git a/libcxx/include/__vector/vector_bool.h b/libcxx/include/__vector/vector_bool.h index 2b721e00058bc..4f1c442ce0be8 100644 --- a/libcxx/include/__vector/vector_bool.h +++ b/libcxx/include/__vector/vector_bool.h @@ -420,9 +420,12 @@ class _LIBCPP_TEMPLATE_VIS vector { template _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __assign_with_sentinel(_Iterator __first, _Sentinel __last); - template + // The `_Iterator` in `*_with_size` functions can be input-only only if called from `*_range` (since C++23). + // Otherwise, `_Iterator` is a forward iterator. + + template _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void - __assign_with_size(_ForwardIterator __first, _Sentinel __last, difference_type __ns); + __assign_with_size(_Iterator __first, _Sentinel __last, difference_type __ns); template _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator @@ -578,7 +581,7 @@ vector::__construct_at_end(_InputIterator __first, _Sentinel _ else this->__begin_[(this->__size_ - 1) / __bits_per_word] = __storage_type(0); } - std::__copy(__first, __last, __make_iter(__old_size)); + std::__copy(std::move(__first), std::move(__last), __make_iter(__old_size)); } template @@ -828,9 +831,9 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector::assign(_ForwardIter } template -template +template _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void -vector::__assign_with_size(_ForwardIterator __first, _Sentinel __last, difference_type __ns) { +vector::__assign_with_size(_Iterator __first, _Sentinel __last, difference_type __ns) { _LIBCPP_ASSERT_VALID_INPUT_RANGE(__ns >= 0, "invalid range specified"); clear(); @@ -841,7 +844,7 @@ vector::__assign_with_size(_ForwardIterator __first, _Sentinel __vdeallocate(); __vallocate(__n); } - __construct_at_end(__first, __last, __n); + __construct_at_end(std::move(__first), std::move(__last), __n); } } @@ -859,11 +862,13 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector::reserve(size_type _ template _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector::shrink_to_fit() _NOEXCEPT { - if (__external_cap_to_internal(size()) > __cap_) { + if (__external_cap_to_internal(size()) < __cap_) { #if _LIBCPP_HAS_EXCEPTIONS try { #endif // _LIBCPP_HAS_EXCEPTIONS - vector(*this, allocator_type(__alloc_)).swap(*this); + vector __v(*this, allocator_type(__alloc_)); + if (__v.__cap_ < __cap_) + __v.swap(*this); #if _LIBCPP_HAS_EXCEPTIONS } catch (...) { } @@ -986,10 +991,10 @@ vector::insert(const_iterator __position, _ForwardIterator __f } template -template +template _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI typename vector::iterator vector::__insert_with_size( - const_iterator __position, _ForwardIterator __first, _Sentinel __last, difference_type __n_signed) { + const_iterator __position, _Iterator __first, _Sentinel __last, difference_type __n_signed) { _LIBCPP_ASSERT_VALID_INPUT_RANGE(__n_signed >= 0, "invalid range specified"); const size_type __n = static_cast(__n_signed); iterator __r; @@ -1007,7 +1012,7 @@ vector::__insert_with_size( std::copy_backward(__position, cend(), __v.end()); swap(__v); } - std::__copy(__first, __last, __r); + std::__copy(std::move(__first), std::move(__last), __r); return __r; } diff --git a/libcxx/include/string b/libcxx/include/string index 39982d5670bdb..fdd8085106dcc 100644 --- a/libcxx/include/string +++ b/libcxx/include/string @@ -1919,7 +1919,8 @@ private: __copy_non_overlapping_range(_ForwardIter __first, _Sent __last, value_type* __dest) { # ifndef _LIBCPP_CXX03_LANG if constexpr (__libcpp_is_contiguous_iterator<_ForwardIter>::value && - is_same>::value && is_same<_ForwardIter, _Sent>::value) { + is_same>::value && + is_same<_ForwardIter, _Sent>::value) { _LIBCPP_ASSERT_INTERNAL( !std::__is_overlapping_range(std::__to_address(__first), std::__to_address(__last), __dest), "__copy_non_overlapping_range called with an overlapping range!"); @@ -1952,7 +1953,7 @@ private: __sz += __n; __set_size(__sz); traits_type::assign(__p[__sz], value_type()); - __copy_non_overlapping_range(__first, __last, __p + __ip); + __copy_non_overlapping_range(std::move(__first), std::move(__last), __p + __ip); return begin() + __ip; } @@ -2488,7 +2489,7 @@ basic_string<_CharT, _Traits, _Allocator>::__init_with_size(_InputIterator __fir # if _LIBCPP_HAS_EXCEPTIONS try { # endif // _LIBCPP_HAS_EXCEPTIONS - auto __end = __copy_non_overlapping_range(__first, __last, std::__to_address(__p)); + auto __end = __copy_non_overlapping_range(std::move(__first), std::move(__last), std::__to_address(__p)); traits_type::assign(*__end, value_type()); # if _LIBCPP_HAS_EXCEPTIONS } catch (...) { @@ -3080,9 +3081,9 @@ basic_string<_CharT, _Traits, _Allocator>::__insert_with_size( return begin() + __ip; if (__string_is_trivial_iterator<_Iterator>::value && !__addr_in_range(*__first)) { - return __insert_from_safe_copy(__n, __ip, __first, __last); + return __insert_from_safe_copy(__n, __ip, std::move(__first), std::move(__last)); } else { - const basic_string __temp(__init_with_sentinel_tag(), __first, __last, __alloc_); + const basic_string __temp(__init_with_sentinel_tag(), std::move(__first), std::move(__last), __alloc_); return __insert_from_safe_copy(__n, __ip, __temp.begin(), __temp.end()); } } diff --git a/libcxx/include/tuple b/libcxx/include/tuple index 0c96786ae6d02..5d968bfd4015a 100644 --- a/libcxx/include/tuple +++ b/libcxx/include/tuple @@ -257,6 +257,7 @@ template # include <__type_traits/maybe_const.h> # include <__type_traits/nat.h> # include <__type_traits/negation.h> +# include <__type_traits/remove_cv.h> # include <__type_traits/remove_cvref.h> # include <__type_traits/remove_reference.h> # include <__type_traits/unwrap_ref.h> @@ -390,7 +391,7 @@ public: }; template -class __tuple_leaf<_Ip, _Hp, true> : private _Hp { +class __tuple_leaf<_Ip, _Hp, true> : private __remove_cv_t<_Hp> { public: _LIBCPP_CONSTEXPR_SINCE_CXX14 __tuple_leaf& operator=(const __tuple_leaf&) = delete; diff --git a/libcxx/test/std/containers/sequences/vector.bool/assign_range.pass.cpp b/libcxx/test/std/containers/sequences/vector.bool/assign_range.pass.cpp index e5d0454a844d5..a8cbb32c2655e 100644 --- a/libcxx/test/std/containers/sequences/vector.bool/assign_range.pass.cpp +++ b/libcxx/test/std/containers/sequences/vector.bool/assign_range.pass.cpp @@ -12,6 +12,7 @@ // template R> // constexpr void assign_range(R&& rg); // C++23 +#include #include #include "../insert_range_sequence_containers.h" @@ -49,11 +50,29 @@ constexpr bool test() { v.assign_range(in); assert(std::ranges::equal(v, in)); } + + { // Ensure input-only sized ranges are accepted. + using input_iter = cpp20_input_iterator; + const bool in[]{true, true, false, true}; + std::vector v; + v.assign_range(std::views::counted(input_iter{std::ranges::begin(in)}, std::ranges::ssize(in))); + assert(std::ranges::equal(v, std::vector{true, true, false, true})); + } } return true; } +#ifndef TEST_HAS_NO_LOCALIZATION +void test_counted_istream_view() { + std::istringstream is{"1 1 0 1"}; + auto vals = std::views::istream(is); + std::vector v; + v.assign_range(std::views::counted(vals.begin(), 3)); + assert(v == (std::vector{true, true, false})); +} +#endif + int main(int, char**) { test(); static_assert(test()); @@ -61,5 +80,9 @@ int main(int, char**) { // Note: `test_assign_range_exception_safety_throwing_copy` doesn't apply because copying booleans cannot throw. test_assign_range_exception_safety_throwing_allocator(); +#ifndef TEST_HAS_NO_LOCALIZATION + test_counted_istream_view(); +#endif + return 0; } diff --git a/libcxx/test/std/containers/sequences/vector.bool/construct_from_range.pass.cpp b/libcxx/test/std/containers/sequences/vector.bool/construct_from_range.pass.cpp index 03f3100b92883..055f2378125d9 100644 --- a/libcxx/test/std/containers/sequences/vector.bool/construct_from_range.pass.cpp +++ b/libcxx/test/std/containers/sequences/vector.bool/construct_from_range.pass.cpp @@ -8,6 +8,7 @@ // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 +#include #include #include "../from_range_sequence_containers.h" @@ -24,9 +25,25 @@ constexpr bool test() { }); }); + { // Ensure input-only sized ranges are accepted. + using input_iter = cpp20_input_iterator; + const bool in[]{true, true, false, true}; + std::vector v(std::from_range, std::views::counted(input_iter{std::ranges::begin(in)}, std::ranges::ssize(in))); + assert(std::ranges::equal(v, std::vector{true, true, false, true})); + } + return true; } +#ifndef TEST_HAS_NO_LOCALIZATION +void test_counted_istream_view() { + std::istringstream is{"1 1 0 1"}; + auto vals = std::views::istream(is); + std::vector v(std::from_range, std::views::counted(vals.begin(), 3)); + assert(v == (std::vector{true, true, false})); +} +#endif + int main(int, char**) { test(); static_assert(test()); @@ -36,5 +53,9 @@ int main(int, char**) { // Note: test_exception_safety_throwing_copy doesn't apply because copying a boolean cannot throw. test_exception_safety_throwing_allocator(); +#ifndef TEST_HAS_NO_LOCALIZATION + test_counted_istream_view(); +#endif + return 0; } diff --git a/libcxx/test/std/containers/sequences/vector.bool/insert_range.pass.cpp b/libcxx/test/std/containers/sequences/vector.bool/insert_range.pass.cpp index 65d085fa1f083..d8f19d47e9942 100644 --- a/libcxx/test/std/containers/sequences/vector.bool/insert_range.pass.cpp +++ b/libcxx/test/std/containers/sequences/vector.bool/insert_range.pass.cpp @@ -12,6 +12,7 @@ // template R> // constexpr iterator insert_range(const_iterator position, R&& rg); // C++23 +#include #include #include "../insert_range_sequence_containers.h" @@ -56,11 +57,29 @@ constexpr bool test() { v.insert_range(v.end(), in); assert(std::ranges::equal(v, std::vector{0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1})); } + + { // Ensure input-only sized ranges are accepted. + using input_iter = cpp20_input_iterator; + const bool in[]{true, true, false, true}; + std::vector v{true, false}; + v.insert_range(v.begin(), std::views::counted(input_iter{std::ranges::begin(in)}, std::ranges::ssize(in))); + assert(std::ranges::equal(v, std::vector{true, true, false, true, true, false})); + } } return true; } +#ifndef TEST_HAS_NO_LOCALIZATION +void test_counted_istream_view() { + std::istringstream is{"1 1 0 1"}; + auto vals = std::views::istream(is); + std::vector v; + v.insert_range(v.end(), std::views::counted(vals.begin(), 3)); + assert(v == (std::vector{true, true, false})); +} +#endif + int main(int, char**) { test(); static_assert(test()); @@ -68,5 +87,9 @@ int main(int, char**) { // Note: `test_insert_range_exception_safety_throwing_copy` doesn't apply because copying booleans cannot throw. test_insert_range_exception_safety_throwing_allocator(); +#ifndef TEST_HAS_NO_LOCALIZATION + test_counted_istream_view(); +#endif + return 0; } diff --git a/libcxx/test/std/containers/sequences/vector.bool/shrink_to_fit.pass.cpp b/libcxx/test/std/containers/sequences/vector.bool/shrink_to_fit.pass.cpp index 3bc639d0479f9..30efe047054ab 100644 --- a/libcxx/test/std/containers/sequences/vector.bool/shrink_to_fit.pass.cpp +++ b/libcxx/test/std/containers/sequences/vector.bool/shrink_to_fit.pass.cpp @@ -11,7 +11,10 @@ // void shrink_to_fit(); +// XFAIL: FROZEN-CXX03-HEADERS-FIXME + #include +#include #include #include "increasing_allocator.h" @@ -20,19 +23,56 @@ TEST_CONSTEXPR_CXX20 bool tests() { { - std::vector v(100); + using C = std::vector; + C v(100); v.push_back(1); + C::size_type before_cap = v.capacity(); + v.clear(); v.shrink_to_fit(); - assert(v.capacity() >= 101); - assert(v.size() >= 101); + assert(v.capacity() <= before_cap); + LIBCPP_ASSERT(v.capacity() == 0); // libc++ honors the shrink_to_fit request as a QOI matter + assert(v.size() == 0); } -#if TEST_STD_VER >= 11 { - std::vector> v(100); + using C = std::vector >; + C v(100); v.push_back(1); + C::size_type before_cap = v.capacity(); v.shrink_to_fit(); assert(v.capacity() >= 101); - assert(v.size() >= 101); + assert(v.capacity() <= before_cap); + assert(v.size() == 101); + v.erase(v.begin() + 1, v.end()); + v.shrink_to_fit(); + assert(v.capacity() <= before_cap); + LIBCPP_ASSERT(v.capacity() == C(1).capacity()); // libc++ honors the shrink_to_fit request as a QOI matter. + assert(v.size() == 1); + } + +#if defined(_LIBCPP_VERSION) + { + using C = std::vector; + unsigned bits_per_word = static_cast(sizeof(C::__storage_type) * CHAR_BIT); + C v(bits_per_word); + v.push_back(1); + assert(v.capacity() == bits_per_word * 2); + assert(v.size() == bits_per_word + 1); + v.pop_back(); + v.shrink_to_fit(); + assert(v.capacity() == bits_per_word); + assert(v.size() == bits_per_word); + } + { + using C = std::vector; + unsigned bits_per_word = static_cast(sizeof(C::__storage_type) * CHAR_BIT); + C v; + v.reserve(bits_per_word * 2); + v.push_back(1); + assert(v.capacity() == bits_per_word * 2); + assert(v.size() == 1); + v.shrink_to_fit(); + assert(v.capacity() == bits_per_word); + assert(v.size() == 1); } #endif diff --git a/libcxx/test/std/containers/sequences/vector/vector.cons/construct_from_range.pass.cpp b/libcxx/test/std/containers/sequences/vector/vector.cons/construct_from_range.pass.cpp index 5fb2b46f7e942..501abf396391f 100644 --- a/libcxx/test/std/containers/sequences/vector/vector.cons/construct_from_range.pass.cpp +++ b/libcxx/test/std/containers/sequences/vector/vector.cons/construct_from_range.pass.cpp @@ -11,6 +11,7 @@ // template R> // vector(from_range_t, R&& rg, const Allocator& = Allocator()); // C++23 +#include #include #include "../../from_range_sequence_containers.h" @@ -26,9 +27,25 @@ constexpr bool test() { }); test_sequence_container_move_only(); + { // Ensure input-only sized ranges are accepted. + using input_iter = cpp20_input_iterator; + const int in[]{1, 2, 3, 4}; + std::vector v(std::from_range, std::views::counted(input_iter{std::ranges::begin(in)}, std::ranges::ssize(in))); + assert(std::ranges::equal(v, std::vector{1, 2, 3, 4})); + } + return true; } +#ifndef TEST_HAS_NO_LOCALIZATION +void test_counted_istream_view() { + std::istringstream is{"1 2 3 4"}; + auto vals = std::views::istream(is); + std::vector v(std::from_range, std::views::counted(vals.begin(), 3)); + assert(v == (std::vector{1, 2, 3})); +} +#endif + int main(int, char**) { static_assert(test_constraints()); test(); @@ -38,5 +55,9 @@ int main(int, char**) { test_exception_safety_throwing_copy(); test_exception_safety_throwing_allocator(); +#ifndef TEST_HAS_NO_LOCALIZATION + test_counted_istream_view(); +#endif + return 0; } diff --git a/libcxx/test/std/containers/sequences/vector/vector.modifiers/assign_range.pass.cpp b/libcxx/test/std/containers/sequences/vector/vector.modifiers/assign_range.pass.cpp index 8ab3dc10aed99..6326ffca96966 100644 --- a/libcxx/test/std/containers/sequences/vector/vector.modifiers/assign_range.pass.cpp +++ b/libcxx/test/std/containers/sequences/vector/vector.modifiers/assign_range.pass.cpp @@ -12,6 +12,7 @@ // template R> // constexpr void assign_range(R&& rg); // C++23 +#include #include #include "../../insert_range_sequence_containers.h" @@ -62,11 +63,29 @@ constexpr bool test() { v.assign_range(in); assert(std::ranges::equal(v, in)); } + + { // Ensure input-only sized ranges are accepted. + using input_iter = cpp20_input_iterator; + const int in[]{1, 2, 3, 4}; + std::vector v; + v.assign_range(std::views::counted(input_iter{std::ranges::begin(in)}, std::ranges::ssize(in))); + assert(std::ranges::equal(v, std::vector{1, 2, 3, 4})); + } } return true; } +#ifndef TEST_HAS_NO_LOCALIZATION +void test_counted_istream_view() { + std::istringstream is{"1 2 3 4"}; + auto vals = std::views::istream(is); + std::vector v; + v.assign_range(std::views::counted(vals.begin(), 3)); + assert(v == (std::vector{1, 2, 3})); +} +#endif + int main(int, char**) { test(); static_assert(test()); @@ -74,5 +93,9 @@ int main(int, char**) { test_assign_range_exception_safety_throwing_copy(); test_assign_range_exception_safety_throwing_allocator(); +#ifndef TEST_HAS_NO_LOCALIZATION + test_counted_istream_view(); +#endif + return 0; } diff --git a/libcxx/test/std/containers/sequences/vector/vector.modifiers/insert_range.pass.cpp b/libcxx/test/std/containers/sequences/vector/vector.modifiers/insert_range.pass.cpp index 0e26cb1546277..25ffc33aad424 100644 --- a/libcxx/test/std/containers/sequences/vector/vector.modifiers/insert_range.pass.cpp +++ b/libcxx/test/std/containers/sequences/vector/vector.modifiers/insert_range.pass.cpp @@ -12,6 +12,7 @@ // template R> // constexpr iterator insert_range(const_iterator position, R&& rg); // C++23 +#include #include #include "../../insert_range_sequence_containers.h" @@ -53,11 +54,29 @@ constexpr bool test() { v.insert_range(v.end(), in); assert(std::ranges::equal(v, std::array{1, 2, 3, 4, 5, 6, 7, 8, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10})); } + + { // Ensure input-only sized ranges are accepted. + using input_iter = cpp20_input_iterator; + const int in[]{1, 2, 3, 4}; + std::vector v{-5, -6}; + v.insert_range(v.begin(), std::views::counted(input_iter{std::ranges::begin(in)}, std::ranges::ssize(in))); + assert(std::ranges::equal(v, std::vector{1, 2, 3, 4, -5, -6})); + } } return true; } +#ifndef TEST_HAS_NO_LOCALIZATION +void test_counted_istream_view() { + std::istringstream is{"1 2 3 4"}; + auto vals = std::views::istream(is); + std::vector v; + v.insert_range(v.end(), std::views::counted(vals.begin(), 3)); + assert(v == (std::vector{1, 2, 3})); +} +#endif + int main(int, char**) { test(); static_assert(test()); @@ -67,5 +86,9 @@ int main(int, char**) { test_insert_range_exception_safety_throwing_copy(); test_insert_range_exception_safety_throwing_allocator(); +#ifndef TEST_HAS_NO_LOCALIZATION + test_counted_istream_view(); +#endif + return 0; } diff --git a/libcxx/test/std/strings/basic.string/string.cons/from_range.pass.cpp b/libcxx/test/std/strings/basic.string/string.cons/from_range.pass.cpp index 6a1b45b25ef03..c110a59d606ff 100644 --- a/libcxx/test/std/strings/basic.string/string.cons/from_range.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.cons/from_range.pass.cpp @@ -12,6 +12,7 @@ // constexpr basic_string(from_range_t, R&& rg, const Allocator& a = Allocator()); // since C++23 #include +#include #include #include #include @@ -82,6 +83,13 @@ constexpr void test_with_input(std::vector input) { assert(std::ranges::equal(input, c)); LIBCPP_ASSERT(is_string_asan_correct(c)); } + + { // Ensure input-only sized ranges are accepted. + using input_iter = cpp20_input_iterator; + const char in[]{'q', 'w', 'e', 'r'}; + std::string s(std::from_range, std::views::counted(input_iter{std::ranges::begin(in)}, std::ranges::ssize(in))); + assert(s == "qwer"); + } } void test_string_exception_safety_throwing_allocator() { @@ -116,6 +124,15 @@ constexpr bool test_inputs() { return true; } +#ifndef TEST_HAS_NO_LOCALIZATION +void test_counted_istream_view() { + std::istringstream is{"qwert"}; + auto vals = std::views::istream(is); + std::string s(std::from_range, std::views::counted(vals.begin(), 3)); + assert(s == "qwe"); +} +#endif + int main(int, char**) { test_inputs(); static_assert(test_inputs()); @@ -125,5 +142,9 @@ int main(int, char**) { // Note: `test_exception_safety_throwing_copy` doesn't apply because copying a `char` cannot throw. test_string_exception_safety_throwing_allocator(); +#ifndef TEST_HAS_NO_LOCALIZATION + test_counted_istream_view(); +#endif + return 0; } diff --git a/libcxx/test/std/strings/basic.string/string.modifiers/string_insert/insert_range.pass.cpp b/libcxx/test/std/strings/basic.string/string.modifiers/string_insert/insert_range.pass.cpp index 45d1f620e9054..691cd0e19fa3a 100644 --- a/libcxx/test/std/strings/basic.string/string.modifiers/string_insert/insert_range.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.modifiers/string_insert/insert_range.pass.cpp @@ -11,6 +11,7 @@ // template R> // constexpr iterator insert_range(const_iterator p, R&& rg); // C++23 +#include #include #include "../../../../containers/sequences/insert_range_sequence_containers.h" @@ -27,9 +28,27 @@ constexpr bool test_constexpr() { []([[maybe_unused]] auto&& c) { LIBCPP_ASSERT(c.__invariants()); }); }); + { // Ensure input-only sized ranges are accepted. + using input_iter = cpp20_input_iterator; + const char in[]{'q', 'w', 'e', 'r'}; + std::string s = "zxcv"; + s.insert_range(s.begin(), std::views::counted(input_iter{std::ranges::begin(in)}, std::ranges::ssize(in))); + assert(s == "qwerzxcv"); + } + return true; } +#ifndef TEST_HAS_NO_LOCALIZATION +void test_counted_istream_view() { + std::istringstream is{"qwert"}; + auto vals = std::views::istream(is); + std::string s = "zxcv"; + s.insert_range(s.begin(), std::views::counted(vals.begin(), 3)); + assert(s == "qwezxcv"); +} +#endif + int main(int, char**) { static_assert(test_constraints_insert_range()); @@ -39,6 +58,10 @@ int main(int, char**) { }); static_assert(test_constexpr()); +#ifndef TEST_HAS_NO_LOCALIZATION + test_counted_istream_view(); +#endif + // Note: `test_insert_range_exception_safety_throwing_copy` doesn't apply because copying chars cannot throw. { #if !defined(TEST_HAS_NO_EXCEPTIONS) diff --git a/lld/COFF/Chunks.cpp b/lld/COFF/Chunks.cpp index ff3c89884c24d..11e7cf4346b23 100644 --- a/lld/COFF/Chunks.cpp +++ b/lld/COFF/Chunks.cpp @@ -1167,7 +1167,7 @@ uint32_t ImportThunkChunkARM64EC::extendRanges() { } uint64_t Arm64XRelocVal::get() const { - return (sym ? sym->getRVA() : 0) + value; + return (sym ? sym->getRVA() : 0) + (chunk ? chunk->getRVA() : 0) + value; } size_t Arm64XDynamicRelocEntry::getSize() const { @@ -1230,6 +1230,17 @@ void DynamicRelocsChunk::finalize() { size = alignTo(size, sizeof(uint32_t)); } +// Set the reloc value. The reloc entry must be allocated beforehand. +void DynamicRelocsChunk::set(uint32_t rva, Arm64XRelocVal value) { + auto entry = + llvm::find_if(arm64xRelocs, [rva](const Arm64XDynamicRelocEntry &e) { + return e.offset.get() == rva; + }); + assert(entry != arm64xRelocs.end()); + assert(!entry->value.get()); + entry->value = value; +} + void DynamicRelocsChunk::writeTo(uint8_t *buf) const { auto table = reinterpret_cast(buf); table->Version = 1; diff --git a/lld/COFF/Chunks.h b/lld/COFF/Chunks.h index 7ba58e336451f..d6216efdd90bd 100644 --- a/lld/COFF/Chunks.h +++ b/lld/COFF/Chunks.h @@ -840,10 +840,13 @@ class Arm64XRelocVal { public: Arm64XRelocVal(uint64_t value = 0) : value(value) {} Arm64XRelocVal(Defined *sym, int32_t offset = 0) : sym(sym), value(offset) {} + Arm64XRelocVal(Chunk *chunk, int32_t offset = 0) + : chunk(chunk), value(offset) {} uint64_t get() const; private: Defined *sym = nullptr; + Chunk *chunk = nullptr; uint64_t value; }; @@ -874,10 +877,12 @@ class DynamicRelocsChunk : public NonSectionChunk { void finalize(); void add(llvm::COFF::Arm64XFixupType type, uint8_t size, - Arm64XRelocVal offset, Arm64XRelocVal value) { + Arm64XRelocVal offset, Arm64XRelocVal value = Arm64XRelocVal()) { arm64xRelocs.emplace_back(type, size, offset, value); } + void set(uint32_t rva, Arm64XRelocVal value); + private: std::vector arm64xRelocs; size_t size; diff --git a/lld/COFF/Config.h b/lld/COFF/Config.h index b08427f738bb4..cd280aa09964d 100644 --- a/lld/COFF/Config.h +++ b/lld/COFF/Config.h @@ -162,8 +162,6 @@ struct Configuration { bool dll = false; StringRef implib; bool noimplib = false; - std::vector exports; - bool hadExplicitExports; std::set delayLoads; std::map dllOrder; Symbol *delayLoadHelper = nullptr; diff --git a/lld/COFF/DLL.cpp b/lld/COFF/DLL.cpp index 3e9f3f4718386..6a3f8eb21e847 100644 --- a/lld/COFF/DLL.cpp +++ b/lld/COFF/DLL.cpp @@ -639,22 +639,22 @@ class ExportDirectoryChunk : public NonSectionChunk { class AddressTableChunk : public NonSectionChunk { public: - explicit AddressTableChunk(COFFLinkerContext &ctx, size_t baseOrdinal, + explicit AddressTableChunk(SymbolTable &symtab, size_t baseOrdinal, size_t maxOrdinal) : baseOrdinal(baseOrdinal), size((maxOrdinal - baseOrdinal) + 1), - ctx(ctx) {} + symtab(symtab) {} size_t getSize() const override { return size * 4; } void writeTo(uint8_t *buf) const override { memset(buf, 0, getSize()); - for (const Export &e : ctx.config.exports) { + for (const Export &e : symtab.exports) { assert(e.ordinal >= baseOrdinal && "Export symbol has invalid ordinal"); // Subtract the OrdinalBase to get the index. uint8_t *p = buf + (e.ordinal - baseOrdinal) * 4; uint32_t bit = 0; // Pointer to thumb code must have the LSB set, so adjust it. - if (ctx.config.machine == ARMNT && !e.data) + if (symtab.machine == ARMNT && !e.data) bit = 1; if (e.forwardChunk) { write32le(p, e.forwardChunk->getRVA() | bit); @@ -669,7 +669,7 @@ class AddressTableChunk : public NonSectionChunk { private: size_t baseOrdinal; size_t size; - const COFFLinkerContext &ctx; + const SymbolTable &symtab; }; class NamePointersChunk : public NonSectionChunk { @@ -690,13 +690,13 @@ class NamePointersChunk : public NonSectionChunk { class ExportOrdinalChunk : public NonSectionChunk { public: - explicit ExportOrdinalChunk(const COFFLinkerContext &ctx, size_t baseOrdinal, + explicit ExportOrdinalChunk(const SymbolTable &symtab, size_t baseOrdinal, size_t tableSize) - : baseOrdinal(baseOrdinal), size(tableSize), ctx(ctx) {} + : baseOrdinal(baseOrdinal), size(tableSize), symtab(symtab) {} size_t getSize() const override { return size * 2; } void writeTo(uint8_t *buf) const override { - for (const Export &e : ctx.config.exports) { + for (const Export &e : symtab.exports) { if (e.noname) continue; assert(e.ordinal >= baseOrdinal && "Export symbol has invalid ordinal"); @@ -709,7 +709,7 @@ class ExportOrdinalChunk : public NonSectionChunk { private: size_t baseOrdinal; size_t size; - const COFFLinkerContext &ctx; + const SymbolTable &symtab; }; } // anonymous namespace @@ -920,9 +920,9 @@ Chunk *DelayLoadContents::newThunkChunk(DefinedImportData *s, } } -void createEdataChunks(COFFLinkerContext &ctx, std::vector &chunks) { +void createEdataChunks(SymbolTable &symtab, std::vector &chunks) { unsigned baseOrdinal = 1 << 16, maxOrdinal = 0; - for (Export &e : ctx.config.exports) { + for (Export &e : symtab.exports) { baseOrdinal = std::min(baseOrdinal, (unsigned)e.ordinal); maxOrdinal = std::max(maxOrdinal, (unsigned)e.ordinal); } @@ -930,15 +930,16 @@ void createEdataChunks(COFFLinkerContext &ctx, std::vector &chunks) { // https://learn.microsoft.com/en-us/cpp/build/reference/export-exports-a-function?view=msvc-170 assert(baseOrdinal >= 1); - auto *dllName = make(sys::path::filename(ctx.config.outputFile)); - auto *addressTab = make(ctx, baseOrdinal, maxOrdinal); + auto *dllName = + make(sys::path::filename(symtab.ctx.config.outputFile)); + auto *addressTab = make(symtab, baseOrdinal, maxOrdinal); std::vector names; - for (Export &e : ctx.config.exports) + for (Export &e : symtab.exports) if (!e.noname) names.push_back(make(e.exportName)); std::vector forwards; - for (Export &e : ctx.config.exports) { + for (Export &e : symtab.exports) { if (e.forwardTo.empty()) continue; e.forwardChunk = make(e.forwardTo); @@ -946,7 +947,8 @@ void createEdataChunks(COFFLinkerContext &ctx, std::vector &chunks) { } auto *nameTab = make(names); - auto *ordinalTab = make(ctx, baseOrdinal, names.size()); + auto *ordinalTab = + make(symtab, baseOrdinal, names.size()); auto *dir = make(baseOrdinal, maxOrdinal, names.size(), dllName, addressTab, nameTab, ordinalTab); diff --git a/lld/COFF/DLL.h b/lld/COFF/DLL.h index 901c974069b47..724a323d62d20 100644 --- a/lld/COFF/DLL.h +++ b/lld/COFF/DLL.h @@ -78,7 +78,7 @@ class DelayLoadContents { }; // Create all chunks for the DLL export table. -void createEdataChunks(COFFLinkerContext &ctx, std::vector &chunks); +void createEdataChunks(SymbolTable &symtab, std::vector &chunks); } // namespace lld::coff diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp index b257071c97086..4e0678282eed0 100644 --- a/lld/COFF/Driver.cpp +++ b/lld/COFF/Driver.cpp @@ -458,7 +458,7 @@ void LinkerDriver::parseDirectives(InputFile *file) { // declarations, many object files may end up with having the // same /EXPORT options. In order to save cost of parsing them, // we dedup them first. - if (!directivesExports.insert(e).second) + if (!file->symtab.directivesExports.insert(e).second) continue; Export exp = parseExport(e); @@ -469,7 +469,7 @@ void LinkerDriver::parseDirectives(InputFile *file) { exp.extName = saver().save("_" + exp.extName); } exp.source = ExportSource::Directives; - ctx.config.exports.push_back(exp); + file->symtab.exports.push_back(exp); } // Handle /include: in bulk. @@ -956,7 +956,7 @@ std::string LinkerDriver::getImportName(bool asLib) { void LinkerDriver::createImportLibrary(bool asLib) { llvm::TimeTraceScope timeScope("Create import library"); std::vector exports; - for (Export &e1 : ctx.config.exports) { + for (Export &e1 : ctx.symtab.exports) { COFFShortExport e2; e2.Name = std::string(e1.name); e2.SymbolName = std::string(e1.symbolName); @@ -1069,7 +1069,7 @@ void LinkerDriver::parseModuleDefs(StringRef path) { e2.isPrivate = e1.Private; e2.constant = e1.Constant; e2.source = ExportSource::ModuleDefinition; - ctx.config.exports.push_back(e2); + ctx.symtab.exports.push_back(e2); } } @@ -1222,8 +1222,10 @@ static void findKeepUniqueSections(COFFLinkerContext &ctx) { // Exported symbols could be address-significant in other executables or DSOs, // so we conservatively mark them as address-significant. - for (Export &r : ctx.config.exports) - markAddrsig(r.sym); + ctx.forEachSymtab([](SymbolTable &symtab) { + for (Export &r : symtab.exports) + markAddrsig(r.sym); + }); // Visit the address-significance table in each object file and mark each // referenced symbol as address-significant. @@ -1376,13 +1378,13 @@ void LinkerDriver::maybeCreateECExportThunk(StringRef name, Symbol *&sym) { void LinkerDriver::createECExportThunks() { // Check if EXP+ symbols have corresponding $hp_target symbols and use them // to create export thunks when available. - for (Symbol *s : ctx.symtab.expSymbols) { + for (Symbol *s : ctx.symtabEC->expSymbols) { if (!s->isUsedInRegularObj) continue; assert(s->getName().starts_with("EXP+")); std::string targetName = (s->getName().substr(strlen("EXP+")) + "$hp_target").str(); - Symbol *sym = ctx.symtab.find(targetName); + Symbol *sym = ctx.symtabEC->find(targetName); if (!sym) continue; Defined *targetSym; @@ -1407,7 +1409,7 @@ void LinkerDriver::createECExportThunks() { if (ctx.symtabEC->entry) maybeCreateECExportThunk(ctx.symtabEC->entry->getName(), ctx.symtabEC->entry); - for (Export &e : ctx.config.exports) { + for (Export &e : ctx.symtabEC->exports) { if (!e.data) maybeCreateECExportThunk(e.extName.empty() ? e.name : e.extName, e.sym); } @@ -1430,7 +1432,7 @@ void LinkerDriver::maybeExportMinGWSymbols(const opt::InputArgList &args) { if (!ctx.config.dll) return; - if (!ctx.config.exports.empty()) + if (!ctx.symtab.exports.empty()) return; if (args.hasArg(OPT_exclude_all_symbols)) return; @@ -1466,7 +1468,7 @@ void LinkerDriver::maybeExportMinGWSymbols(const opt::InputArgList &args) { if (!(c->getOutputCharacteristics() & IMAGE_SCN_MEM_EXECUTE)) e.data = true; s->isUsedInRegularObj = true; - ctx.config.exports.push_back(e); + ctx.symtab.exports.push_back(e); }); } @@ -2343,7 +2345,7 @@ void LinkerDriver::linkerMain(ArrayRef argsArr) { if (!e.extName.empty() && !isDecorated(e.extName)) e.extName = saver().save("_" + e.extName); } - config->exports.push_back(e); + mainSymtab.exports.push_back(e); } } @@ -2355,7 +2357,7 @@ void LinkerDriver::linkerMain(ArrayRef argsArr) { // Handle generation of import library from a def file. if (!args.hasArg(OPT_INPUT, OPT_wholearchive_file)) { - fixupExports(); + ctx.forEachSymtab([](SymbolTable &symtab) { symtab.fixupExports(); }); if (!config->noimplib) createImportLibrary(/*asLib=*/true); return; @@ -2541,16 +2543,16 @@ void LinkerDriver::linkerMain(ArrayRef argsArr) { // search for its mangled names. if (symtab.entry) symtab.mangleMaybe(symtab.entry); - }); - // Windows specific -- Make sure we resolve all dllexported symbols. - for (Export &e : config->exports) { - if (!e.forwardTo.empty()) - continue; - e.sym = ctx.symtab.addGCRoot(e.name, !e.data); - if (e.source != ExportSource::Directives) - e.symbolName = ctx.symtab.mangleMaybe(e.sym); - } + // Windows specific -- Make sure we resolve all dllexported symbols. + for (Export &e : symtab.exports) { + if (!e.forwardTo.empty()) + continue; + e.sym = symtab.addGCRoot(e.name, !e.data); + if (e.source != ExportSource::Directives) + e.symbolName = symtab.mangleMaybe(e.sym); + } + }); // Add weak aliases. Weak aliases is a mechanism to give remaining // undefined symbols final chance to be resolved successfully. @@ -2651,7 +2653,9 @@ void LinkerDriver::linkerMain(ArrayRef argsArr) { if (errorCount()) return; - config->hadExplicitExports = !config->exports.empty(); + ctx.forEachSymtab([](SymbolTable &symtab) { + symtab.hadExplicitExports = !symtab.exports.empty(); + }); if (config->mingw) { // In MinGW, all symbols are automatically exported if no symbols // are chosen to be exported. @@ -2716,17 +2720,18 @@ void LinkerDriver::linkerMain(ArrayRef argsArr) { // Windows specific -- when we are creating a .dll file, we also // need to create a .lib file. In MinGW mode, we only do that when the // -implib option is given explicitly, for compatibility with GNU ld. - if (!config->exports.empty() || config->dll) { + if (!ctx.symtab.exports.empty() || config->dll) { llvm::TimeTraceScope timeScope("Create .lib exports"); - fixupExports(); + ctx.forEachSymtab([](SymbolTable &symtab) { symtab.fixupExports(); }); if (!config->noimplib && (!config->mingw || !config->implib.empty())) createImportLibrary(/*asLib=*/false); - assignExportOrdinals(); + ctx.forEachSymtab( + [](SymbolTable &symtab) { symtab.assignExportOrdinals(); }); } // Handle /output-def (MinGW specific). if (auto *arg = args.getLastArg(OPT_output_def)) - writeDefFile(ctx, arg->getValue(), config->exports); + writeDefFile(ctx, arg->getValue(), ctx.symtab.exports); // Set extra alignment for .comm symbols for (auto pair : config->alignComm) { diff --git a/lld/COFF/Driver.h b/lld/COFF/Driver.h index 5f65bd7f8d097..12724cbd1eef4 100644 --- a/lld/COFF/Driver.h +++ b/lld/COFF/Driver.h @@ -182,7 +182,6 @@ class LinkerDriver { std::list> taskQueue; std::vector resources; - llvm::DenseSet directivesExports; llvm::DenseSet excludedSymbols; COFFLinkerContext &ctx; @@ -249,8 +248,6 @@ class LinkerDriver { // Used for dllexported symbols. Export parseExport(StringRef arg); - void fixupExports(); - void assignExportOrdinals(); // Parses a string in the form of "key=value" and check // if value matches previous values for the key. diff --git a/lld/COFF/DriverUtils.cpp b/lld/COFF/DriverUtils.cpp index 19abd4806d53f..4a70c826691d1 100644 --- a/lld/COFF/DriverUtils.cpp +++ b/lld/COFF/DriverUtils.cpp @@ -656,142 +656,6 @@ Export LinkerDriver::parseExport(StringRef arg) { llvm_unreachable(""); } -// Convert stdcall/fastcall style symbols into unsuffixed symbols, -// with or without a leading underscore. (MinGW specific.) -static StringRef killAt(StringRef sym, bool prefix) { - if (sym.empty()) - return sym; - // Strip any trailing stdcall suffix - sym = sym.substr(0, sym.find('@', 1)); - if (!sym.starts_with("@")) { - if (prefix && !sym.starts_with("_")) - return saver().save("_" + sym); - return sym; - } - // For fastcall, remove the leading @ and replace it with an - // underscore, if prefixes are used. - sym = sym.substr(1); - if (prefix) - sym = saver().save("_" + sym); - return sym; -} - -static StringRef exportSourceName(ExportSource s) { - switch (s) { - case ExportSource::Directives: - return "source file (directives)"; - case ExportSource::Export: - return "/export"; - case ExportSource::ModuleDefinition: - return "/def"; - default: - llvm_unreachable("unknown ExportSource"); - } -} - -// Performs error checking on all /export arguments. -// It also sets ordinals. -void LinkerDriver::fixupExports() { - llvm::TimeTraceScope timeScope("Fixup exports"); - // Symbol ordinals must be unique. - std::set ords; - for (Export &e : ctx.config.exports) { - if (e.ordinal == 0) - continue; - if (!ords.insert(e.ordinal).second) - Fatal(ctx) << "duplicate export ordinal: " << e.name; - } - - for (Export &e : ctx.config.exports) { - if (!e.exportAs.empty()) { - e.exportName = e.exportAs; - continue; - } - - StringRef sym = - !e.forwardTo.empty() || e.extName.empty() ? e.name : e.extName; - if (ctx.config.machine == I386 && sym.starts_with("_")) { - // In MSVC mode, a fully decorated stdcall function is exported - // as-is with the leading underscore (with type IMPORT_NAME). - // In MinGW mode, a decorated stdcall function gets the underscore - // removed, just like normal cdecl functions. - if (ctx.config.mingw || !sym.contains('@')) { - e.exportName = sym.substr(1); - continue; - } - } - if (isArm64EC(ctx.config.machine) && !e.data && !e.constant) { - if (std::optional demangledName = - getArm64ECDemangledFunctionName(sym)) { - e.exportName = saver().save(*demangledName); - continue; - } - } - e.exportName = sym; - } - - if (ctx.config.killAt && ctx.config.machine == I386) { - for (Export &e : ctx.config.exports) { - e.name = killAt(e.name, true); - e.exportName = killAt(e.exportName, false); - e.extName = killAt(e.extName, true); - e.symbolName = killAt(e.symbolName, true); - } - } - - // Uniquefy by name. - DenseMap> map( - ctx.config.exports.size()); - std::vector v; - for (Export &e : ctx.config.exports) { - auto pair = map.insert(std::make_pair(e.exportName, std::make_pair(&e, 0))); - bool inserted = pair.second; - if (inserted) { - pair.first->second.second = v.size(); - v.push_back(e); - continue; - } - Export *existing = pair.first->second.first; - if (e == *existing || e.name != existing->name) - continue; - // If the existing export comes from .OBJ directives, we are allowed to - // overwrite it with /DEF: or /EXPORT without any warning, as MSVC link.exe - // does. - if (existing->source == ExportSource::Directives) { - *existing = e; - v[pair.first->second.second] = e; - continue; - } - if (existing->source == e.source) { - Warn(ctx) << "duplicate " << exportSourceName(existing->source) - << " option: " << e.name; - } else { - Warn(ctx) << "duplicate export: " << e.name << " first seen in " - << exportSourceName(existing->source) << ", now in " - << exportSourceName(e.source); - } - } - ctx.config.exports = std::move(v); - - // Sort by name. - llvm::sort(ctx.config.exports, [](const Export &a, const Export &b) { - return a.exportName < b.exportName; - }); -} - -void LinkerDriver::assignExportOrdinals() { - // Assign unique ordinals if default (= 0). - uint32_t max = 0; - for (Export &e : ctx.config.exports) - max = std::max(max, (uint32_t)e.ordinal); - for (Export &e : ctx.config.exports) - if (e.ordinal == 0) - e.ordinal = ++max; - if (max > std::numeric_limits::max()) - Fatal(ctx) << "too many exported symbols (got " << max << ", max " - << Twine(std::numeric_limits::max()) << ")"; -} - // Parses a string in the form of "key=value" and check // if value matches previous values for the same key. void LinkerDriver::checkFailIfMismatch(StringRef arg, InputFile *source) { diff --git a/lld/COFF/MapFile.cpp b/lld/COFF/MapFile.cpp index af87587d143d5..eb98bb484f9f4 100644 --- a/lld/COFF/MapFile.cpp +++ b/lld/COFF/MapFile.cpp @@ -326,7 +326,7 @@ void lld::coff::writeMapFile(COFFLinkerContext &ctx) { os << " Exports\n"; os << "\n"; os << " ordinal name\n\n"; - for (Export &e : ctx.config.exports) { + for (Export &e : ctx.symtab.exports) { os << format(" %7d", e.ordinal) << " " << e.name << "\n"; if (!e.extName.empty() && e.extName != e.name) os << " exported name: " << e.extName << "\n"; diff --git a/lld/COFF/SymbolTable.cpp b/lld/COFF/SymbolTable.cpp index bf965e8a2332d..ecccc7d6ed70c 100644 --- a/lld/COFF/SymbolTable.cpp +++ b/lld/COFF/SymbolTable.cpp @@ -1118,6 +1118,141 @@ void SymbolTable::addUndefinedGlob(StringRef arg) { addGCRoot(sym->getName()); } +// Convert stdcall/fastcall style symbols into unsuffixed symbols, +// with or without a leading underscore. (MinGW specific.) +static StringRef killAt(StringRef sym, bool prefix) { + if (sym.empty()) + return sym; + // Strip any trailing stdcall suffix + sym = sym.substr(0, sym.find('@', 1)); + if (!sym.starts_with("@")) { + if (prefix && !sym.starts_with("_")) + return saver().save("_" + sym); + return sym; + } + // For fastcall, remove the leading @ and replace it with an + // underscore, if prefixes are used. + sym = sym.substr(1); + if (prefix) + sym = saver().save("_" + sym); + return sym; +} + +static StringRef exportSourceName(ExportSource s) { + switch (s) { + case ExportSource::Directives: + return "source file (directives)"; + case ExportSource::Export: + return "/export"; + case ExportSource::ModuleDefinition: + return "/def"; + default: + llvm_unreachable("unknown ExportSource"); + } +} + +// Performs error checking on all /export arguments. +// It also sets ordinals. +void SymbolTable::fixupExports() { + llvm::TimeTraceScope timeScope("Fixup exports"); + // Symbol ordinals must be unique. + std::set ords; + for (Export &e : exports) { + if (e.ordinal == 0) + continue; + if (!ords.insert(e.ordinal).second) + Fatal(ctx) << "duplicate export ordinal: " << e.name; + } + + for (Export &e : exports) { + if (!e.exportAs.empty()) { + e.exportName = e.exportAs; + continue; + } + + StringRef sym = + !e.forwardTo.empty() || e.extName.empty() ? e.name : e.extName; + if (machine == I386 && sym.starts_with("_")) { + // In MSVC mode, a fully decorated stdcall function is exported + // as-is with the leading underscore (with type IMPORT_NAME). + // In MinGW mode, a decorated stdcall function gets the underscore + // removed, just like normal cdecl functions. + if (ctx.config.mingw || !sym.contains('@')) { + e.exportName = sym.substr(1); + continue; + } + } + if (isEC() && !e.data && !e.constant) { + if (std::optional demangledName = + getArm64ECDemangledFunctionName(sym)) { + e.exportName = saver().save(*demangledName); + continue; + } + } + e.exportName = sym; + } + + if (ctx.config.killAt && machine == I386) { + for (Export &e : exports) { + e.name = killAt(e.name, true); + e.exportName = killAt(e.exportName, false); + e.extName = killAt(e.extName, true); + e.symbolName = killAt(e.symbolName, true); + } + } + + // Uniquefy by name. + DenseMap> map(exports.size()); + std::vector v; + for (Export &e : exports) { + auto pair = map.insert(std::make_pair(e.exportName, std::make_pair(&e, 0))); + bool inserted = pair.second; + if (inserted) { + pair.first->second.second = v.size(); + v.push_back(e); + continue; + } + Export *existing = pair.first->second.first; + if (e == *existing || e.name != existing->name) + continue; + // If the existing export comes from .OBJ directives, we are allowed to + // overwrite it with /DEF: or /EXPORT without any warning, as MSVC link.exe + // does. + if (existing->source == ExportSource::Directives) { + *existing = e; + v[pair.first->second.second] = e; + continue; + } + if (existing->source == e.source) { + Warn(ctx) << "duplicate " << exportSourceName(existing->source) + << " option: " << e.name; + } else { + Warn(ctx) << "duplicate export: " << e.name << " first seen in " + << exportSourceName(existing->source) << ", now in " + << exportSourceName(e.source); + } + } + exports = std::move(v); + + // Sort by name. + llvm::sort(exports, [](const Export &a, const Export &b) { + return a.exportName < b.exportName; + }); +} + +void SymbolTable::assignExportOrdinals() { + // Assign unique ordinals if default (= 0). + uint32_t max = 0; + for (Export &e : exports) + max = std::max(max, (uint32_t)e.ordinal); + for (Export &e : exports) + if (e.ordinal == 0) + e.ordinal = ++max; + if (max > std::numeric_limits::max()) + Fatal(ctx) << "too many exported symbols (got " << max << ", max " + << Twine(std::numeric_limits::max()) << ")"; +} + Symbol *SymbolTable::addUndefined(StringRef name) { return addUndefined(name, nullptr, false); } diff --git a/lld/COFF/SymbolTable.h b/lld/COFF/SymbolTable.h index 66bca0d63e5ff..e5b02ce5904c4 100644 --- a/lld/COFF/SymbolTable.h +++ b/lld/COFF/SymbolTable.h @@ -150,6 +150,17 @@ class SymbolTable { // A list of EC EXP+ symbols. std::vector expSymbols; + // A list of DLL exports. + std::vector exports; + llvm::DenseSet directivesExports; + bool hadExplicitExports; + + Chunk *edataStart = nullptr; + Chunk *edataEnd = nullptr; + + void fixupExports(); + void assignExportOrdinals(); + // Iterates symbols in non-determinstic hash table order. template void forEachSymbol(T callback) { for (auto &pair : symMap) diff --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp index 90b2c083cbfb9..bef2ced9f2957 100644 --- a/lld/COFF/Writer.cpp +++ b/lld/COFF/Writer.cpp @@ -288,8 +288,6 @@ class Writer { IdataContents idata; Chunk *importTableStart = nullptr; uint64_t importTableSize = 0; - Chunk *edataStart = nullptr; - Chunk *edataEnd = nullptr; Chunk *iatStart = nullptr; uint64_t iatSize = 0; DelayLoadContents delayIdata; @@ -1331,22 +1329,46 @@ void Writer::createExportTable() { if (!edataSec->chunks.empty()) { // Allow using a custom built export table from input object files, instead // of having the linker synthesize the tables. - if (ctx.config.hadExplicitExports) - Warn(ctx) << "literal .edata sections override exports"; - } else if (!ctx.config.exports.empty()) { - std::vector edataChunks; - createEdataChunks(ctx, edataChunks); - for (Chunk *c : edataChunks) - edataSec->addChunk(c); - } - if (!edataSec->chunks.empty()) { - edataStart = edataSec->chunks.front(); - edataEnd = edataSec->chunks.back(); + if (!ctx.hybridSymtab) { + ctx.symtab.edataStart = edataSec->chunks.front(); + ctx.symtab.edataEnd = edataSec->chunks.back(); + } else { + // On hybrid target, split EC and native chunks. + llvm::stable_sort(edataSec->chunks, [=](const Chunk *a, const Chunk *b) { + return (a->getMachine() != ARM64) < (b->getMachine() != ARM64); + }); + + for (auto chunk : edataSec->chunks) { + if (chunk->getMachine() != ARM64) { + ctx.hybridSymtab->edataStart = chunk; + ctx.hybridSymtab->edataEnd = edataSec->chunks.back(); + break; + } + + if (!ctx.symtab.edataStart) + ctx.symtab.edataStart = chunk; + ctx.symtab.edataEnd = chunk; + } + } } - // Warn on exported deleting destructor. - for (auto e : ctx.config.exports) - if (e.sym && e.sym->getName().starts_with("??_G")) - Warn(ctx) << "export of deleting dtor: " << e.sym; + ctx.forEachSymtab([&](SymbolTable &symtab) { + if (symtab.edataStart) { + if (symtab.hadExplicitExports) + Warn(ctx) << "literal .edata sections override exports"; + } else if (!symtab.exports.empty()) { + std::vector edataChunks; + createEdataChunks(symtab, edataChunks); + for (Chunk *c : edataChunks) + edataSec->addChunk(c); + symtab.edataStart = edataChunks.front(); + symtab.edataEnd = edataChunks.back(); + } + + // Warn on exported deleting destructor. + for (auto e : symtab.exports) + if (e.sym && e.sym->getName().starts_with("??_G")) + Warn(ctx) << "export of deleting dtor: " << toString(ctx, *e.sym); + }); } void Writer::removeUnusedSections() { @@ -1819,10 +1841,11 @@ template void Writer::writeHeader() { dataDirOffset64 == buf - buffer->getBufferStart()); auto *dir = reinterpret_cast(buf); buf += sizeof(*dir) * numberOfDataDirectory; - if (edataStart) { - dir[EXPORT_TABLE].RelativeVirtualAddress = edataStart->getRVA(); - dir[EXPORT_TABLE].Size = - edataEnd->getRVA() + edataEnd->getSize() - edataStart->getRVA(); + if (ctx.symtab.edataStart) { + dir[EXPORT_TABLE].RelativeVirtualAddress = ctx.symtab.edataStart->getRVA(); + dir[EXPORT_TABLE].Size = ctx.symtab.edataEnd->getRVA() + + ctx.symtab.edataEnd->getSize() - + ctx.symtab.edataStart->getRVA(); } if (importTableStart) { dir[IMPORT_TABLE].RelativeVirtualAddress = importTableStart->getRVA(); @@ -2061,11 +2084,11 @@ void Writer::createGuardCFTables() { ctx.forEachSymtab([&](SymbolTable &symtab) { if (symtab.entry) maybeAddAddressTakenFunction(addressTakenSyms, symtab.entry); - }); - // Mark exported symbols in executable sections as address-taken. - for (Export &e : config->exports) - maybeAddAddressTakenFunction(addressTakenSyms, e.sym); + // Mark exported symbols in executable sections as address-taken. + for (Export &e : symtab.exports) + maybeAddAddressTakenFunction(addressTakenSyms, e.sym); + }); // For each entry in the .giats table, check if it has a corresponding load // thunk (e.g. because the DLL that defines it will be delay-loaded) and, if @@ -2392,6 +2415,19 @@ void Writer::setECSymbols() { symtab->findUnderscore("__arm64x_native_entrypoint") ->replaceKeepingName(altEntrySym, sizeof(SymbolUnion)); } + + if (symtab->edataStart) + ctx.dynamicRelocs->set( + dataDirOffset64 + EXPORT_TABLE * sizeof(data_directory) + + offsetof(data_directory, Size), + symtab->edataEnd->getRVA() - symtab->edataStart->getRVA() + + symtab->edataEnd->getSize()); + if (hybridPdata.first) + ctx.dynamicRelocs->set( + dataDirOffset64 + EXCEPTION_TABLE * sizeof(data_directory) + + offsetof(data_directory, Size), + hybridPdata.last->getRVA() - hybridPdata.first->getRVA() + + hybridPdata.last->getSize()); } } @@ -2644,6 +2680,32 @@ void Writer::createDynamicRelocs() { Warn(ctx) << "'__chpe_metadata' is missing for ARM64X target"; } + if (ctx.symtab.edataStart != ctx.hybridSymtab->edataStart) { + ctx.dynamicRelocs->add(IMAGE_DVRT_ARM64X_FIXUP_TYPE_VALUE, sizeof(uint32_t), + dataDirOffset64 + + EXPORT_TABLE * sizeof(data_directory) + + offsetof(data_directory, RelativeVirtualAddress), + ctx.hybridSymtab->edataStart); + // The Size value is assigned after addresses are finalized. + ctx.dynamicRelocs->add(IMAGE_DVRT_ARM64X_FIXUP_TYPE_VALUE, sizeof(uint32_t), + dataDirOffset64 + + EXPORT_TABLE * sizeof(data_directory) + + offsetof(data_directory, Size)); + } + + if (pdata.first != hybridPdata.first) { + ctx.dynamicRelocs->add(IMAGE_DVRT_ARM64X_FIXUP_TYPE_VALUE, sizeof(uint32_t), + dataDirOffset64 + + EXCEPTION_TABLE * sizeof(data_directory) + + offsetof(data_directory, RelativeVirtualAddress), + hybridPdata.first); + // The Size value is assigned after addresses are finalized. + ctx.dynamicRelocs->add(IMAGE_DVRT_ARM64X_FIXUP_TYPE_VALUE, sizeof(uint32_t), + dataDirOffset64 + + EXCEPTION_TABLE * sizeof(data_directory) + + offsetof(data_directory, Size)); + } + // Set the hybrid load config to the EC load config. ctx.dynamicRelocs->add(IMAGE_DVRT_ARM64X_FIXUP_TYPE_VALUE, sizeof(uint32_t), dataDirOffset64 + diff --git a/lld/ELF/Arch/AArch64.cpp b/lld/ELF/Arch/AArch64.cpp index b63551d0f682e..9538dd4a70bae 100644 --- a/lld/ELF/Arch/AArch64.cpp +++ b/lld/ELF/Arch/AArch64.cpp @@ -157,9 +157,14 @@ RelExpr AArch64::getRelExpr(RelType type, const Symbol &s, return RE_AARCH64_AUTH; case R_AARCH64_TLSDESC_ADR_PAGE21: return RE_AARCH64_TLSDESC_PAGE; + case R_AARCH64_AUTH_TLSDESC_ADR_PAGE21: + return RE_AARCH64_AUTH_TLSDESC_PAGE; case R_AARCH64_TLSDESC_LD64_LO12: case R_AARCH64_TLSDESC_ADD_LO12: return R_TLSDESC; + case R_AARCH64_AUTH_TLSDESC_LD64_LO12: + case R_AARCH64_AUTH_TLSDESC_ADD_LO12: + return RE_AARCH64_AUTH_TLSDESC; case R_AARCH64_TLSDESC_CALL: return R_TLSDESC_CALL; case R_AARCH64_TLSLE_ADD_TPREL_HI12: @@ -545,6 +550,7 @@ void AArch64::relocate(uint8_t *loc, const Relocation &rel, case R_AARCH64_ADR_PREL_PG_HI21: case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: case R_AARCH64_TLSDESC_ADR_PAGE21: + case R_AARCH64_AUTH_TLSDESC_ADR_PAGE21: checkInt(ctx, loc, val, 33, rel); [[fallthrough]]; case R_AARCH64_ADR_PREL_PG_HI21_NC: @@ -597,6 +603,7 @@ void AArch64::relocate(uint8_t *loc, const Relocation &rel, case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: case R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC: case R_AARCH64_TLSDESC_LD64_LO12: + case R_AARCH64_AUTH_TLSDESC_LD64_LO12: checkAlignment(ctx, loc, val, 8, rel); write32Imm12(loc, getBits(val, 3, 11)); break; @@ -671,6 +678,7 @@ void AArch64::relocate(uint8_t *loc, const Relocation &rel, break; case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC: case R_AARCH64_TLSDESC_ADD_LO12: + case R_AARCH64_AUTH_TLSDESC_ADD_LO12: write32Imm12(loc, val); break; case R_AARCH64_TLSDESC: diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp index efa7ba3e7cb06..42ef530b79d89 100644 --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -966,12 +966,14 @@ uint64_t InputSectionBase::getRelocTargetVA(Ctx &ctx, const Relocation &r, case R_SIZE: return r.sym->getSize() + a; case R_TLSDESC: + case RE_AARCH64_AUTH_TLSDESC: return ctx.in.got->getTlsDescAddr(*r.sym) + a; case R_TLSDESC_PC: return ctx.in.got->getTlsDescAddr(*r.sym) + a - p; case R_TLSDESC_GOTPLT: return ctx.in.got->getTlsDescAddr(*r.sym) + a - ctx.in.gotPlt->getVA(); case RE_AARCH64_TLSDESC_PAGE: + case RE_AARCH64_AUTH_TLSDESC_PAGE: return getAArch64Page(ctx.in.got->getTlsDescAddr(*r.sym) + a) - getAArch64Page(p); case RE_LOONGARCH_TLSDESC_PAGE_PC: diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp index 77b90172bc1c2..76b151b93d517 100644 --- a/lld/ELF/Relocations.cpp +++ b/lld/ELF/Relocations.cpp @@ -1292,6 +1292,27 @@ static unsigned handleMipsTlsRelocation(Ctx &ctx, RelType type, Symbol &sym, return 0; } +static unsigned handleAArch64PAuthTlsRelocation(InputSectionBase *sec, + RelExpr expr, RelType type, + uint64_t offset, Symbol &sym, + int64_t addend) { + // Do not optimize signed TLSDESC to LE/IE (as described in pauthabielf64). + // https://github.com/ARM-software/abi-aa/blob/main/pauthabielf64/pauthabielf64.rst#general-restrictions + // > PAUTHELF64 only supports the descriptor based TLS (TLSDESC). + if (oneof(expr)) { + sym.setFlags(NEEDS_TLSDESC | NEEDS_TLSDESC_AUTH); + sec->addReloc({expr, type, offset, addend, &sym}); + return 1; + } + + // TLSDESC_CALL hint relocation should not be emitted by compiler with signed + // TLSDESC enabled. + if (expr == R_TLSDESC_CALL) + sym.setFlags(NEEDS_TLSDESC_NONAUTH); + + return 0; +} + // Notes about General Dynamic and Local Dynamic TLS models below. They may // require the generation of a pair of GOT entries that have associated dynamic // relocations. The pair of GOT entries created are of the form GOT[e0] Module @@ -1302,6 +1323,13 @@ static unsigned handleMipsTlsRelocation(Ctx &ctx, RelType type, Symbol &sym, unsigned RelocationScanner::handleTlsRelocation(RelExpr expr, RelType type, uint64_t offset, Symbol &sym, int64_t addend) { + bool isAArch64 = ctx.arg.emachine == EM_AARCH64; + + if (isAArch64) + if (unsigned processed = handleAArch64PAuthTlsRelocation( + sec, expr, type, offset, sym, addend)) + return processed; + if (expr == R_TPREL || expr == R_TPREL_NEG) { if (ctx.arg.shared) { auto diag = Err(ctx); @@ -1336,7 +1364,9 @@ unsigned RelocationScanner::handleTlsRelocation(RelExpr expr, RelType type, // R_RISCV_TLSDESC_{LOAD_LO12,ADD_LO12_I,CALL} reference a label. Do not // set NEEDS_TLSDESC on the label. if (expr != R_TLSDESC_CALL) { - if (!isRISCV || type == R_RISCV_TLSDESC_HI20) + if (isAArch64) + sym.setFlags(NEEDS_TLSDESC | NEEDS_TLSDESC_NONAUTH); + else if (!isRISCV || type == R_RISCV_TLSDESC_HI20) sym.setFlags(NEEDS_TLSDESC); sec->addReloc({expr, type, offset, addend, &sym}); } @@ -1847,10 +1877,21 @@ void elf::postScanRelocations(Ctx &ctx) { GotSection *got = ctx.in.got.get(); if (flags & NEEDS_TLSDESC) { + if ((flags & NEEDS_TLSDESC_AUTH) && (flags & NEEDS_TLSDESC_NONAUTH)) { + Err(ctx) + << "both AUTH and non-AUTH TLSDESC entries for '" << sym.getName() + << "' requested, but only one type of TLSDESC entry per symbol is " + "supported"; + return; + } got->addTlsDescEntry(sym); + RelType tlsDescRel = ctx.target->tlsDescRel; + if (flags & NEEDS_TLSDESC_AUTH) { + got->addTlsDescAuthEntry(); + tlsDescRel = ELF::R_AARCH64_AUTH_TLSDESC; + } ctx.mainPart->relaDyn->addAddendOnlyRelocIfNonPreemptible( - ctx.target->tlsDescRel, *got, got->getTlsDescOffset(sym), sym, - ctx.target->tlsDescRel); + tlsDescRel, *got, got->getTlsDescOffset(sym), sym, tlsDescRel); } if (flags & NEEDS_TLSGD) { got->addDynTlsEntry(sym); diff --git a/lld/ELF/Relocations.h b/lld/ELF/Relocations.h index fde25a230b72e..d2a77bc953109 100644 --- a/lld/ELF/Relocations.h +++ b/lld/ELF/Relocations.h @@ -99,6 +99,8 @@ enum RelExpr { RE_AARCH64_PAGE_PC, RE_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC, RE_AARCH64_TLSDESC_PAGE, + RE_AARCH64_AUTH_TLSDESC_PAGE, + RE_AARCH64_AUTH_TLSDESC, RE_AARCH64_AUTH, RE_ARM_PCA, RE_ARM_SBREL, diff --git a/lld/ELF/ScriptParser.cpp b/lld/ELF/ScriptParser.cpp index f53515cc3f3c0..06a22613ee93a 100644 --- a/lld/ELF/ScriptParser.cpp +++ b/lld/ELF/ScriptParser.cpp @@ -1489,6 +1489,8 @@ Expr ScriptParser::readPrimary() { Expr e = readPrimary(); return [=] { return -e().getValue(); }; } + if (consume("+")) + return readPrimary(); StringRef tok = next(); std::string location = getCurrentLocation(); diff --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h index a59faf1037cb2..48df6f60db864 100644 --- a/lld/ELF/Symbols.h +++ b/lld/ELF/Symbols.h @@ -53,6 +53,8 @@ enum { NEEDS_TLSIE = 1 << 8, NEEDS_GOT_AUTH = 1 << 9, NEEDS_GOT_NONAUTH = 1 << 10, + NEEDS_TLSDESC_AUTH = 1 << 11, + NEEDS_TLSDESC_NONAUTH = 1 << 12, }; // The base class for real symbol classes. diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp index 10cbfe19b3b0a..eb07d82fc9601 100644 --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -681,6 +681,11 @@ bool GotSection::addTlsDescEntry(const Symbol &sym) { return true; } +void GotSection::addTlsDescAuthEntry() { + authEntries.push_back({(numEntries - 2) * ctx.arg.wordsize, true}); + authEntries.push_back({(numEntries - 1) * ctx.arg.wordsize, false}); +} + bool GotSection::addDynTlsEntry(const Symbol &sym) { assert(sym.auxIdx == ctx.symAux.size() - 1); ctx.symAux.back().tlsGdIdx = numEntries; diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h index 9fcee3b481af0..c977562f0b174 100644 --- a/lld/ELF/SyntheticSections.h +++ b/lld/ELF/SyntheticSections.h @@ -114,6 +114,7 @@ class GotSection final : public SyntheticSection { void addEntry(const Symbol &sym); void addAuthEntry(const Symbol &sym); bool addTlsDescEntry(const Symbol &sym); + void addTlsDescAuthEntry(); bool addDynTlsEntry(const Symbol &sym); bool addTlsIndex(); uint32_t getTlsDescOffset(const Symbol &sym) const; diff --git a/lld/MachO/Arch/ARM64.cpp b/lld/MachO/Arch/ARM64.cpp index bf458e392be8f..2f3ca13b832a1 100644 --- a/lld/MachO/Arch/ARM64.cpp +++ b/lld/MachO/Arch/ARM64.cpp @@ -205,7 +205,7 @@ InputSection *ARM64::getThunkBranchTarget(InputSection *thunk) const { assert(isa(reloc.referent) && "ARM64 thunk reloc is expected to point to an InputSection"); - return reloc.referent.dyn_cast(); + return cast(reloc.referent); } uint32_t ARM64::getICFSafeThunkSize() const { return sizeof(icfSafeThunkCode); } diff --git a/lld/MachO/SyntheticSections.cpp b/lld/MachO/SyntheticSections.cpp index 417b7cf93efa7..97164e5992b8c 100644 --- a/lld/MachO/SyntheticSections.cpp +++ b/lld/MachO/SyntheticSections.cpp @@ -1958,7 +1958,7 @@ void InitOffsetsSection::writeTo(uint8_t *buf) const { // FIXME: Add function specified by -init when that argument is implemented. for (ConcatInputSection *isec : sections) { for (const Reloc &rel : isec->relocs) { - const Symbol *referent = rel.referent.dyn_cast(); + const Symbol *referent = cast(rel.referent); assert(referent && "section relocation should have been rejected"); uint64_t offset = referent->getVA() - in.header->addr; // FIXME: Can we handle this gracefully? diff --git a/lld/test/COFF/arm64x-export.test b/lld/test/COFF/arm64x-export.test new file mode 100644 index 0000000000000..526be63397358 --- /dev/null +++ b/lld/test/COFF/arm64x-export.test @@ -0,0 +1,229 @@ +REQUIRES: aarch64, x86 +RUN: split-file %s %t.dir && cd %t.dir + +RUN: llvm-mc -filetype=obj -triple=arm64ec-windows arm64ec-func.s -o arm64ec-func.obj +RUN: llvm-mc -filetype=obj -triple=aarch64-windows arm64-func.s -o arm64-func.obj +RUN: llvm-mc -filetype=obj -triple=arm64ec-windows func-drectve.s -o arm64ec-drectve.obj +RUN: llvm-mc -filetype=obj -triple=aarch64-windows func-drectve.s -o arm64-drectve.obj +RUN: llvm-mc -filetype=obj -triple=aarch64-windows edata.s -o arm64-edata.obj +RUN: llvm-mc -filetype=obj -triple=arm64ec-windows edata.s -o arm64ec-edata.obj +RUN: llvm-mc -filetype=obj -triple=arm64ec-windows %S/Inputs/loadconfig-arm64ec.s -o loadconfig-arm64ec.obj +RUN: llvm-mc -filetype=obj -triple=aarch64-windows %S/Inputs/loadconfig-arm64.s -o loadconfig-arm64.obj + + +# A command-line export applies only to EC exports. + +RUN: lld-link -machine:arm64x -dll -out:out-cmd.dll arm64ec-func.obj arm64-func.obj \ +RUN: loadconfig-arm64.obj loadconfig-arm64ec.obj -noentry -export:func + +RUN: llvm-objdump -d out-cmd.dll | FileCheck --check-prefix=DISASM-EC %s +DISASM-EC: Disassembly of section .text: +DISASM-EC-EMPTY: +DISASM-EC-NEXT: 0000000180001000 <.text>: +DISASM-EC-NEXT: 180001000: 52800040 mov w0, #0x2 // =2 +DISASM-EC-NEXT: 180001004: d65f03c0 ret +DISASM-EC-EMPTY: +DISASM-EC-NEXT: Disassembly of section .hexpthk: +DISASM-EC-EMPTY: +DISASM-EC-NEXT: 0000000180002000 <.hexpthk>: +DISASM-EC-NEXT: 180002000: 48 8b c4 movq %rsp, %rax +DISASM-EC-NEXT: 180002003: 48 89 58 20 movq %rbx, 0x20(%rax) +DISASM-EC-NEXT: 180002007: 55 pushq %rbp +DISASM-EC-NEXT: 180002008: 5d popq %rbp +DISASM-EC-NEXT: 180002009: e9 f2 ef ff ff jmp 0x180001000 <.text> +DISASM-EC-NEXT: 18000200e: cc int3 +DISASM-EC-NEXT: 18000200f: cc int3 + +RUN: llvm-readobj --headers --coff-exports out-cmd.dll | FileCheck --check-prefix=EXPORTS-EC %s +EXPORTS-EC: ExportTableRVA: 0x0 +EXPORTS-EC-NEXT: ExportTableSize: 0x0 +EXPORTS-EC-NOT: Name: func +EXPORTS-EC: HybridObject { +EXPORTS-EC: ExportTableRVA: 0x3{{.*}} +EXPORTS-EC-NEXT: ExportTableSize: 0x4{{.*}} +EXPORTS-EC: Export { +EXPORTS-EC-NEXT: Ordinal: 1 +EXPORTS-EC-NEXT: Name: func +EXPORTS-EC-NEXT: RVA: 0x2000 +EXPORTS-EC-NEXT: } +EXPORTS-EC-NEXT: } + +# Export using the EC .drectve section. + +RUN: lld-link -machine:arm64x -dll -out:out-drectve-ec.dll arm64ec-func.obj arm64-func.obj \ +RUN: loadconfig-arm64.obj loadconfig-arm64ec.obj arm64ec-drectve.obj -noentry +RUN: llvm-objdump -d out-drectve-ec.dll | FileCheck --check-prefix=DISASM-EC %s +RUN: llvm-readobj --headers --coff-exports out-drectve-ec.dll | FileCheck --check-prefix=EXPORTS-EC %s + +# Export using the EC .edata section. + +RUN: lld-link -machine:arm64x -dll -out:out-edata-ec.dll arm64ec-func.obj arm64-func.obj \ +RUN: loadconfig-arm64.obj loadconfig-arm64ec.obj arm64ec-edata.obj -noentry + +RUN: llvm-objdump -d out-edata-ec.dll | FileCheck --check-prefix=DISASM-EDATA-EC %s +DISASM-EDATA-EC: 0000000180001000 <.text>: +DISASM-EDATA-EC-NEXT: 180001000: 52800040 mov w0, #0x2 // =2 +DISASM-EDATA-EC-NEXT: 180001004: d65f03c0 ret + +RUN: llvm-readobj --headers --coff-exports out-edata-ec.dll | FileCheck --check-prefix=EXPORTS-EDATA-EC %s +EXPORTS-EDATA-EC: ExportTableRVA: 0x0 +EXPORTS-EDATA-EC-NEXT: ExportTableSize: 0x0 +EXPORTS-EDATA-EC-NOT: Name: func +EXPORTS-EDATA-EC: HybridObject { +EXPORTS-EDATA-EC: ExportTableRVA: 0x2{{.*}} +EXPORTS-EDATA-EC-NEXT: ExportTableSize: 0x4{{.*}} +EXPORTS-EDATA-EC: Export { +EXPORTS-EDATA-EC-NEXT: Ordinal: 1 +EXPORTS-EDATA-EC-NEXT: Name: func +EXPORTS-EDATA-EC-NEXT: RVA: 0x1000 +EXPORTS-EDATA-EC-NEXT: } +EXPORTS-EDATA-EC-NEXT: } + +# Export using the native .drectve section. + +RUN: lld-link -machine:arm64x -dll -out:out-drectve-native.dll arm64ec-func.obj arm64-func.obj \ +RUN: loadconfig-arm64.obj loadconfig-arm64ec.obj arm64-drectve.obj -noentry + +RUN: llvm-objdump -d out-drectve-native.dll | FileCheck --check-prefix=DISASM-NATIVE %s +DISASM-NATIVE: Disassembly of section .text: +DISASM-NATIVE-EMPTY: +DISASM-NATIVE-NEXT: 0000000180001000 : +DISASM-NATIVE-NEXT: 180001000: 52800020 mov w0, #0x1 // =1 +DISASM-NATIVE-NEXT: 180001004: d65f03c0 ret + +RUN: llvm-readobj --headers --coff-exports out-drectve-native.dll | FileCheck --check-prefix=EXPORTS-NATIVE %s +EXPORTS-NATIVE: ExportTableRVA: 0x2{{.*}} +EXPORTS-NATIVE-NEXT: ExportTableSize: 0x4{{.*}} +EXPORTS-NATIVE: Export { +EXPORTS-NATIVE-NEXT: Ordinal: 1 +EXPORTS-NATIVE-NEXT: Name: func +EXPORTS-NATIVE-NEXT: RVA: 0x1000 +EXPORTS-NATIVE-NEXT: } +EXPORTS-NATIVE: HybridObject { +EXPORTS-NATIVE: ExportTableRVA: 0x0 +EXPORTS-NATIVE-NEXT: ExportTableSize: 0x0 +EXPORTS-NATIVE-NOT: Name: func + +# Export using the native .edata section. + +RUN: lld-link -machine:arm64x -dll -out:out-edata.dll arm64ec-func.obj arm64-func.obj \ +RUN: loadconfig-arm64.obj loadconfig-arm64ec.obj arm64-edata.obj -noentry +RUN: llvm-objdump -d out-edata.dll | FileCheck --check-prefix=DISASM-NATIVE %s +RUN: llvm-readobj --headers --coff-exports out-edata.dll | FileCheck --check-prefix=EXPORTS-NATIVE %s + +# Export using both the native and EC .drectve sections. + +RUN: lld-link -machine:arm64x -dll -out:out-both.dll arm64ec-func.obj arm64-func.obj \ +RUN: loadconfig-arm64.obj loadconfig-arm64ec.obj arm64-drectve.obj arm64ec-drectve.obj -noentry + +RUN: llvm-objdump -d out-both.dll | FileCheck --check-prefix=DISASM-BOTH %s +DISASM-BOTH: Disassembly of section .text: +DISASM-BOTH-EMPTY: +DISASM-BOTH-NEXT: 0000000180001000 : +DISASM-BOTH-NEXT: 180001000: 52800020 mov w0, #0x1 // =1 +DISASM-BOTH-NEXT: 180001004: d65f03c0 ret +DISASM-BOTH-NEXT: ... +DISASM-BOTH-NEXT: 180002000: 52800040 mov w0, #0x2 // =2 +DISASM-BOTH-NEXT: 180002004: d65f03c0 ret +DISASM-BOTH-EMPTY: +DISASM-BOTH-NEXT: Disassembly of section .hexpthk: +DISASM-BOTH-EMPTY: +DISASM-BOTH-NEXT: 0000000180003000 <.hexpthk>: +DISASM-BOTH-NEXT: 180003000: 48 8b c4 movq %rsp, %rax +DISASM-BOTH-NEXT: 180003003: 48 89 58 20 movq %rbx, 0x20(%rax) +DISASM-BOTH-NEXT: 180003007: 55 pushq %rbp +DISASM-BOTH-NEXT: 180003008: 5d popq %rbp +DISASM-BOTH-NEXT: 180003009: e9 f2 ef ff ff jmp 0x180002000 +DISASM-BOTH-NEXT: 18000300e: cc int3 +DISASM-BOTH-NEXT: 18000300f: cc int3 + +RUN: llvm-readobj --headers --coff-exports out-both.dll | FileCheck --check-prefix=EXPORTS-BOTH %s +EXPORTS-BOTH: ExportTableRVA: 0x4{{.*}} +EXPORTS-BOTH-NEXT: ExportTableSize: 0x4{{.*}} +EXPORTS-BOTH: Export { +EXPORTS-BOTH-NEXT: Ordinal: 1 +EXPORTS-BOTH-NEXT: Name: func +EXPORTS-BOTH-NEXT: RVA: 0x1000 +EXPORTS-BOTH-NEXT: } +EXPORTS-BOTH: HybridObject { +EXPORTS-BOTH: ExportTableRVA: 0x4{{.*}} +EXPORTS-BOTH-NEXT: ExportTableSize: 0x4{{.*}} +EXPORTS-BOTH: Export { +EXPORTS-BOTH-NEXT: Ordinal: 1 +EXPORTS-BOTH-NEXT: Name: func +EXPORTS-BOTH-NEXT: RVA: 0x3000 +EXPORTS-BOTH-NEXT: } +EXPORTS-BOTH-NEXT: } + +# Export using both the native and EC .edata sections. + +RUN: lld-link -machine:arm64x -dll -out:out-edata-both.dll arm64ec-func.obj arm64-func.obj \ +RUN: loadconfig-arm64.obj loadconfig-arm64ec.obj arm64-edata.obj arm64ec-edata.obj -noentry +RUN: llvm-readobj --headers --coff-exports out-edata-both.dll | FileCheck --check-prefix=EXPORTS-EDATA-BOTH %s +EXPORTS-EDATA-BOTH: ExportTableRVA: 0x3{{.*}} +EXPORTS-EDATA-BOTH-NEXT: ExportTableSize: 0x4{{.*}} +EXPORTS-EDATA-BOTH: Export { +EXPORTS-EDATA-BOTH-NEXT: Ordinal: 1 +EXPORTS-EDATA-BOTH-NEXT: Name: func +EXPORTS-EDATA-BOTH-NEXT: RVA: 0x1000 +EXPORTS-EDATA-BOTH-NEXT: } +EXPORTS-EDATA-BOTH: HybridObject { +EXPORTS-EDATA-BOTH: ExportTableRVA: 0x3{{.*}} +EXPORTS-EDATA-BOTH-NEXT: ExportTableSize: 0x4{{.*}} +EXPORTS-EDATA-BOTH: Export { +EXPORTS-EDATA-BOTH-NEXT: Ordinal: 1 +EXPORTS-EDATA-BOTH-NEXT: Name: func +EXPORTS-EDATA-BOTH-NEXT: RVA: 0x2000 +EXPORTS-EDATA-BOTH-NEXT: } +EXPORTS-EDATA-BOTH-NEXT: } + +#--- arm64-func.s + .section .text,"xr",discard,func + .globl func + .p2align 2 +func: + mov w0, #1 + ret + +#--- arm64ec-func.s + .section .text,"xr",discard,func + .globl func + .p2align 2 +func: + mov w0, #2 + ret + +#--- func-drectve.s +.section .drectve + .ascii "-export:func" + +#--- edata.s + .section .edata, "dr" + .align 4 +exports: + .long 0 // ExportFlags + .long 0 // TimeDateStamp + .long 0 // MajorVersion + MinorVersion + .rva name // NameRVA + .long 1 // OrdinalBase + .long 1 // AddressTableEntries + .long 1 // NumberOfNamePointers + .rva functions // ExportAddressTableRVA + .rva names // NamePointerRVA + .rva nameordinals // OrdinalTableRVA + +names: + .rva funcname_func + +nameordinals: + .short 0 + +functions: + .rva func + .long 0 + +funcname_func: + .asciz "func" + +name: + .asciz "out-edata.dll" diff --git a/lld/test/COFF/pdata-arm64ec.test b/lld/test/COFF/pdata-arm64ec.test index 7f20c460dc109..fbec797525f7f 100644 --- a/lld/test/COFF/pdata-arm64ec.test +++ b/lld/test/COFF/pdata-arm64ec.test @@ -6,6 +6,7 @@ Test handlign of hybrid .pdata section on ARM64EC target. RUN: llvm-mc -filetype=obj -triple=arm64-windows arm64-func-sym.s -o arm64-func-sym.obj RUN: llvm-mc -filetype=obj -triple=arm64ec-windows arm64ec-func-sym.s -o arm64ec-func-sym.obj RUN: llvm-mc -filetype=obj -triple=x86_64-windows x86_64-func-sym.s -o x86_64-func-sym.obj +RUN: llvm-mc -filetype=obj -triple=aarch64-windows %S/Inputs/loadconfig-arm64.s -o loadconfig-arm64.obj RUN: llvm-mc -filetype=obj -triple=arm64ec-windows %p/Inputs/loadconfig-arm64ec.s -o loadconfig-arm64ec.obj Only arm64ec code: @@ -55,11 +56,21 @@ DATA3: 180005000 00100000 11000001 00200000 0e200000 Mixed arm64x code: RUN: lld-link -out:test4.dll -machine:arm64x arm64-func-sym.obj arm64ec-func-sym.obj \ -RUN: x86_64-func-sym.obj loadconfig-arm64ec.obj -dll -noentry +RUN: x86_64-func-sym.obj loadconfig-arm64.obj loadconfig-arm64ec.obj -dll -noentry RUN: llvm-readobj --headers test4.dll | FileCheck -check-prefix=DIR3 %s -DIR3: ExceptionTableRVA: 0x6000 -DIR3-NEXT: ExceptionTableSize: 0x10 +DIR3: ImageOptionalHeader { +DIR3: DataDirectory { +DIR3: ExceptionTableRVA: 0x6000 +DIR3-NEXT: ExceptionTableSize: 0x10 +DIR3: } +DIR3: } +DIR3: HybridObject { +DIR3: ImageOptionalHeader { +DIR3: ExceptionTableRVA: 0x6010 +DIR3-NEXT: ExceptionTableSize: 0xC +DIR3: } +DIR3: } RUN: llvm-objdump -s --section=.pdata test4.dll | FileCheck -check-prefix=DATA4 %s DATA4: 180006000 00100000 11000001 00200000 11000001 ......... ...... @@ -74,12 +85,12 @@ RUN: llvm-readobj --headers test5.dll | FileCheck -check-prefix=DIR2 %s RUN: llvm-objdump -s --section=.pdata test5.dll | FileCheck -check-prefix=DATA3 %s RUN: lld-link -out:test6.dll -machine:arm64x arm64ec-func-sym.obj x86_64-func-sym.obj \ -RUN: arm64-func-sym.obj loadconfig-arm64ec.obj -dll -noentry +RUN: arm64-func-sym.obj loadconfig-arm64.obj loadconfig-arm64ec.obj -dll -noentry RUN: llvm-readobj --headers test6.dll | FileCheck -check-prefix=DIR3 %s RUN: llvm-objdump -s --section=.pdata test6.dll | FileCheck -check-prefix=DATA4 %s RUN: lld-link -out:test7.dll -machine:arm64x x86_64-func-sym.obj arm64ec-func-sym.obj \ -RUN: arm64-func-sym.obj loadconfig-arm64ec.obj -dll -noentry +RUN: arm64-func-sym.obj loadconfig-arm64.obj loadconfig-arm64ec.obj -dll -noentry RUN: llvm-readobj --headers test7.dll | FileCheck -check-prefix=DIR3 %s RUN: llvm-objdump -s --section=.pdata test7.dll | FileCheck -check-prefix=DATA4 %s diff --git a/lld/test/ELF/aarch64-tlsdesc-pauth.s b/lld/test/ELF/aarch64-tlsdesc-pauth.s new file mode 100644 index 0000000000000..bf0ae4a87f322 --- /dev/null +++ b/lld/test/ELF/aarch64-tlsdesc-pauth.s @@ -0,0 +1,134 @@ +// REQUIRES: aarch64 +// RUN: rm -rf %t && split-file %s %t && cd %t + +//--- a.s +.section .tbss,"awT",@nobits +.global a +a: +.xword 0 + +//--- ok.s +// RUN: llvm-mc -filetype=obj -triple=aarch64-pc-linux -mattr=+pauth ok.s -o ok.o +// RUN: ld.lld -shared ok.o -o ok.so +// RUN: llvm-objdump --no-print-imm-hex -d --no-show-raw-insn ok.so | \ +// RUN: FileCheck -DP=20 -DA=896 -DB=912 -DC=928 %s +// RUN: llvm-readobj -r -x .got ok.so | FileCheck --check-prefix=REL \ +// RUN: -DP1=20 -DA1=380 -DB1=390 -DC1=3A0 -DP2=020 -DA2=380 -DB2=390 -DC2=3a0 %s + +// RUN: llvm-mc -filetype=obj -triple=aarch64-pc-linux -mattr=+pauth a.s -o a.so.o +// RUN: ld.lld -shared a.so.o -soname=so -o a.so +// RUN: ld.lld ok.o a.so -o ok +// RUN: llvm-objdump --no-print-imm-hex -d --no-show-raw-insn ok | \ +// RUN: FileCheck -DP=220 -DA=936 -DB=952 -DC=968 %s +// RUN: llvm-readobj -r -x .got ok | FileCheck --check-prefix=REL \ +// RUN: -DP1=220 -DA1=3A8 -DB1=3B8 -DC1=3C8 -DP2=220 -DA2=3a8 -DB2=3b8 -DC2=3c8 %s + + .text + adrp x0, :tlsdesc_auth:a + ldr x16, [x0, :tlsdesc_auth_lo12:a] + add x0, x0, :tlsdesc_auth_lo12:a + blraa x16, x0 + +// CHECK: adrp x0, 0x[[P]]000 +// CHECK-NEXT: ldr x16, [x0, #[[A]]] +// CHECK-NEXT: add x0, x0, #[[A]] +// CHECK-NEXT: blraa x16, x0 + +/// Create relocation against local TLS symbols where linker should +/// create target specific dynamic TLSDESC relocation where addend is +/// the symbol VMA in tls block. + + adrp x0, :tlsdesc_auth:local1 + ldr x16, [x0, :tlsdesc_auth_lo12:local1] + add x0, x0, :tlsdesc_auth_lo12:local1 + blraa x16, x0 + +// CHECK: adrp x0, 0x[[P]]000 +// CHECK-NEXT: ldr x16, [x0, #[[B]]] +// CHECK-NEXT: add x0, x0, #[[B]] +// CHECK-NEXT: blraa x16, x0 + + adrp x0, :tlsdesc_auth:local2 + ldr x16, [x0, :tlsdesc_auth_lo12:local2] + add x0, x0, :tlsdesc_auth_lo12:local2 + blraa x16, x0 + +// CHECK: adrp x0, 0x[[P]]000 +// CHECK-NEXT: ldr x16, [x0, #[[C]]] +// CHECK-NEXT: add x0, x0, #[[C]] +// CHECK-NEXT: blraa x16, x0 + + .section .tbss,"awT",@nobits + .type local1,@object + .p2align 2 +local1: + .word 0 + .size local1, 4 + + .type local2,@object + .p2align 3 +local2: + .xword 0 + .size local2, 8 + + +// R_AARCH64_AUTH_TLSDESC - 0x0 -> start of tls block +// R_AARCH64_AUTH_TLSDESC - 0x8 -> align (sizeof (local1), 8) + +// REL: Relocations [ +// REL-NEXT: Section (5) .rela.dyn { +// REL-NEXT: 0x[[P1]][[B1]] R_AARCH64_AUTH_TLSDESC - 0x0 +// REL-NEXT: 0x[[P1]][[C1]] R_AARCH64_AUTH_TLSDESC - 0x8 +// REL-NEXT: 0x[[P1]][[A1]] R_AARCH64_AUTH_TLSDESC a 0x0 +// REL-NEXT: } +// REL-NEXT: ] + +// REL: Hex dump of section '.got': +// REL-NEXT: 0x00[[P2]][[A2]] 00000000 00000080 00000000 000000a0 +// REL-NEXT: 0x00[[P2]][[B2]] 00000000 00000080 00000000 000000a0 +// REL-NEXT: 0x00[[P2]][[C2]] 00000000 00000080 00000000 000000a0 +/// ^^ +/// 0b10000000 bit 63 address diversity = true, bits 61..60 key = IA +/// ^^ +/// 0b10100000 bit 63 address diversity = true, bits 61..60 key = DA + +//--- err1.s +// RUN: llvm-mc -filetype=obj -triple=aarch64-pc-linux -mattr=+pauth err1.s -o err1.o +// RUN: not ld.lld -shared err1.o 2>&1 | FileCheck --check-prefix=ERR1 --implicit-check-not=error: %s +// ERR1: error: both AUTH and non-AUTH TLSDESC entries for 'a' requested, but only one type of TLSDESC entry per symbol is supported + .text + adrp x0, :tlsdesc_auth:a + ldr x16, [x0, :tlsdesc_auth_lo12:a] + add x0, x0, :tlsdesc_auth_lo12:a + blraa x16, x0 + + adrp x0, :tlsdesc:a + ldr x1, [x0, :tlsdesc_lo12:a] + add x0, x0, :tlsdesc_lo12:a + blr x1 + +//--- err2.s +// RUN: llvm-mc -filetype=obj -triple=aarch64-pc-linux -mattr=+pauth err2.s -o err2.o +// RUN: not ld.lld -shared err2.o 2>&1 | FileCheck --check-prefix=ERR2 --implicit-check-not=error: %s +// ERR2: error: both AUTH and non-AUTH TLSDESC entries for 'a' requested, but only one type of TLSDESC entry per symbol is supported + .text + adrp x0, :tlsdesc:a + ldr x1, [x0, :tlsdesc_lo12:a] + add x0, x0, :tlsdesc_lo12:a + blr x1 + + adrp x0, :tlsdesc_auth:a + ldr x16, [x0, :tlsdesc_auth_lo12:a] + add x0, x0, :tlsdesc_auth_lo12:a + blraa x16, x0 + +//--- err3.s +// RUN: llvm-mc -filetype=obj -triple=aarch64-pc-linux -mattr=+pauth err3.s -o err3.o +// RUN: not ld.lld -shared err3.o 2>&1 | FileCheck --check-prefix=ERR3 --implicit-check-not=error: %s +// ERR3: error: both AUTH and non-AUTH TLSDESC entries for 'a' requested, but only one type of TLSDESC entry per symbol is supported + .text + adrp x0, :tlsdesc_auth:a + ldr x16, [x0, :tlsdesc_auth_lo12:a] + add x0, x0, :tlsdesc_auth_lo12:a + .tlsdesccall a + blraa x16, x0 diff --git a/lld/test/ELF/linkerscript/diag.test b/lld/test/ELF/linkerscript/diag.test index fbc24659a5311..114f5c2c0820b 100644 --- a/lld/test/ELF/linkerscript/diag.test +++ b/lld/test/ELF/linkerscript/diag.test @@ -12,9 +12,9 @@ SECTIONS { } # RUN: not ld.lld -shared 0.o -T 1.lds 2>&1 | FileCheck %s --check-prefix=CHECK1 --match-full-lines --strict-whitespace -# CHECK1:{{.*}}:2: malformed number: + +# CHECK1:{{.*}}:2: malformed number: { # CHECK1-NEXT:>>> .text + { *(.text) } -# CHECK1-NEXT:>>> ^ +# CHECK1-NEXT:>>> ^ #--- 2.lds diff --git a/lld/test/ELF/linkerscript/operators.test b/lld/test/ELF/linkerscript/operators.test index 27209a2e40f59..f84f23fd4d469 100644 --- a/lld/test/ELF/linkerscript/operators.test +++ b/lld/test/ELF/linkerscript/operators.test @@ -73,6 +73,8 @@ SECTIONS { log2ceil100000000 = LOG2CEIL(0x100000000); log2ceil100000001 = LOG2CEIL(0x100000001); log2ceilmax = LOG2CEIL(0xffffffffffffffff); + unaryadd = +3 + ++5; + unaryadd_and_unaryminus = 15 + +-5 + -+7; } # CHECK: 0000000000000002 A unary @@ -126,6 +128,8 @@ SECTIONS { # CHECK-NEXT: 0000000000000020 A log2ceil100000000 # CHECK-NEXT: 0000000000000021 A log2ceil100000001 # CHECK-NEXT: 0000000000000040 A log2ceilmax +# CHECK-NEXT: 0000000000000008 A unaryadd +# CHECK-NEXT: 0000000000000003 A unaryadd_and_unaryminus ## Mailformed number error. # RUN: echo "SECTIONS { . = 0x12Q41; }" > %t.script diff --git a/lldb/include/lldb/API/SBDebugger.h b/lldb/include/lldb/API/SBDebugger.h index eb371e33c4951..e0819f1684f8b 100644 --- a/lldb/include/lldb/API/SBDebugger.h +++ b/lldb/include/lldb/API/SBDebugger.h @@ -42,12 +42,16 @@ class LLDB_API SBInputReader { class LLDB_API SBDebugger { public: - FLAGS_ANONYMOUS_ENUM(){ - eBroadcastBitProgress = lldb::DebuggerBroadcastBit::eBroadcastBitProgress, - eBroadcastBitWarning = lldb::DebuggerBroadcastBit::eBroadcastBitWarning, - eBroadcastBitError = lldb::DebuggerBroadcastBit::eBroadcastBitError, - eBroadcastBitProgressCategory = - lldb::DebuggerBroadcastBit::eBroadcastBitProgressCategory, + FLAGS_ANONYMOUS_ENUM() { + eBroadcastBitProgress = lldb::DebuggerBroadcastBit::eBroadcastBitProgress, + eBroadcastBitWarning = lldb::DebuggerBroadcastBit::eBroadcastBitWarning, + eBroadcastBitError = lldb::DebuggerBroadcastBit::eBroadcastBitError, + eBroadcastBitProgressCategory = + lldb::DebuggerBroadcastBit::eBroadcastBitProgressCategory, + eBroadcastBitExternalProgress = + lldb::DebuggerBroadcastBit::eBroadcastBitExternalProgress, + eBroadcastBitExternalProgressCategory = + lldb::DebuggerBroadcastBit::eBroadcastBitExternalProgressCategory, }; SBDebugger(); diff --git a/lldb/include/lldb/Host/Editline.h b/lldb/include/lldb/Host/Editline.h index 26deba38f8471..27b863870090c 100644 --- a/lldb/include/lldb/Host/Editline.h +++ b/lldb/include/lldb/Host/Editline.h @@ -152,7 +152,7 @@ using namespace line_editor; class Editline { public: Editline(const char *editor_name, FILE *input_file, FILE *output_file, - FILE *error_file, std::recursive_mutex &output_mutex); + FILE *error_file, bool color, std::recursive_mutex &output_mutex); ~Editline(); @@ -212,19 +212,23 @@ class Editline { } void SetPromptAnsiPrefix(std::string prefix) { - m_prompt_ansi_prefix = std::move(prefix); + if (m_color) + m_prompt_ansi_prefix = std::move(prefix); } void SetPromptAnsiSuffix(std::string suffix) { - m_prompt_ansi_suffix = std::move(suffix); + if (m_color) + m_prompt_ansi_suffix = std::move(suffix); } void SetSuggestionAnsiPrefix(std::string prefix) { - m_suggestion_ansi_prefix = std::move(prefix); + if (m_color) + m_suggestion_ansi_prefix = std::move(prefix); } void SetSuggestionAnsiSuffix(std::string suffix) { - m_suggestion_ansi_suffix = std::move(suffix); + if (m_color) + m_suggestion_ansi_suffix = std::move(suffix); } /// Prompts for and reads a single line of user input. @@ -400,6 +404,7 @@ class Editline { CompleteCallbackType m_completion_callback; SuggestionCallbackType m_suggestion_callback; + bool m_color; std::string m_prompt_ansi_prefix; std::string m_prompt_ansi_suffix; std::string m_suggestion_ansi_prefix; diff --git a/lldb/include/lldb/Utility/AnsiTerminal.h b/lldb/include/lldb/Utility/AnsiTerminal.h index 67795971d2ca8..1939c49c7b859 100644 --- a/lldb/include/lldb/Utility/AnsiTerminal.h +++ b/lldb/include/lldb/Utility/AnsiTerminal.h @@ -171,7 +171,32 @@ inline std::string FormatAnsiTerminalCodes(llvm::StringRef format, } return fmt; } + +inline std::string StripAnsiTerminalCodes(llvm::StringRef str) { + std::string stripped; + while (!str.empty()) { + llvm::StringRef left, right; + + std::tie(left, right) = str.split(ANSI_ESC_START); + stripped += left; + + // ANSI_ESC_START not found. + if (left == str && right.empty()) + break; + + size_t end = right.find_first_not_of("0123456789;"); + if (end < right.size() && (right[end] == 'm' || right[end] == 'G')) { + str = right.substr(end + 1); + } else { + // ANSI_ESC_END not found. + stripped += ANSI_ESC_START; + str = right; + } + } + return stripped; } + +} // namespace ansi } // namespace lldb_private #endif diff --git a/lldb/source/Core/IOHandler.cpp b/lldb/source/Core/IOHandler.cpp index 695c2481e353d..ca06b52b874db 100644 --- a/lldb/source/Core/IOHandler.cpp +++ b/lldb/source/Core/IOHandler.cpp @@ -264,7 +264,7 @@ IOHandlerEditline::IOHandlerEditline( if (use_editline) { m_editline_up = std::make_unique(editline_name, GetInputFILE(), GetOutputFILE(), GetErrorFILE(), - GetOutputMutex()); + m_color, GetOutputMutex()); m_editline_up->SetIsInputCompleteCallback( [this](Editline *editline, StringList &lines) { return this->IsInputCompleteCallback(editline, lines); @@ -278,12 +278,10 @@ IOHandlerEditline::IOHandlerEditline( m_editline_up->SetSuggestionCallback([this](llvm::StringRef line) { return this->SuggestionCallback(line); }); - if (m_color) { - m_editline_up->SetSuggestionAnsiPrefix(ansi::FormatAnsiTerminalCodes( - debugger.GetAutosuggestionAnsiPrefix())); - m_editline_up->SetSuggestionAnsiSuffix(ansi::FormatAnsiTerminalCodes( - debugger.GetAutosuggestionAnsiSuffix())); - } + m_editline_up->SetSuggestionAnsiPrefix(ansi::FormatAnsiTerminalCodes( + debugger.GetAutosuggestionAnsiPrefix())); + m_editline_up->SetSuggestionAnsiSuffix(ansi::FormatAnsiTerminalCodes( + debugger.GetAutosuggestionAnsiSuffix())); } // See if the delegate supports fixing indentation const char *indent_chars = delegate.IOHandlerGetFixIndentationCharacters(); @@ -478,12 +476,10 @@ bool IOHandlerEditline::SetPrompt(llvm::StringRef prompt) { #if LLDB_ENABLE_LIBEDIT if (m_editline_up) { m_editline_up->SetPrompt(m_prompt.empty() ? nullptr : m_prompt.c_str()); - if (m_color) { - m_editline_up->SetPromptAnsiPrefix( - ansi::FormatAnsiTerminalCodes(m_debugger.GetPromptAnsiPrefix())); - m_editline_up->SetPromptAnsiSuffix( - ansi::FormatAnsiTerminalCodes(m_debugger.GetPromptAnsiSuffix())); - } + m_editline_up->SetPromptAnsiPrefix( + ansi::FormatAnsiTerminalCodes(m_debugger.GetPromptAnsiPrefix())); + m_editline_up->SetPromptAnsiSuffix( + ansi::FormatAnsiTerminalCodes(m_debugger.GetPromptAnsiSuffix())); } #endif return true; diff --git a/lldb/source/Host/common/Editline.cpp b/lldb/source/Host/common/Editline.cpp index 6e35b15d69651..73da1d8481618 100644 --- a/lldb/source/Host/common/Editline.cpp +++ b/lldb/source/Host/common/Editline.cpp @@ -14,6 +14,7 @@ #include "lldb/Host/Editline.h" #include "lldb/Host/FileSystem.h" #include "lldb/Host/Host.h" +#include "lldb/Utility/AnsiTerminal.h" #include "lldb/Utility/CompletionRequest.h" #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/LLDBAssert.h" @@ -85,7 +86,8 @@ bool IsOnlySpaces(const EditLineStringType &content) { } static size_t ColumnWidth(llvm::StringRef str) { - return llvm::sys::locale::columnWidth(str); + std::string stripped = ansi::StripAnsiTerminalCodes(str); + return llvm::sys::locale::columnWidth(stripped); } static int GetOperation(HistoryOperation op) { @@ -610,7 +612,7 @@ int Editline::GetCharacter(EditLineGetCharType *c) { } const char *Editline::Prompt() { - if (!m_prompt_ansi_prefix.empty() || !m_prompt_ansi_suffix.empty()) + if (m_color) m_needs_prompt_repaint = true; return m_current_prompt.c_str(); } @@ -1471,11 +1473,11 @@ Editline *Editline::InstanceFor(EditLine *editline) { } Editline::Editline(const char *editline_name, FILE *input_file, - FILE *output_file, FILE *error_file, + FILE *output_file, FILE *error_file, bool color, std::recursive_mutex &output_mutex) : m_editor_status(EditorStatus::Complete), m_input_file(input_file), m_output_file(output_file), m_error_file(error_file), - m_input_connection(fileno(input_file), false), + m_input_connection(fileno(input_file), false), m_color(color), m_output_mutex(output_mutex) { // Get a shared history instance m_editor_name = (editline_name == nullptr) ? "lldb-tmp" : editline_name; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp index fb3af44abfa8d..81a1375c03718 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -3084,51 +3084,10 @@ size_t DWARFASTParserClang::ParseChildParameters( const dw_tag_t tag = die.Tag(); switch (tag) { case DW_TAG_formal_parameter: { - DWARFAttributes attributes = die.GetAttributes(); - if (attributes.Size() == 0) { - arg_idx++; - break; - } - - const char *name = nullptr; - DWARFFormValue param_type_die_form; - bool is_artificial = false; - // one of None, Auto, Register, Extern, Static, PrivateExtern - - clang::StorageClass storage = clang::SC_None; - uint32_t i; - for (i = 0; i < attributes.Size(); ++i) { - const dw_attr_t attr = attributes.AttributeAtIndex(i); - DWARFFormValue form_value; - if (attributes.ExtractFormValueAtIndex(i, form_value)) { - switch (attr) { - case DW_AT_name: - name = form_value.AsCString(); - break; - case DW_AT_type: - param_type_die_form = form_value; - break; - case DW_AT_artificial: - is_artificial = form_value.Boolean(); - break; - case DW_AT_location: - case DW_AT_const_value: - case DW_AT_default_value: - case DW_AT_description: - case DW_AT_endianity: - case DW_AT_is_optional: - case DW_AT_segment: - case DW_AT_variable_parameter: - default: - case DW_AT_abstract_origin: - case DW_AT_sibling: - break; - } - } - } + const char *name = die.GetName(); + DWARFDIE param_type_die = die.GetAttributeValueAsReferenceDIE(DW_AT_type); - bool skip = false; - if (is_artificial) { + if (die.GetAttributeValueAsUnsigned(DW_AT_artificial, 0)) { // In order to determine if a C++ member function is "const" we // have to look at the const-ness of "this"... if (arg_idx == 0 && @@ -3137,8 +3096,7 @@ size_t DWARFASTParserClang::ParseChildParameters( // specification DIEs, so we can't rely upon the name being in // the formal parameter DIE... (name == nullptr || ::strcmp(name, "this") == 0)) { - Type *this_type = die.ResolveTypeUID(param_type_die_form.Reference()); - if (this_type) { + if (Type *this_type = die.ResolveTypeUID(param_type_die)) { uint32_t encoding_mask = this_type->GetEncodingMask(); if (encoding_mask & Type::eEncodingIsPointerUID) { is_static = false; @@ -3150,23 +3108,18 @@ size_t DWARFASTParserClang::ParseChildParameters( } } } - skip = true; - } - - if (!skip) { - Type *type = die.ResolveTypeUID(param_type_die_form.Reference()); - if (type) { - function_param_types.push_back(type->GetForwardCompilerType()); + } else if (Type *type = die.ResolveTypeUID(param_type_die)) { + function_param_types.push_back(type->GetForwardCompilerType()); - clang::ParmVarDecl *param_var_decl = m_ast.CreateParameterDeclaration( - containing_decl_ctx, GetOwningClangModule(die), name, - type->GetForwardCompilerType(), storage); - assert(param_var_decl); - function_param_decls.push_back(param_var_decl); + clang::ParmVarDecl *param_var_decl = m_ast.CreateParameterDeclaration( + containing_decl_ctx, GetOwningClangModule(die), name, + type->GetForwardCompilerType(), clang::StorageClass::SC_None); + assert(param_var_decl); + function_param_decls.push_back(param_var_decl); - m_ast.SetMetadataAsUserID(param_var_decl, die.GetID()); - } + m_ast.SetMetadataAsUserID(param_var_decl, die.GetID()); } + arg_idx++; } break; diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp index c47e728fdf716..89731f798deda 100644 --- a/lldb/source/Target/Process.cpp +++ b/lldb/source/Target/Process.cpp @@ -1292,17 +1292,12 @@ bool Process::HasAssignedIndexIDToThread(uint64_t thread_id) { } uint32_t Process::AssignIndexIDToThread(uint64_t thread_id) { - uint32_t result = 0; - std::map::iterator iterator = - m_thread_id_to_index_id_map.find(thread_id); - if (iterator == m_thread_id_to_index_id_map.end()) { - result = ++m_thread_index_id; - m_thread_id_to_index_id_map[thread_id] = result; - } else { - result = iterator->second; - } + auto [iterator, inserted] = + m_thread_id_to_index_id_map.try_emplace(thread_id, m_thread_index_id + 1); + if (inserted) + ++m_thread_index_id; - return result; + return iterator->second; } StateType Process::GetState() { diff --git a/lldb/test/API/terminal/TestEditline.py b/lldb/test/API/terminal/TestEditline.py index aa7d827e59944..ddaa441d5f7c1 100644 --- a/lldb/test/API/terminal/TestEditline.py +++ b/lldb/test/API/terminal/TestEditline.py @@ -2,7 +2,6 @@ Test that the lldb editline handling is configured correctly. """ - import lldb from lldbsuite.test.decorators import * from lldbsuite.test.lldbtest import * @@ -69,6 +68,22 @@ def test_prompt_color(self): # Column: 1....6.8 self.child.expect(re.escape("\x1b[31m(lldb) \x1b[0m\x1b[8G")) + @skipIfAsan + @skipIfEditlineSupportMissing + def test_prompt_format_color(self): + """Test that we can change the prompt color with a format string.""" + self.launch(use_colors=True) + # Clear the prefix and suffix setting to simplify the output. + self.expect('settings set prompt-ansi-prefix ""') + self.expect('settings set prompt-ansi-suffix ""') + self.expect('settings set prompt "${ansi.fg.red}(lldb) ${ansi.normal}"') + self.child.send("foo") + # Make sure this change is reflected immediately. Check that the color + # is set (31) and the cursor position (8) is correct. + # Prompt: (lldb) _ + # Column: 1....6.8 + self.child.expect(re.escape("\x1b[31m(lldb) \x1b[0m\x1b[8Gfoo")) + @skipIfAsan @skipIfEditlineSupportMissing def test_prompt_no_color(self): diff --git a/lldb/tools/lldb-dap/lldb-dap.cpp b/lldb/tools/lldb-dap/lldb-dap.cpp index 7e8f7b5f6df67..6b12569d90a83 100644 --- a/lldb/tools/lldb-dap/lldb-dap.cpp +++ b/lldb/tools/lldb-dap/lldb-dap.cpp @@ -414,7 +414,8 @@ void SendStdOutStdErr(DAP &dap, lldb::SBProcess &process) { void ProgressEventThreadFunction(DAP &dap) { lldb::SBListener listener("lldb-dap.progress.listener"); dap.debugger.GetBroadcaster().AddListener( - listener, lldb::SBDebugger::eBroadcastBitProgress); + listener, lldb::SBDebugger::eBroadcastBitProgress | + lldb::SBDebugger::eBroadcastBitExternalProgress); dap.broadcaster.AddListener(listener, eBroadcastBitStopProgressThread); lldb::SBEvent event; bool done = false; diff --git a/lldb/unittests/Editline/EditlineTest.cpp b/lldb/unittests/Editline/EditlineTest.cpp index 333ad77a0a16f..1327b587e7c3d 100644 --- a/lldb/unittests/Editline/EditlineTest.cpp +++ b/lldb/unittests/Editline/EditlineTest.cpp @@ -118,7 +118,7 @@ EditlineAdapter::EditlineAdapter() // Create an Editline instance. _editline_sp.reset(new lldb_private::Editline( "gtest editor", *_el_secondary_file, *_el_secondary_file, - *_el_secondary_file, output_mutex)); + *_el_secondary_file, /*color=*/false, output_mutex)); _editline_sp->SetPrompt("> "); // Hookup our input complete callback. diff --git a/lldb/unittests/Utility/AnsiTerminalTest.cpp b/lldb/unittests/Utility/AnsiTerminalTest.cpp index a6dbfd6106142..1ba9565c3f6af 100644 --- a/lldb/unittests/Utility/AnsiTerminalTest.cpp +++ b/lldb/unittests/Utility/AnsiTerminalTest.cpp @@ -16,16 +16,21 @@ TEST(AnsiTerminal, Empty) { EXPECT_EQ("", ansi::FormatAnsiTerminalCodes("")); } TEST(AnsiTerminal, WhiteSpace) { EXPECT_EQ(" ", ansi::FormatAnsiTerminalCodes(" ")); + EXPECT_EQ(" ", ansi::StripAnsiTerminalCodes(" ")); } TEST(AnsiTerminal, AtEnd) { EXPECT_EQ("abc\x1B[30m", ansi::FormatAnsiTerminalCodes("abc${ansi.fg.black}")); + + EXPECT_EQ("abc", ansi::StripAnsiTerminalCodes("abc\x1B[30m")); } TEST(AnsiTerminal, AtStart) { EXPECT_EQ("\x1B[30mabc", ansi::FormatAnsiTerminalCodes("${ansi.fg.black}abc")); + + EXPECT_EQ("abc", ansi::StripAnsiTerminalCodes("\x1B[30mabc")); } TEST(AnsiTerminal, KnownPrefix) { @@ -45,10 +50,20 @@ TEST(AnsiTerminal, Incomplete) { TEST(AnsiTerminal, Twice) { EXPECT_EQ("\x1B[30m\x1B[31mabc", ansi::FormatAnsiTerminalCodes("${ansi.fg.black}${ansi.fg.red}abc")); + + EXPECT_EQ("abc", ansi::StripAnsiTerminalCodes("\x1B[30m\x1B[31mabc")); } TEST(AnsiTerminal, Basic) { EXPECT_EQ( "abc\x1B[31mabc\x1B[0mabc", ansi::FormatAnsiTerminalCodes("abc${ansi.fg.red}abc${ansi.normal}abc")); + + EXPECT_EQ("abcabcabc", + ansi::StripAnsiTerminalCodes("abc\x1B[31mabc\x1B[0mabc")); +} + +TEST(AnsiTerminal, InvalidEscapeCode) { + EXPECT_EQ("abc\x1B[31kabcabc", + ansi::StripAnsiTerminalCodes("abc\x1B[31kabc\x1B[0mabc")); } diff --git a/llvm/CMakeLists.txt b/llvm/CMakeLists.txt index f14065ab03799..ad12100fdb5b8 100644 --- a/llvm/CMakeLists.txt +++ b/llvm/CMakeLists.txt @@ -486,6 +486,7 @@ set(LLVM_ALL_TARGETS PowerPC RISCV Sparc + SPIRV SystemZ VE WebAssembly @@ -498,7 +499,6 @@ set(LLVM_ALL_EXPERIMENTAL_TARGETS CSKY DirectX M68k - SPIRV Xtensa ) diff --git a/llvm/Maintainers.md b/llvm/Maintainers.md index 56457946136f0..534d81e68d024 100644 --- a/llvm/Maintainers.md +++ b/llvm/Maintainers.md @@ -284,8 +284,11 @@ koachan@protonmail.com (email), [koachan](https://github.com/koachan) (GitHub) #### SPIRV backend -Ilia Diachkov \ -ilia.diachkov@gmail.com (email), [iliya-diyachkov](https://github.com/iliya-diyachkov) (GitHub) +Vyacheslav Levytskyy \ +vyacheslav.levytskyy@intel.com, vyacheslav.levytskyy@gmail.com (email), [VyacheslavLevytskyy](https://github.com/VyacheslavLevytskyy) (GitHub) + +Nathan Gauër \ +brioche@google.com (email), [Keenuts](https://github.com/Keenuts) (GitHub) #### SystemZ backend diff --git a/llvm/docs/DeveloperPolicy.rst b/llvm/docs/DeveloperPolicy.rst index 18b05d2e58e6e..5b1f7dc29bee3 100644 --- a/llvm/docs/DeveloperPolicy.rst +++ b/llvm/docs/DeveloperPolicy.rst @@ -1154,6 +1154,18 @@ acceptable for their contributions. We feel that a high burden for relicensing is good for the project, because contributors do not have to fear that their code will be used in a way with which they disagree. +Embedded Copyright or 'Contributed by' Statements +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The LLVM project does not accept contributions that include in-source copyright +notices except where such notices are part of a larger external project being +added as a vendored dependency. + +LLVM source code lives for a long time and is edited by many people, the best +way to track contributions is through revision control history. +See the `Attribution of Changes`_ section for more information about attributing +changes to authors other than the committer. + Relicensing ----------- diff --git a/llvm/docs/Docker.rst b/llvm/docs/Docker.rst index 6b3c80da684b4..5d976eddb3130 100644 --- a/llvm/docs/Docker.rst +++ b/llvm/docs/Docker.rst @@ -9,7 +9,7 @@ You can find a number of sources to build docker images with LLVM components in images for their own use, or as a starting point for someone who wants to write their own Dockerfiles. -We currently provide Dockerfiles with ``debian10`` and ``nvidia-cuda`` base images. +We currently provide Dockerfiles with ``debian12`` and ``nvidia-cuda`` base images. We also provide an ``example`` image, which contains placeholders that one would need to fill out in order to produce Dockerfiles for a new docker image. @@ -72,13 +72,13 @@ checkout from git and provide a list of CMake arguments to use during when building LLVM inside docker container. Here's a very simple example of getting a docker image with clang binary, -compiled by the system compiler in the debian10 image: +compiled by the system compiler in the debian12 image: .. code-block:: bash ./llvm/utils/docker/build_docker_image.sh \ - --source debian10 \ - --docker-repository clang-debian10 --docker-tag "staging" \ + --source debian12 \ + --docker-repository clang-debian12 --docker-tag "staging" \ -p clang -i install-clang -i install-clang-resource-headers \ -- \ -DCMAKE_BUILD_TYPE=Release @@ -93,51 +93,45 @@ this command will do that: # LLVM_TARGETS_TO_BUILD=Native is to reduce stage1 compile time. # Options, starting with BOOTSTRAP_* are passed to stage2 cmake invocation. ./build_docker_image.sh \ - --source debian10 \ - --docker-repository clang-debian10 --docker-tag "staging" \ + --source debian12 \ + --docker-repository clang-debian12 --docker-tag "staging" \ -p clang -i stage2-install-clang -i stage2-install-clang-resource-headers \ -- \ -DLLVM_TARGETS_TO_BUILD=Native -DCMAKE_BUILD_TYPE=Release \ -DBOOTSTRAP_CMAKE_BUILD_TYPE=Release \ -DCLANG_ENABLE_BOOTSTRAP=ON -DCLANG_BOOTSTRAP_TARGETS="install-clang;install-clang-resource-headers" -This will produce a new image ``clang-debian10:staging`` from the latest +This will produce a new image ``clang-debian12:staging`` from the latest upstream revision. After the image is built you can run bash inside a container based on your image like this: .. code-block:: bash - docker run -ti clang-debian10:staging bash + docker run -ti clang-debian12:staging bash Now you can run bash commands as you normally would: .. code-block:: bash root@80f351b51825:/# clang -v - clang version 5.0.0 (trunk 305064) + clang version 19.1.7 (trunk 524462) + Target: x86_64-unknown-linux-gnu Target: x86_64-unknown-linux-gnu Thread model: posix InstalledDir: /bin - Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/4.8 - Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/4.8.4 - Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/4.9 - Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/4.9.2 - Selected GCC installation: /usr/lib/gcc/x86_64-linux-gnu/4.9 - Candidate multilib: .;@m64 - Selected multilib: .;@m64 Which image should I choose? ============================ -We currently provide two images: Debian10-based and nvidia-cuda-based. They +We currently provide two images: Debian12-based and nvidia-cuda-based. They differ in the base image that they use, i.e. they have a different set of preinstalled binaries. Debian8 is very minimal, nvidia-cuda is larger, but has preinstalled CUDA libraries and allows to access a GPU, installed on your machine. If you need a minimal linux distribution with only clang and libstdc++ included, -you should try Debian10-based image. +you should try Debian12-based image. If you want to use CUDA libraries and have access to a GPU on your machine, you should choose nvidia-cuda-based image and use `nvidia-docker @@ -150,7 +144,7 @@ If you have a different use-case, you could create your own image based on ``example/`` folder. Any docker image can be built and run using only the docker binary, i.e. you can -run debian10 build on Fedora or any other Linux distribution. You don't need to +run debian12 build on Fedora or any other Linux distribution. You don't need to install CMake, compilers or any other clang dependencies. It is all handled during the build process inside Docker's isolated environment. @@ -158,12 +152,12 @@ Stable build ============ If you want a somewhat recent and somewhat stable build, use the ``branches/google/stable`` branch, i.e. the following command will produce a -Debian10-based image using the latest ``google/stable`` sources for you: +Debian12-based image using the latest ``google/stable`` sources for you: .. code-block:: bash ./llvm/utils/docker/build_docker_image.sh \ - -s debian10 --d clang-debian10 -t "staging" \ + -s debian12 --d clang-debian12 -t "staging" \ --branch branches/google/stable \ -p clang -i install-clang -i install-clang-resource-headers \ -- \ diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst index 8cc9036d1b67f..b922636d6c914 100644 --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -4776,8 +4776,8 @@ allowing the '``or``' to be folded to -1. %B = undef %C = undef -This set of examples shows that undefined '``select``' (and conditional -branch) conditions can go *either way*, but they have to come from one +This set of examples shows that undefined '``select``' +conditions can go *either way*, but they have to come from one of the two operands. In the ``%A`` example, if ``%X`` and ``%Y`` were both known to have a clear low bit, then ``%A`` would have to have a cleared low bit. However, in the ``%C`` example, the optimizer is diff --git a/llvm/docs/ReleaseNotes.md b/llvm/docs/ReleaseNotes.md index 8f88b824f965a..50cdaafcb3bb7 100644 --- a/llvm/docs/ReleaseNotes.md +++ b/llvm/docs/ReleaseNotes.md @@ -47,6 +47,12 @@ for adding a new subsection. --> same semantics. The normalizer makes it easier to spot semantic differences when diffing two modules which have undergone different passes. +* The SPIR-V backend is now an official LLVM target, providing OpenCL and SYCL + conformance and establishing a foundation for broader applicability to other + APIs, including Vulkan, GLSL, and HLSL. This backend aims to offer a unified + approach for diverse compute and graphics workloads, providing a robust + alternative to the Khronos SPIR-V LLVM Translator. + * ...